Commit realizado el 12:13:52 08-04-2024
This commit is contained in:
396
wp-content/plugins/web-stories/includes/Integrations/Jetpack.php
Normal file
396
wp-content/plugins/web-stories/includes/Integrations/Jetpack.php
Normal file
@@ -0,0 +1,396 @@
|
||||
<?php
|
||||
/**
|
||||
* Class Jetpack
|
||||
*
|
||||
* @link https://github.com/googleforcreators/web-stories-wp
|
||||
*
|
||||
* @copyright 2020 Google LLC
|
||||
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace Google\Web_Stories\Integrations;
|
||||
|
||||
use Google\Web_Stories\Context;
|
||||
use Google\Web_Stories\Media\Media_Source_Taxonomy;
|
||||
use Google\Web_Stories\Service_Base;
|
||||
use Google\Web_Stories\Story_Post_Type;
|
||||
use WP_Post;
|
||||
use WP_REST_Response;
|
||||
|
||||
/**
|
||||
* Class Jetpack.
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
|
||||
*
|
||||
* @phpstan-type AttachmentData array{
|
||||
* media_details?: array{
|
||||
* length?: int,
|
||||
* length_formatted?: string
|
||||
* },
|
||||
* url?: string,
|
||||
* featured_media_src?: string
|
||||
* }
|
||||
*
|
||||
* @phpstan-type EnhancedAttachmentMetadata array{
|
||||
* width: int,
|
||||
* height: int,
|
||||
* file: string,
|
||||
* sizes: mixed,
|
||||
* image_meta: mixed,
|
||||
* videopress?: array{
|
||||
* duration: int,
|
||||
* poster: string,
|
||||
* width: int,
|
||||
* height: int,
|
||||
* file_url_base?: array{
|
||||
* https: string
|
||||
* },
|
||||
* files?: array{
|
||||
* hd?: array{
|
||||
* mp4?: string
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
class Jetpack extends Service_Base {
|
||||
|
||||
/**
|
||||
* VideoPress Mime type.
|
||||
*
|
||||
* @since 1.7.2
|
||||
*/
|
||||
public const VIDEOPRESS_MIME_TYPE = 'video/videopress';
|
||||
|
||||
/**
|
||||
* VideoPress poster meta key.
|
||||
*
|
||||
* @since 1.7.2
|
||||
*/
|
||||
public const VIDEOPRESS_POSTER_META_KEY = 'videopress_poster_image';
|
||||
|
||||
/**
|
||||
* Media_Source_Taxonomy instance.
|
||||
*
|
||||
* @var Media_Source_Taxonomy Experiments instance.
|
||||
*/
|
||||
protected Media_Source_Taxonomy $media_source_taxonomy;
|
||||
|
||||
/**
|
||||
* Context instance.
|
||||
*
|
||||
* @var Context Context instance.
|
||||
*/
|
||||
private Context $context;
|
||||
|
||||
/**
|
||||
* Jetpack constructor.
|
||||
*
|
||||
* @since 1.12.0
|
||||
*
|
||||
* @param Media_Source_Taxonomy $media_source_taxonomy Media_Source_Taxonomy instance.
|
||||
* @param Context $context Context instance.
|
||||
*/
|
||||
public function __construct( Media_Source_Taxonomy $media_source_taxonomy, Context $context ) {
|
||||
$this->media_source_taxonomy = $media_source_taxonomy;
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes all hooks.
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public function register(): void {
|
||||
// See https://github.com/Automattic/jetpack/blob/4b85be883b3c584c64eeb2fb0f3fcc15dabe2d30/modules/custom-post-types/portfolios.php#L80.
|
||||
if ( \defined( 'IS_WPCOM' ) && IS_WPCOM ) {
|
||||
add_filter( 'wpcom_sitemap_post_types', [ $this, 'add_to_jetpack_sitemap' ] );
|
||||
} else {
|
||||
add_filter( 'jetpack_sitemap_post_types', [ $this, 'add_to_jetpack_sitemap' ] );
|
||||
}
|
||||
|
||||
add_filter( 'jetpack_is_amp_request', [ $this, 'force_amp_request' ] );
|
||||
add_filter( 'web_stories_allowed_mime_types', [ $this, 'add_videopress' ] );
|
||||
add_filter( 'web_stories_rest_prepare_attachment', [ $this, 'filter_rest_api_response' ], 10, 2 );
|
||||
add_filter( 'ajax_query_attachments_args', [ $this, 'filter_ajax_query_attachments_args' ] );
|
||||
add_action( 'added_post_meta', [ $this, 'add_term' ], 10, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the web-story post type to Jetpack / WordPress.com sitemaps.
|
||||
*
|
||||
* @since 1.2.0
|
||||
*
|
||||
* @see https://github.com/Automattic/jetpack/blob/4b85be883b3c584c64eeb2fb0f3fcc15dabe2d30/modules/custom-post-types/portfolios.php#L80
|
||||
*
|
||||
* @param array|mixed $post_types Array of post types.
|
||||
* @return array|mixed Modified list of post types.
|
||||
*
|
||||
* @template T
|
||||
*
|
||||
* @phpstan-return ($post_types is array<T> ? array<T> : mixed)
|
||||
*/
|
||||
public function add_to_jetpack_sitemap( $post_types ) {
|
||||
if ( ! \is_array( $post_types ) ) {
|
||||
return $post_types;
|
||||
}
|
||||
$post_types[] = Story_Post_Type::POST_TYPE_SLUG;
|
||||
|
||||
return $post_types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add VideoPress to allowed mime types.
|
||||
*
|
||||
* If the site does not support VideoPress, this will be filtered out.
|
||||
*
|
||||
* @since 1.7.2
|
||||
*
|
||||
* @param array{video?: string[]}|mixed $mime_types Associative array of allowed mime types per media type (image, audio, video).
|
||||
* @return array{video?: string[]}|mixed
|
||||
*
|
||||
* @template T
|
||||
*
|
||||
* @phpstan-return ($mime_types is array<T> ? array<T> : mixed)
|
||||
*/
|
||||
public function add_videopress( $mime_types ) {
|
||||
if ( ! \is_array( $mime_types ) ) {
|
||||
return $mime_types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mime types config.
|
||||
*
|
||||
* @var array{video?: string[]} $mime_types
|
||||
*/
|
||||
$mime_types['video'][] = self::VIDEOPRESS_MIME_TYPE;
|
||||
|
||||
return $mime_types;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Filter ajax query attachments args when accessed from the Web Stories editor.
|
||||
*
|
||||
* Only filters the response if the mime type matches exactly what Web Stories is looking for.
|
||||
*
|
||||
* @since 1.7.2
|
||||
*
|
||||
* @param array|mixed $args Query args.
|
||||
* @return array|mixed Filtered query args.
|
||||
*
|
||||
* @template T
|
||||
*
|
||||
* @phpstan-return ($args is array<T> ? array<T> : mixed)
|
||||
*/
|
||||
public function filter_ajax_query_attachments_args( $args ) {
|
||||
if ( ! \is_array( $args ) || ! isset( $args['post_mime_type'] ) || ! \is_array( $args['post_mime_type'] ) ) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
if ( \in_array( self::VIDEOPRESS_MIME_TYPE, $args['post_mime_type'], true ) ) {
|
||||
add_filter( 'wp_prepare_attachment_for_js', [ $this, 'filter_admin_ajax_response' ], 15, 2 );
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter admin ajax responses for VideoPress videos.
|
||||
*
|
||||
* Changes the video/videopress type back to mp4
|
||||
* and ensures MP4 source URLs are returned.
|
||||
*
|
||||
* @since 1.7.2
|
||||
*
|
||||
* @param array|mixed $data Array of prepared attachment data. @see wp_prepare_attachment_for_js().
|
||||
* @param WP_Post $attachment Attachment object.
|
||||
* @return array|mixed
|
||||
*
|
||||
* @phpstan-param AttachmentData $data
|
||||
* @phpstan-return AttachmentData|mixed
|
||||
*
|
||||
* @template T
|
||||
*
|
||||
* @phpstan-return ($data is array<T> ? array<T> : mixed)
|
||||
*/
|
||||
public function filter_admin_ajax_response( $data, WP_Post $attachment ) {
|
||||
if ( self::VIDEOPRESS_MIME_TYPE !== $attachment->post_mime_type ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
if ( ! \is_array( $data ) ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
// Reset mime type back to mp4, as this is the correct value.
|
||||
$data['mime'] = 'video/mp4';
|
||||
$data['subtype'] = 'mp4';
|
||||
|
||||
// Mark video as optimized.
|
||||
$data[ $this->media_source_taxonomy::MEDIA_SOURCE_KEY ] = 'video-optimization';
|
||||
|
||||
/**
|
||||
* Jetpack adds an additional field to regular attachment metadata.
|
||||
*
|
||||
* @var array $metadata
|
||||
* @phpstan-var EnhancedAttachmentMetadata|false $metadata
|
||||
*/
|
||||
$metadata = wp_get_attachment_metadata( $attachment->ID );
|
||||
|
||||
if ( $metadata && isset( $metadata['videopress']['duration'], $data['media_details'] ) && \is_array( $data['media_details'] ) ) {
|
||||
$data['media_details']['length_formatted'] = $this->format_milliseconds( $metadata['videopress']['duration'] );
|
||||
$data['media_details']['length'] = (int) floor( $metadata['videopress']['duration'] / 1000 );
|
||||
}
|
||||
|
||||
if ( $metadata && isset( $data['url'], $metadata['videopress']['file_url_base']['https'], $metadata['videopress']['files']['hd']['mp4'] ) ) {
|
||||
$data['url'] = $metadata['videopress']['file_url_base']['https'] . $metadata['videopress']['files']['hd']['mp4'];
|
||||
}
|
||||
|
||||
// Get the correct poster with matching dimensions from VideoPress.
|
||||
if ( $metadata && isset( $data['featured_media_src'], $metadata['videopress']['poster'], $metadata['videopress']['width'], $metadata['videopress']['height'] ) ) {
|
||||
$data['featured_media_src'] = [
|
||||
'src' => $metadata['videopress']['poster'],
|
||||
'width' => $metadata['videopress']['width'],
|
||||
'height' => $metadata['videopress']['height'],
|
||||
'generated' => true,
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter REST API responses for VideoPress videos.
|
||||
*
|
||||
* Changes the video/videopress type back to mp4
|
||||
* and ensures MP4 source URLs are returned.
|
||||
*
|
||||
* @since 1.7.2
|
||||
*
|
||||
* @param WP_REST_Response $response The response object.
|
||||
* @param WP_Post $post The original attachment post.
|
||||
*/
|
||||
public function filter_rest_api_response( WP_REST_Response $response, WP_Post $post ): WP_REST_Response {
|
||||
if ( self::VIDEOPRESS_MIME_TYPE !== $post->post_mime_type ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Response data.
|
||||
*
|
||||
* @var array<string, string|array<string, int|string>|bool> $data
|
||||
*/
|
||||
$data = $response->get_data();
|
||||
|
||||
// Reset mime type back to mp4, as this is the correct value.
|
||||
$data['mime_type'] = 'video/mp4';
|
||||
|
||||
// Mark video as optimized.
|
||||
$data[ $this->media_source_taxonomy::MEDIA_SOURCE_KEY ] = 'video-optimization';
|
||||
|
||||
/**
|
||||
* Jetpack adds an additional field to regular attachment metadata.
|
||||
*
|
||||
* @var EnhancedAttachmentMetadata|false $metadata
|
||||
*/
|
||||
$metadata = wp_get_attachment_metadata( $post->ID );
|
||||
|
||||
if ( $metadata && isset( $metadata['videopress']['duration'], $data['media_details'] ) && \is_array( $data['media_details'] ) ) {
|
||||
$data['media_details']['length_formatted'] = $this->format_milliseconds( $metadata['videopress']['duration'] );
|
||||
$data['media_details']['length'] = (int) floor( $metadata['videopress']['duration'] / 1000 );
|
||||
}
|
||||
|
||||
if ( $metadata && isset( $data['source_url'], $metadata['videopress']['file_url_base']['https'], $metadata['videopress']['files']['hd']['mp4'] ) ) {
|
||||
$data['source_url'] = $metadata['videopress']['file_url_base']['https'] . $metadata['videopress']['files']['hd']['mp4'];
|
||||
}
|
||||
|
||||
// Get the correct poster with matching dimensions from VideoPress.
|
||||
if ( $metadata && isset( $data['featured_media_src'], $metadata['videopress']['poster'], $metadata['videopress']['width'], $metadata['videopress']['height'] ) ) {
|
||||
$data['featured_media_src'] = [
|
||||
'src' => $metadata['videopress']['poster'],
|
||||
'width' => $metadata['videopress']['width'],
|
||||
'height' => $metadata['videopress']['height'],
|
||||
'generated' => true,
|
||||
];
|
||||
}
|
||||
|
||||
$response->set_data( $data );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook into added_post_meta.
|
||||
*
|
||||
* @since 1.7.2
|
||||
*
|
||||
* @param int $mid The meta ID after successful update.
|
||||
* @param int $object_id ID of the object metadata is for.
|
||||
* @param string $meta_key Metadata key.
|
||||
*/
|
||||
public function add_term( int $mid, int $object_id, string $meta_key ): void {
|
||||
if ( self::VIDEOPRESS_POSTER_META_KEY !== $meta_key ) {
|
||||
return;
|
||||
}
|
||||
if ( 'attachment' !== get_post_type( $object_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_set_object_terms( (int) $object_id, $this->media_source_taxonomy::TERM_POSTER_GENERATION, $this->media_source_taxonomy->get_taxonomy_slug() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Force Jetpack to see Web Stories as AMP.
|
||||
*
|
||||
* @since 1.2.0
|
||||
*
|
||||
* @param bool $is_amp_request Is the request supposed to return valid AMP content.
|
||||
* @return bool Whether the current request is an AMP request.
|
||||
*/
|
||||
public function force_amp_request( bool $is_amp_request ): bool {
|
||||
if ( ! $this->context->is_web_story() ) {
|
||||
return (bool) $is_amp_request;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format milliseconds into seconds.
|
||||
*
|
||||
* @since 1.7.2
|
||||
*
|
||||
* @param int $milliseconds Milliseconds to converted to minutes and seconds.
|
||||
*/
|
||||
protected function format_milliseconds( int $milliseconds ): string {
|
||||
$seconds = floor( $milliseconds / 1000 );
|
||||
|
||||
if ( $seconds >= 1 ) {
|
||||
$minutes = floor( $seconds / 60 );
|
||||
$seconds %= 60;
|
||||
} else {
|
||||
$seconds = 0;
|
||||
$minutes = 0;
|
||||
}
|
||||
|
||||
return sprintf( '%d:%02u', $minutes, $seconds );
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user