Commit realizado el 12:13:52 08-04-2024
This commit is contained in:
120
wp-content/plugins/web-stories/includes/Renderer/Archives.php
Normal file
120
wp-content/plugins/web-stories/includes/Renderer/Archives.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
/**
|
||||
* Class Archives
|
||||
*
|
||||
* @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\Renderer;
|
||||
|
||||
use Google\Web_Stories\AMP_Story_Player_Assets;
|
||||
use Google\Web_Stories\Assets;
|
||||
use Google\Web_Stories\Context;
|
||||
use Google\Web_Stories\Model\Story;
|
||||
use Google\Web_Stories\Renderer\Story\Embed;
|
||||
use Google\Web_Stories\Service_Base;
|
||||
use Google\Web_Stories\Story_Post_Type;
|
||||
use WP_Post;
|
||||
|
||||
/**
|
||||
* Class Archives
|
||||
*/
|
||||
class Archives extends Service_Base {
|
||||
|
||||
/**
|
||||
* Assets instance.
|
||||
*
|
||||
* @var Assets Assets instance.
|
||||
*/
|
||||
protected Assets $assets;
|
||||
|
||||
/**
|
||||
* AMP_Story_Player_Assets instance.
|
||||
*
|
||||
* @var AMP_Story_Player_Assets AMP_Story_Player_Assets instance.
|
||||
*/
|
||||
protected AMP_Story_Player_Assets $amp_story_player_assets;
|
||||
|
||||
/**
|
||||
* Context instance.
|
||||
*
|
||||
* @var Context Context instance.
|
||||
*/
|
||||
protected Context $context;
|
||||
|
||||
/**
|
||||
* Archives constructor.
|
||||
*
|
||||
* @since 1.8.0
|
||||
*
|
||||
* @param Assets $assets Assets instance.
|
||||
* @param AMP_Story_Player_Assets $amp_story_player_assets AMP_Story_Player_Assets instance.
|
||||
* @param Context $context Context instance.
|
||||
*/
|
||||
public function __construct( Assets $assets, AMP_Story_Player_Assets $amp_story_player_assets, Context $context ) {
|
||||
$this->assets = $assets;
|
||||
$this->amp_story_player_assets = $amp_story_player_assets;
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter content and excerpt for search and post type archive.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public function register(): void {
|
||||
add_filter( 'the_content', [ $this, 'embed_player' ], PHP_INT_MAX );
|
||||
add_filter( 'the_excerpt', [ $this, 'embed_player' ], PHP_INT_MAX );
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the content to an embedded player
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string|mixed $content Current content of filter.
|
||||
* @return string|mixed
|
||||
*/
|
||||
public function embed_player( $content ) {
|
||||
$post = get_post();
|
||||
|
||||
if ( is_feed() ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
if ( ! is_search() && ! is_post_type_archive( Story_Post_Type::POST_TYPE_SLUG ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
if ( $post instanceof WP_Post && Story_Post_Type::POST_TYPE_SLUG === $post->post_type ) {
|
||||
$story = new Story();
|
||||
$story->load_from_post( $post );
|
||||
|
||||
$embed = new Embed( $story, $this->assets, $this->context );
|
||||
$content = $embed->render();
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
73
wp-content/plugins/web-stories/includes/Renderer/Feed.php
Normal file
73
wp-content/plugins/web-stories/includes/Renderer/Feed.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
* Class Feed
|
||||
*
|
||||
* @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\Renderer;
|
||||
|
||||
use Google\Web_Stories\Model\Story;
|
||||
use Google\Web_Stories\Renderer\Story\Image;
|
||||
use Google\Web_Stories\Service_Base;
|
||||
use Google\Web_Stories\Story_Post_Type;
|
||||
use WP_Post;
|
||||
|
||||
/**
|
||||
* Class Feed
|
||||
*/
|
||||
class Feed extends Service_Base {
|
||||
|
||||
/**
|
||||
* Filter RSS content fields.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public function register(): void {
|
||||
add_filter( 'the_content_feed', [ $this, 'embed_image' ] );
|
||||
add_filter( 'the_excerpt_rss', [ $this, 'embed_image' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter feed content for stories to render as an image.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string|mixed $content Feed content.
|
||||
* @return string|mixed
|
||||
*/
|
||||
public function embed_image( $content ) {
|
||||
$post = get_post();
|
||||
|
||||
if ( $post instanceof WP_Post && Story_Post_Type::POST_TYPE_SLUG === $post->post_type ) {
|
||||
$story = new Story();
|
||||
$story->load_from_post( $post );
|
||||
|
||||
$image = new Image( $story );
|
||||
$content = $image->render();
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
166
wp-content/plugins/web-stories/includes/Renderer/Oembed.php
Normal file
166
wp-content/plugins/web-stories/includes/Renderer/Oembed.php
Normal file
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
/**
|
||||
* Class Oembed
|
||||
*
|
||||
* @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\Renderer;
|
||||
|
||||
use Google\Web_Stories\Service_Base;
|
||||
use Google\Web_Stories\Story_Post_Type;
|
||||
use WP_Post;
|
||||
|
||||
/**
|
||||
* Class Oembed
|
||||
*/
|
||||
class Oembed extends Service_Base {
|
||||
|
||||
/**
|
||||
* Filter to render oembed.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public function register(): void {
|
||||
add_filter( 'embed_template', [ $this, 'filter_embed_template' ] );
|
||||
add_filter( 'embed_html', [ $this, 'filter_embed_html' ], 10, 4 );
|
||||
// So it runs after get_oembed_response_data_rich().
|
||||
add_filter( 'oembed_response_data', [ $this, 'filter_oembed_response_data' ], 20, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the path of the queried template by type.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @param string|mixed $template Path to the template. See locate_template().
|
||||
* @return string|mixed $template
|
||||
*/
|
||||
public function filter_embed_template( $template ) {
|
||||
if ( get_post_type() === Story_Post_Type::POST_TYPE_SLUG ) {
|
||||
$template = WEBSTORIES_PLUGIN_DIR_PATH . 'includes/templates/frontend/embed-web-story.php';
|
||||
}
|
||||
|
||||
return $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the embed code for a specific post.
|
||||
*
|
||||
* For stories, changes the aspect ratio from 16/9 to 3/5.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @param string|mixed $output Embed code.
|
||||
* @param WP_Post $post Post object.
|
||||
* @param int $width The width for the response.
|
||||
* @param int $height The height for the response.
|
||||
* @return string|mixed Filtered embed code.
|
||||
*
|
||||
* @phpstan-return ($output is string ? string : mixed)
|
||||
*/
|
||||
public function filter_embed_html( $output, WP_Post $post, int $width, int $height ) {
|
||||
if ( ! \is_string( $output ) ) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
if ( Story_Post_Type::POST_TYPE_SLUG !== $post->post_type ) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
if ( ! has_post_thumbnail( $post ) ) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
$new_data = $this->get_embed_height_width( $width );
|
||||
|
||||
$new_width = $new_data['width'];
|
||||
$new_height = $new_data['height'];
|
||||
|
||||
return str_replace(
|
||||
[ "width=\"$width\"", "height=\"$height\"" ],
|
||||
[
|
||||
"width=\"$new_width\"",
|
||||
"height=\"$new_height\"",
|
||||
],
|
||||
$output
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the oEmbed response data for a specific post.
|
||||
*
|
||||
* For stories, changes the aspect ratio from 16/9 to 3/5.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @param array|mixed $data The response data.
|
||||
* @param WP_Post $post The post object.
|
||||
* @param int $width The requested width.
|
||||
* @return array|mixed The modified response data.
|
||||
*
|
||||
* @template T
|
||||
*
|
||||
* @phpstan-return ($data is array<T> ? array<T> : mixed)
|
||||
*/
|
||||
public function filter_oembed_response_data( $data, WP_Post $post, int $width ) {
|
||||
if ( Story_Post_Type::POST_TYPE_SLUG !== $post->post_type ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
if ( ! has_post_thumbnail( $post ) ) {
|
||||
return $data;
|
||||
}
|
||||
if ( ! \is_array( $data ) ) {
|
||||
return $data;
|
||||
}
|
||||
$new_data = $this->get_embed_height_width( $width );
|
||||
|
||||
return array_merge( $data, $new_data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate new height and width for embed.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @param int $old_width Old width, used to generate new height and width.
|
||||
* @return array{width: int, height: int}
|
||||
*/
|
||||
protected function get_embed_height_width( int $old_width ): array {
|
||||
/** This filter is documented in wp-includes/embed.php */
|
||||
$min_max_width = apply_filters(
|
||||
'oembed_min_max_width',
|
||||
[
|
||||
'min' => 200,
|
||||
'max' => 360,
|
||||
]
|
||||
);
|
||||
|
||||
$width = (int) min( max( $min_max_width['min'], $old_width ), $min_max_width['max'] );
|
||||
$height = (int) max( ceil( $width / 3 * 5 ), 330 );
|
||||
|
||||
return compact( 'width', 'height' );
|
||||
}
|
||||
}
|
100
wp-content/plugins/web-stories/includes/Renderer/Single.php
Normal file
100
wp-content/plugins/web-stories/includes/Renderer/Single.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
/**
|
||||
* Class Single
|
||||
*
|
||||
* @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\Renderer;
|
||||
|
||||
use Google\Web_Stories\Context;
|
||||
use Google\Web_Stories\Service_Base;
|
||||
|
||||
/**
|
||||
* Class Single
|
||||
*/
|
||||
class Single extends Service_Base {
|
||||
/**
|
||||
* Context instance.
|
||||
*
|
||||
* @var Context Context instance.
|
||||
*/
|
||||
private Context $context;
|
||||
|
||||
/**
|
||||
* Single constructor.
|
||||
*
|
||||
* @param Context $context Context instance.
|
||||
*/
|
||||
public function __construct( Context $context ) {
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the Single logic.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public function register(): void {
|
||||
// This is hooked to both the `template_include` and the `single_template` filters,
|
||||
// as an additional measure to improve compatibility with themes
|
||||
// overriding the template hierarchy in an unusual way, like the Sage theme does.
|
||||
add_filter( 'single_template', [ $this, 'filter_template_include' ], PHP_INT_MAX );
|
||||
add_filter( 'template_include', [ $this, 'filter_template_include' ], PHP_INT_MAX );
|
||||
|
||||
add_filter( 'show_admin_bar', [ $this, 'show_admin_bar' ] ); // phpcs:ignore WordPressVIPMinimum.UserExperience.AdminBarRemoval.RemovalDetected
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the path of the queried template for single stories.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string|mixed $template Absolute path to template file.
|
||||
* @return string|mixed Filtered template file path.
|
||||
*/
|
||||
public function filter_template_include( $template ) {
|
||||
if ( $this->context->is_web_story() ) {
|
||||
return WEBSTORIES_PLUGIN_DIR_PATH . 'includes/templates/frontend/single-web-story.php';
|
||||
}
|
||||
|
||||
return $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter if show admin bar on single post type.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param bool|mixed $show Current value of filter.
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function show_admin_bar( $show ) {
|
||||
if ( $this->context->is_web_story() ) {
|
||||
$show = false;
|
||||
}
|
||||
|
||||
return $show;
|
||||
}
|
||||
}
|
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
/**
|
||||
* Carousel_Renderer class.
|
||||
*
|
||||
* @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\Renderer\Stories;
|
||||
|
||||
/**
|
||||
* Carousel_Renderer class.
|
||||
*
|
||||
* Note: This class is useful to render stories in carousel view type.
|
||||
* Do not instantiate this class directly, pass `view_type` argument
|
||||
* to `Story_Query` which will handle the instantiation of the class.
|
||||
*/
|
||||
class Carousel_Renderer extends Renderer {
|
||||
|
||||
/**
|
||||
* Script handle.
|
||||
*/
|
||||
public const SCRIPT_HANDLE = 'web-stories-carousel';
|
||||
|
||||
/**
|
||||
* Perform initial setup for object.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init(): void {
|
||||
|
||||
parent::init();
|
||||
|
||||
$this->load_assets();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue assets.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function load_assets(): void {
|
||||
parent::load_assets();
|
||||
|
||||
$this->assets->register_script_asset( self::SCRIPT_HANDLE );
|
||||
$this->assets->register_style_asset( self::SCRIPT_HANDLE );
|
||||
|
||||
wp_localize_script(
|
||||
self::SCRIPT_HANDLE,
|
||||
'webStoriesCarouselSettings',
|
||||
$this->get_carousel_settings()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the stories output for given attributes.
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.UnusedLocalVariable)
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param array<string,mixed> $args Array of rendering arguments.
|
||||
* @return string Rendered stories output.
|
||||
*/
|
||||
public function render( array $args = [] ): string {
|
||||
if ( ! $this->valid() ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
parent::render( $args );
|
||||
$container_classes = $this->get_container_classes();
|
||||
$container_styles = $this->get_container_styles();
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="<?php echo esc_attr( $container_classes ); ?>" data-id="<?php echo esc_attr( (string) $this->instance_id ); ?>">
|
||||
<div class="web-stories-list__inner-wrapper <?php echo esc_attr( 'carousel-' . $this->instance_id ); ?>" style="<?php echo esc_attr( $container_styles ); ?>">
|
||||
<?php
|
||||
if ( ! $this->context->is_amp() ) {
|
||||
$this->assets->enqueue_script_asset( self::SCRIPT_HANDLE );
|
||||
$this->assets->enqueue_style_asset( self::SCRIPT_HANDLE );
|
||||
?>
|
||||
<div class="web-stories-list__carousel <?php echo esc_attr( $this->get_view_type() ); ?>" data-id="<?php echo esc_attr( 'carousel-' . $this->instance_id ); ?>">
|
||||
<?php
|
||||
array_map(
|
||||
function () {
|
||||
$this->render_single_story_content();
|
||||
$this->next();
|
||||
},
|
||||
$this->stories
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
<div tabindex="0" aria-label="<?php esc_attr_e( 'Previous', 'web-stories' ); ?>" class="glider-prev"></div>
|
||||
<div tabindex="0" aria-label="<?php esc_attr_e( 'Next', 'web-stories' ); ?>" class="glider-next"></div>
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<amp-carousel
|
||||
width="1"
|
||||
height="1"
|
||||
layout="intrinsic"
|
||||
type="carousel"
|
||||
role="region"
|
||||
aria-label="<?php esc_attr_e( 'Web Stories', 'web-stories' ); ?>"
|
||||
>
|
||||
<?php
|
||||
array_map(
|
||||
function () {
|
||||
$this->render_single_story_content();
|
||||
$this->next();
|
||||
},
|
||||
$this->stories
|
||||
);
|
||||
?>
|
||||
</amp-carousel>
|
||||
<?php
|
||||
}
|
||||
$this->maybe_render_archive_link();
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
$content = (string) ob_get_clean();
|
||||
|
||||
/**
|
||||
* Filters the Carousel renderer stories content.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param string $content Stories content.
|
||||
*/
|
||||
return apply_filters( 'web_stories_carousel_renderer_stories_content', $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Carousel settings.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return array<string,array<string,bool>> Carousel settings.
|
||||
*/
|
||||
protected function get_carousel_settings(): array {
|
||||
return [
|
||||
'config' => [
|
||||
'isRTL' => is_rtl(),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
/**
|
||||
* Class BaseFieldState.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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\Renderer\Stories\FieldState;
|
||||
|
||||
use Google\Web_Stories\Interfaces\Field;
|
||||
use Google\Web_Stories\Interfaces\FieldState;
|
||||
use Google\Web_Stories\Renderer\Stories\Fields\BaseField;
|
||||
use Google\Web_Stories\Story_Post_Type;
|
||||
|
||||
/**
|
||||
* Class BaseFieldState.
|
||||
*/
|
||||
class BaseFieldState implements FieldState {
|
||||
|
||||
/**
|
||||
* Post type has archive.
|
||||
*/
|
||||
protected bool $has_archive = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Story_Post_Type $story_post_type Story_Post_Type instance.
|
||||
*/
|
||||
public function __construct( Story_Post_Type $story_post_type ) {
|
||||
$this->has_archive = (bool) $story_post_type->get_has_archive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Image alignment FieldState.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return Field
|
||||
*/
|
||||
public function image_alignment() {
|
||||
return new BaseField(
|
||||
[
|
||||
'label' => __( 'Image Alignment', 'web-stories' ),
|
||||
'show' => false,
|
||||
'hidden' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Excerpt FieldState.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return Field
|
||||
*/
|
||||
public function excerpt() {
|
||||
return new BaseField(
|
||||
[
|
||||
'label' => __( 'Display Excerpt', 'web-stories' ),
|
||||
'show' => false,
|
||||
'hidden' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Author Field State.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return Field
|
||||
*/
|
||||
public function author() {
|
||||
return new BaseField(
|
||||
[
|
||||
'label' => __( 'Display Author', 'web-stories' ),
|
||||
'show' => true,
|
||||
'hidden' => false,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Date field state.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return Field
|
||||
*/
|
||||
public function date() {
|
||||
return new BaseField(
|
||||
[
|
||||
'label' => __( 'Display Date', 'web-stories' ),
|
||||
'show' => false,
|
||||
'hidden' => false,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Archive link field state.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return Field
|
||||
*/
|
||||
public function archive_link() {
|
||||
return new BaseField(
|
||||
[
|
||||
'label' => __( 'Display Archive Link', 'web-stories' ),
|
||||
'show' => $this->has_archive,
|
||||
'hidden' => ! $this->has_archive,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Title field state.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return Field
|
||||
*/
|
||||
public function title() {
|
||||
return new BaseField(
|
||||
[
|
||||
'label' => __( 'Display Title', 'web-stories' ),
|
||||
'show' => true,
|
||||
'hidden' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sharp corners field state.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return Field
|
||||
*/
|
||||
public function sharp_corners() {
|
||||
return new BaseField(
|
||||
[
|
||||
'label' => __( 'Use Sharp Corners', 'web-stories' ),
|
||||
'show' => false,
|
||||
'hidden' => false,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Circle size field.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return BaseField
|
||||
*/
|
||||
public function circle_size() {
|
||||
return new BaseField(
|
||||
[
|
||||
'label' => __( 'Circle Size', 'web-stories' ),
|
||||
'show' => false,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of columns field.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return BaseField
|
||||
*/
|
||||
public function number_of_columns() {
|
||||
return new BaseField(
|
||||
[
|
||||
'label' => __( 'Number of Columns', 'web-stories' ),
|
||||
'show' => false,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a field object.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param array<string,bool|string> $args Arguments to build field.
|
||||
* @return BaseField
|
||||
*/
|
||||
protected function prepare_field( array $args ): BaseField {
|
||||
return new BaseField( $args );
|
||||
}
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* Carousel view based controls state.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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\Renderer\Stories\FieldState;
|
||||
|
||||
use Google\Web_Stories\Renderer\Stories\Fields\BaseField;
|
||||
|
||||
/**
|
||||
* Class CarouselView.
|
||||
*/
|
||||
final class CarouselView extends BaseFieldState {
|
||||
|
||||
/**
|
||||
* Author field.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return \Google\Web_Stories\Interfaces\Field|BaseField
|
||||
*/
|
||||
public function author() {
|
||||
$label = parent::author()->label();
|
||||
|
||||
return $this->prepare_field(
|
||||
[
|
||||
'label' => $label,
|
||||
'show' => false,
|
||||
'hidden' => false,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
/**
|
||||
* Circle view based controls state.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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\Renderer\Stories\FieldState;
|
||||
|
||||
use Google\Web_Stories\Renderer\Stories\Fields\BaseField;
|
||||
|
||||
/**
|
||||
* Class CircleView.
|
||||
*/
|
||||
final class CircleView extends BaseFieldState {
|
||||
|
||||
/**
|
||||
* Title field.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return \Google\Web_Stories\Interfaces\Field|BaseField
|
||||
*/
|
||||
public function title() {
|
||||
$label = parent::title()->label();
|
||||
|
||||
return $this->prepare_field(
|
||||
[
|
||||
'label' => $label,
|
||||
'show' => false,
|
||||
'hidden' => false,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Author field.
|
||||
*
|
||||
* @return \Google\Web_Stories\Interfaces\Field|BaseField
|
||||
*/
|
||||
public function author() {
|
||||
$label = parent::author()->label();
|
||||
|
||||
return $this->prepare_field(
|
||||
[
|
||||
'label' => $label,
|
||||
'show' => false,
|
||||
'hidden' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Date field.
|
||||
*
|
||||
* @return \Google\Web_Stories\Interfaces\Field|BaseField
|
||||
*/
|
||||
public function date() {
|
||||
$label = parent::date()->label();
|
||||
|
||||
return $this->prepare_field(
|
||||
[
|
||||
'label' => $label,
|
||||
'show' => false,
|
||||
'hidden' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sharp corners field.
|
||||
*
|
||||
* @return \Google\Web_Stories\Interfaces\Field|BaseField
|
||||
*/
|
||||
public function sharp_corners() {
|
||||
$label = parent::sharp_corners()->label();
|
||||
|
||||
return $this->prepare_field(
|
||||
[
|
||||
'label' => $label,
|
||||
'show' => false,
|
||||
'hidden' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Circle size field.
|
||||
*
|
||||
* @return BaseField
|
||||
*/
|
||||
public function circle_size() {
|
||||
$label = parent::circle_size()->label();
|
||||
|
||||
return $this->prepare_field(
|
||||
[
|
||||
'label' => $label,
|
||||
'show' => true,
|
||||
'hidden' => false,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/**
|
||||
* List view based controls state.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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\Renderer\Stories\FieldState;
|
||||
|
||||
use Google\Web_Stories\Renderer\Stories\Fields\BaseField;
|
||||
|
||||
/**
|
||||
* Class GridView.
|
||||
*/
|
||||
final class GridView extends BaseFieldState {
|
||||
/**
|
||||
* Number of columns field.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return \Google\Web_Stories\Interfaces\Field|BaseField
|
||||
*/
|
||||
public function number_of_columns() {
|
||||
$label = parent::number_of_columns()->label();
|
||||
|
||||
return $this->prepare_field(
|
||||
[
|
||||
'label' => $label,
|
||||
'show' => true,
|
||||
'hidden' => false,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/**
|
||||
* List view based controls state.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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\Renderer\Stories\FieldState;
|
||||
|
||||
use Google\Web_Stories\Renderer\Stories\Fields\BaseField;
|
||||
|
||||
/**
|
||||
* Class ListView.
|
||||
*/
|
||||
final class ListView extends BaseFieldState {
|
||||
|
||||
/**
|
||||
* Excerpt field.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return \Google\Web_Stories\Interfaces\Field|BaseField
|
||||
*/
|
||||
public function excerpt() {
|
||||
$label = parent::excerpt()->label();
|
||||
|
||||
return $this->prepare_field(
|
||||
[
|
||||
'label' => $label,
|
||||
'show' => true,
|
||||
'hidden' => false,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Author field.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return \Google\Web_Stories\Interfaces\Field|BaseField
|
||||
*/
|
||||
public function date() {
|
||||
$label = parent::date()->label();
|
||||
|
||||
return $this->prepare_field(
|
||||
[
|
||||
'label' => $label,
|
||||
'show' => true,
|
||||
'hidden' => false,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Image alignment field.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return \Google\Web_Stories\Interfaces\Field|BaseField
|
||||
*/
|
||||
public function image_alignment() {
|
||||
$label = parent::image_alignment()->label();
|
||||
|
||||
return $this->prepare_field(
|
||||
[
|
||||
'label' => $label,
|
||||
'show' => true,
|
||||
'hidden' => false,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
/**
|
||||
* Field state factory.
|
||||
*
|
||||
* @link https://github.com/googleforcreators/web-stories-wp
|
||||
*
|
||||
* @copyright 2021 Google LLC
|
||||
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2021 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\Renderer\Stories\FieldStateFactory;
|
||||
|
||||
use Google\Web_Stories\Infrastructure\Injector;
|
||||
use Google\Web_Stories\Interfaces\FieldState;
|
||||
use Google\Web_Stories\Interfaces\FieldStateFactory;
|
||||
use Google\Web_Stories\Renderer\Stories\FieldState\CarouselView;
|
||||
use Google\Web_Stories\Renderer\Stories\FieldState\CircleView;
|
||||
use Google\Web_Stories\Renderer\Stories\FieldState\GridView;
|
||||
use Google\Web_Stories\Renderer\Stories\FieldState\ListView;
|
||||
|
||||
/**
|
||||
* Class Factory
|
||||
*/
|
||||
class Factory implements FieldStateFactory {
|
||||
|
||||
/**
|
||||
* Injector instance.
|
||||
*
|
||||
* @var Injector Injector instance.
|
||||
*/
|
||||
private Injector $injector;
|
||||
|
||||
/**
|
||||
* Factory constructor.
|
||||
*
|
||||
* @param Injector $injector Injector instance.
|
||||
*/
|
||||
public function __construct( Injector $injector ) {
|
||||
$this->injector = $injector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns field state for the provided view type.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param string $view View Type.
|
||||
* @return FieldState
|
||||
*/
|
||||
public function get_field( $view = 'grid' ) {
|
||||
switch ( $view ) {
|
||||
case 'grid':
|
||||
/**
|
||||
* GridView instance.
|
||||
*
|
||||
* @var FieldState
|
||||
*/
|
||||
$field_state = $this->injector->make( GridView::class );
|
||||
break;
|
||||
case 'list':
|
||||
/**
|
||||
* ListView instance.
|
||||
*
|
||||
* @var FieldState
|
||||
*/
|
||||
$field_state = $this->injector->make( ListView::class );
|
||||
break;
|
||||
case 'circles':
|
||||
/**
|
||||
* CircleView instance.
|
||||
*
|
||||
* @var FieldState
|
||||
*/
|
||||
$field_state = $this->injector->make( CircleView::class );
|
||||
break;
|
||||
case 'carousel':
|
||||
/**
|
||||
* CarouselView instance.
|
||||
*
|
||||
* @var FieldState
|
||||
*/
|
||||
$field_state = $this->injector->make( CarouselView::class );
|
||||
break;
|
||||
default:
|
||||
/**
|
||||
* CircleView instance.
|
||||
*
|
||||
* @var FieldState $default_field_state
|
||||
*/
|
||||
$default_field_state = $this->injector->make( CircleView::class );
|
||||
|
||||
/**
|
||||
* Filters the field state object.
|
||||
*
|
||||
* This depicts
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param FieldState $default_field_state Field state object.
|
||||
*/
|
||||
$field_state = apply_filters( 'web_stories_default_field_state', $default_field_state );
|
||||
}
|
||||
|
||||
return $field_state;
|
||||
}
|
||||
}
|
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/**
|
||||
* Base field class.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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\Renderer\Stories\Fields;
|
||||
|
||||
use Google\Web_Stories\Interfaces\Field;
|
||||
|
||||
/**
|
||||
* Class BaseField.
|
||||
*/
|
||||
class BaseField implements Field {
|
||||
/**
|
||||
* Field label.
|
||||
*/
|
||||
private string $label;
|
||||
|
||||
/**
|
||||
* Whether the field is enabled.
|
||||
*/
|
||||
private bool $hidden;
|
||||
|
||||
/**
|
||||
* Whether to display the field.
|
||||
*/
|
||||
private bool $show;
|
||||
|
||||
/**
|
||||
* BaseField constructor.
|
||||
*
|
||||
* @param array<string,string|bool> $args Arguments.
|
||||
*/
|
||||
public function __construct( array $args ) {
|
||||
$this->label = isset( $args['label'] ) ? (string) $args['label'] : '';
|
||||
$this->hidden = ! isset( $args['hidden'] ) || $args['hidden'];
|
||||
$this->show = ! isset( $args['show'] ) || $args['show'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Label for the field.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function label(): string {
|
||||
return $this->label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag for field display.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function show(): bool {
|
||||
return $this->show;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the field is hidden.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hidden(): bool {
|
||||
return $this->hidden;
|
||||
}
|
||||
}
|
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
/**
|
||||
* Generic_Renderer class.
|
||||
*
|
||||
* @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\Renderer\Stories;
|
||||
|
||||
/**
|
||||
* Generic_Renderer class.
|
||||
*
|
||||
* This is named as `Generic` as this renderer class
|
||||
* will be used to output multiple view types, like:
|
||||
*
|
||||
* 1. Circle
|
||||
* 2. Grid
|
||||
* 3. List
|
||||
*
|
||||
* Since, markup for all these views type is similar, Generic Renderer
|
||||
* can be used to render the stories.
|
||||
*/
|
||||
class Generic_Renderer extends Renderer {
|
||||
|
||||
/**
|
||||
* Perform initial setup for object.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init(): void {
|
||||
|
||||
parent::init();
|
||||
|
||||
$this->load_assets();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the stories output for given attributes.
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.UnusedLocalVariable)
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param array<string,mixed> $args Array of rendering arguments.
|
||||
* @return string Rendered stories output.
|
||||
*/
|
||||
public function render( array $args = [] ): string {
|
||||
if ( ! $this->valid() ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
parent::render( $args );
|
||||
$container_classes = $this->get_container_classes();
|
||||
$container_styles = $this->get_container_styles();
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="<?php echo esc_attr( $container_classes ); ?>" data-id="<?php echo esc_attr( (string) $this->instance_id ); ?>">
|
||||
<div class="web-stories-list__inner-wrapper" style="<?php echo esc_attr( $container_styles ); ?>">
|
||||
<?php
|
||||
array_map(
|
||||
function () {
|
||||
$this->render_single_story_content();
|
||||
$this->next();
|
||||
},
|
||||
$this->stories
|
||||
);
|
||||
$this->maybe_render_archive_link();
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
$view_type = $this->get_view_type();
|
||||
$content = (string) ob_get_clean();
|
||||
|
||||
/**
|
||||
* Filters the Generic renderer stories content.
|
||||
*
|
||||
* The dynamic portion of the hook `$this->get_view_type()` refers to the story view type.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param string $content Stories content.
|
||||
*/
|
||||
return apply_filters( "web_stories_{$view_type}_renderer_stories_content", $content );
|
||||
}
|
||||
}
|
@@ -0,0 +1,843 @@
|
||||
<?php
|
||||
/**
|
||||
* Stories Renderer Base class.
|
||||
*
|
||||
* @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\Renderer\Stories;
|
||||
|
||||
use Google\Web_Stories\AMP_Story_Player_Assets;
|
||||
use Google\Web_Stories\Assets;
|
||||
use Google\Web_Stories\Context;
|
||||
use Google\Web_Stories\Interfaces\Renderer as RenderingInterface;
|
||||
use Google\Web_Stories\Model\Story;
|
||||
use Google\Web_Stories\Services;
|
||||
use Google\Web_Stories\Story_Post_Type;
|
||||
use Google\Web_Stories\Story_Query;
|
||||
use Iterator;
|
||||
use WP_Post;
|
||||
|
||||
/**
|
||||
* Renderer class.
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
|
||||
* @SuppressWarnings(PHPMD.TooManyPublicMethods)
|
||||
*
|
||||
* @phpstan-import-type StoryAttributes from \Google\Web_Stories\Story_Query
|
||||
*
|
||||
* @implements Iterator<int, Story>
|
||||
*/
|
||||
abstract class Renderer implements RenderingInterface, Iterator {
|
||||
/**
|
||||
* Web Stories stylesheet handle.
|
||||
*/
|
||||
public const STYLE_HANDLE = 'web-stories-list-styles';
|
||||
|
||||
/**
|
||||
* Web Stories stylesheet handle.
|
||||
*/
|
||||
public const LIGHTBOX_SCRIPT_HANDLE = 'web-stories-lightbox';
|
||||
|
||||
/**
|
||||
* Number of instances invoked. Kept it static to keep track.
|
||||
*/
|
||||
protected static int $instances = 0;
|
||||
|
||||
/**
|
||||
* Assets instance.
|
||||
*
|
||||
* @var Assets Assets instance.
|
||||
*/
|
||||
protected Assets $assets;
|
||||
|
||||
/**
|
||||
* Context instance.
|
||||
*
|
||||
* @var Context Context instance.
|
||||
*/
|
||||
protected Context $context;
|
||||
|
||||
/**
|
||||
* Object ID for the Renderer class.
|
||||
* To enable support for multiple carousels and lightboxes
|
||||
* on the same page, we needed to identify each Renderer instance.
|
||||
*
|
||||
* This variable is used to add appropriate class to the Web Stories
|
||||
* wrapper.
|
||||
*/
|
||||
protected int $instance_id = 0;
|
||||
|
||||
/**
|
||||
* Story_Query instance.
|
||||
*
|
||||
* @var Story_Query Story_Query instance.
|
||||
*/
|
||||
protected Story_Query $query;
|
||||
|
||||
/**
|
||||
* Story attributes
|
||||
*
|
||||
* @var array<string, string|int|bool> An array of story attributes.
|
||||
* @phpstan-var StoryAttributes
|
||||
*/
|
||||
protected array $attributes = [];
|
||||
|
||||
/**
|
||||
* Story posts.
|
||||
*
|
||||
* @var Story[] An array of story posts.
|
||||
*/
|
||||
protected array $stories = [];
|
||||
|
||||
/**
|
||||
* Holds required html for the lightbox.
|
||||
*
|
||||
* @var string A string of lightbox markup.
|
||||
*/
|
||||
protected string $lightbox_html = '';
|
||||
|
||||
/**
|
||||
* Pointer to iterate over stories.
|
||||
*/
|
||||
private int $position = 0;
|
||||
|
||||
/**
|
||||
* Height for displaying story.
|
||||
*/
|
||||
protected int $height = 308;
|
||||
|
||||
/**
|
||||
* Width for displaying story.
|
||||
*/
|
||||
protected int $width = 185;
|
||||
|
||||
/**
|
||||
* Whether content overlay is enabled for story.
|
||||
*/
|
||||
protected bool $content_overlay;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param Story_Query $query Story_Query instance.
|
||||
*/
|
||||
public function __construct( Story_Query $query ) {
|
||||
$this->query = $query;
|
||||
$this->attributes = $this->query->get_story_attributes();
|
||||
$this->content_overlay = $this->attributes['show_title'] || $this->attributes['show_date'] || $this->attributes['show_author'] || $this->attributes['show_excerpt'];
|
||||
|
||||
// TODO, find a way to inject this a cleaner way.
|
||||
$injector = Services::get_injector();
|
||||
|
||||
/**
|
||||
* Assets instance.
|
||||
*
|
||||
* @var Assets $assets Assets instance.
|
||||
*/
|
||||
$assets = $injector->make( Assets::class );
|
||||
|
||||
/**
|
||||
* Context instance.
|
||||
*
|
||||
* @var Context $context Context instance.
|
||||
*/
|
||||
$context = $injector->make( Context::class );
|
||||
|
||||
$this->assets = $assets;
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output markup for amp stories.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param array<string,mixed> $args Array of rendering arguments.
|
||||
* @return string
|
||||
*/
|
||||
public function render( array $args = [] ): string {
|
||||
++self::$instances;
|
||||
$this->instance_id = self::$instances;
|
||||
|
||||
foreach ( $args as $key => $val ) {
|
||||
if ( property_exists( $this, $key ) ) {
|
||||
$this->{$key} = $val;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve current story.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return Story|null
|
||||
*/
|
||||
public function current(): ?Story {
|
||||
return $this->stories[ $this->position ] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve next story.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function next(): void {
|
||||
++$this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the key for current node in list.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return bool|float|int|string|void|null
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function key() {
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current position is valid.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function valid(): bool {
|
||||
return isset( $this->stories[ $this->position ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset pointer to start of the list.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function rewind(): void {
|
||||
$this->position = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform initial setup for object.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init(): void {
|
||||
$this->stories = array_filter( array_map( [ $this, 'prepare_stories' ], $this->query->get_stories() ) );
|
||||
|
||||
add_action( 'wp_footer', [ $this, 'render_stories_lightbox' ] );
|
||||
add_action( 'amp_post_template_footer', [ $this, 'render_stories_lightbox' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes renderer functionality.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function load_assets(): void {
|
||||
if ( wp_style_is( self::STYLE_HANDLE, 'registered' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Web Stories styles for AMP and non-AMP pages.
|
||||
$this->assets->register_style_asset( self::STYLE_HANDLE );
|
||||
|
||||
// Web Stories lightbox script.
|
||||
$this->assets->register_script_asset( self::LIGHTBOX_SCRIPT_HANDLE, [ AMP_Story_Player_Assets::SCRIPT_HANDLE ] );
|
||||
|
||||
if ( \defined( 'AMPFORWP_VERSION' ) ) {
|
||||
add_action( 'amp_post_template_css', [ $this, 'add_amp_post_template_css' ] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints required inline CSS when using the AMP for WP plugin.
|
||||
*
|
||||
* @since 1.13.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_amp_post_template_css(): void {
|
||||
$path = $this->assets->get_base_path( sprintf( 'assets/css/%s%s.css', self::STYLE_HANDLE, is_rtl() ? '-rtl' : '' ) );
|
||||
|
||||
if ( is_readable( $path ) ) {
|
||||
$css = file_get_contents( $path ); // phpcs:ignore WordPressVIPMinimum.Performance.FetchingRemoteData.FileGetContentsUnknown
|
||||
echo $css; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns story item data.
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.NPathComplexity)
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param object $post Array of post objects.
|
||||
* @return Story|null Story object or null if given post
|
||||
*/
|
||||
public function prepare_stories( $post ): ?Story {
|
||||
if ( ! $post instanceof WP_Post ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$story_data = [];
|
||||
|
||||
// TODO: get from field state instead.
|
||||
if ( ! $this->is_view_type( 'circles' ) ) {
|
||||
if ( isset( $this->attributes['show_author'] ) && true === $this->attributes['show_author'] ) {
|
||||
$author_id = absint( get_post_field( 'post_author', $post->ID ) );
|
||||
|
||||
$story_data['author'] = get_the_author_meta( 'display_name', $author_id );
|
||||
}
|
||||
|
||||
if ( isset( $this->attributes['show_date'] ) && true === $this->attributes['show_date'] ) {
|
||||
/* translators: Date format, see https://www.php.net/manual/en/datetime.format.php */
|
||||
$story_data['date'] = get_the_date( __( 'M j, Y', 'web-stories' ), $post->ID );
|
||||
}
|
||||
}
|
||||
|
||||
$story_data['classes'] = $this->get_single_story_classes();
|
||||
|
||||
$story = new Story( $story_data );
|
||||
$story->load_from_post( $post );
|
||||
|
||||
return $story;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render story markup.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render_single_story_content(): void {
|
||||
/**
|
||||
* Story object.
|
||||
*
|
||||
* @var Story $story
|
||||
*/
|
||||
$story = $this->current();
|
||||
|
||||
$single_story_classes = $this->get_single_story_classes();
|
||||
$lightbox_state = 'lightbox' . $story->get_id() . $this->instance_id;
|
||||
// No need to load these styles on admin as editor styles are being loaded by the block.
|
||||
if ( ! is_admin() || ( \defined( 'IFRAME_REQUEST' ) && IFRAME_REQUEST ) ) {
|
||||
// Web Stories Styles for AMP and non-AMP pages.
|
||||
$this->assets->enqueue_style_asset( self::STYLE_HANDLE );
|
||||
}
|
||||
|
||||
if ( $this->context->is_amp() ) {
|
||||
?>
|
||||
<div
|
||||
class="<?php echo esc_attr( $single_story_classes ); ?>"
|
||||
on="<?php echo esc_attr( sprintf( 'tap:AMP.setState({%1$s: ! %1$s})', $lightbox_state ) ); ?>"
|
||||
tabindex="0"
|
||||
role="button"
|
||||
>
|
||||
<?php $this->render_story_with_poster(); ?>
|
||||
</div>
|
||||
<?php
|
||||
} else {
|
||||
$this->assets->enqueue_style( AMP_Story_Player_Assets::SCRIPT_HANDLE );
|
||||
$this->assets->enqueue_script( AMP_Story_Player_Assets::SCRIPT_HANDLE );
|
||||
$this->assets->enqueue_script_asset( self::LIGHTBOX_SCRIPT_HANDLE );
|
||||
?>
|
||||
<div class="<?php echo esc_attr( $single_story_classes ); ?>">
|
||||
<?php $this->render_story_with_poster(); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the lightbox markup for non-amp pages.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render_stories_with_lightbox(): void {
|
||||
$data = [
|
||||
'controls' => [
|
||||
[
|
||||
'name' => 'close',
|
||||
'position' => 'start',
|
||||
],
|
||||
[
|
||||
'name' => 'skip-next',
|
||||
],
|
||||
],
|
||||
'behavior' => [
|
||||
'autoplay' => false,
|
||||
],
|
||||
];
|
||||
?>
|
||||
<div class="web-stories-list__lightbox">
|
||||
<amp-story-player width="3.6" height="6" layout="responsive">
|
||||
<script type="application/json">
|
||||
<?php echo wp_json_encode( $data ); ?>
|
||||
</script>
|
||||
<?php echo wp_kses_post( $this->lightbox_html ); ?>
|
||||
</amp-story-player>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the lightbox markup for non-amp pages.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render_stories_with_lightbox_amp(): void {
|
||||
// Have to ignore this as the escaping functions are stripping off 'amp-bind' custom attribute '[class]'.
|
||||
echo $this->lightbox_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Generated with properly escaped data.
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders stories lightbox on 'wp_footer'.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render_stories_lightbox(): void {
|
||||
// Return if we don't have anything to render.
|
||||
if ( empty( $this->lightbox_html ) ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<div class="web-stories-list__lightbox-wrapper <?php echo esc_attr( 'ws-lightbox-' . $this->instance_id ); ?>">
|
||||
<?php
|
||||
if ( $this->context->is_amp() ) {
|
||||
$this->render_stories_with_lightbox_amp();
|
||||
} else {
|
||||
$this->render_stories_with_lightbox();
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the current view type.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param string $view_type View type to check.
|
||||
* @return bool Whether or not current view type matches the one passed.
|
||||
*/
|
||||
protected function is_view_type( $view_type ): bool {
|
||||
return ( ! empty( $this->attributes['view_type'] ) && $view_type === $this->attributes['view_type'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get view type for stories.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_view_type(): string {
|
||||
return ! empty( $this->attributes['view_type'] ) ? $this->attributes['view_type'] : 'circles';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders stories archive link if the 'show_archive_link' attribute is set to true.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function maybe_render_archive_link(): void {
|
||||
if (
|
||||
empty( $this->attributes['show_archive_link'] ) ||
|
||||
true !== $this->attributes['show_archive_link'] ||
|
||||
empty( $this->attributes['archive_link_label'] )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$web_stories_archive = get_post_type_archive_link( Story_Post_Type::POST_TYPE_SLUG );
|
||||
|
||||
if ( empty( $web_stories_archive ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
?>
|
||||
<div class="web-stories-list__archive-link">
|
||||
<a href="<?php echo esc_url( $web_stories_archive ); ?>">
|
||||
<?php echo esc_html( $this->attributes['archive_link_label'] ); ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the classes for renderer container.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_view_classes(): string {
|
||||
$view_classes = [];
|
||||
$view_classes[] = ! empty( $this->attributes['view_type'] ) ? sprintf( 'is-view-type-%1$s', $this->attributes['view_type'] ) : 'is-view-type-circles';
|
||||
|
||||
if ( $this->is_view_type( 'grid' ) && ! empty( $this->attributes['number_of_columns'] ) ) {
|
||||
$view_classes[] = sprintf( 'columns-%1$d', $this->attributes['number_of_columns'] );
|
||||
}
|
||||
|
||||
if ( ! $this->is_view_type( 'circles' ) && ! empty( $this->attributes['sharp_corners'] ) ) {
|
||||
$view_classes[] = 'is-style-squared';
|
||||
} else {
|
||||
$view_classes[] = 'is-style-default';
|
||||
}
|
||||
|
||||
if ( $this->is_view_type( 'circles' ) && ! empty( $this->attributes['show_title'] ) ) {
|
||||
$view_classes[] = 'has-title';
|
||||
}
|
||||
|
||||
if ( $this->is_view_type( 'circles' ) || $this->is_view_type( 'carousel' ) ) {
|
||||
$view_classes[] = 'is-carousel';
|
||||
}
|
||||
|
||||
return implode( ' ', $view_classes );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the classes for renderer container.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_container_classes(): string {
|
||||
$container_classes = [];
|
||||
$container_classes[] = 'web-stories-list';
|
||||
$container_classes[] = ! empty( $this->attributes['align'] ) ? sprintf( 'align%1$s', $this->attributes['align'] ) : 'alignnone';
|
||||
$container_classes[] = ! empty( $this->attributes['class'] ) ? $this->attributes['class'] : '';
|
||||
|
||||
if ( ! empty( $this->attributes['show_archive_link'] ) ) {
|
||||
$container_classes[] = 'has-archive-link';
|
||||
}
|
||||
|
||||
$container_classes = array_filter( $container_classes );
|
||||
|
||||
$view_type_classes = $this->get_view_classes();
|
||||
|
||||
return sprintf( '%1$s %2$s', implode( ' ', $container_classes ), $view_type_classes );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the single story container classes.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_single_story_classes(): string {
|
||||
$single_story_classes = [];
|
||||
$single_story_classes[] = 'web-stories-list__story';
|
||||
|
||||
if ( $this->context->is_amp() ) {
|
||||
$single_story_classes[] = 'web-stories-list__story--amp';
|
||||
}
|
||||
|
||||
if ( ! empty( $this->attributes['image_alignment'] ) && ( 'right' === $this->attributes['image_alignment'] ) ) {
|
||||
$single_story_classes[] = 'image-align-right';
|
||||
}
|
||||
|
||||
$classes = implode( ' ', $single_story_classes );
|
||||
|
||||
/**
|
||||
* Filters the web stories renderer single story classes.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param string $classes Single story classes.
|
||||
*/
|
||||
return apply_filters( 'web_stories_renderer_single_story_classes', $classes );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the single story container styles.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return string Style string.
|
||||
*/
|
||||
protected function get_container_styles(): string {
|
||||
$story_styles = ! empty( $this->attributes['circle_size'] ) && $this->is_view_type( 'circles' ) ?
|
||||
sprintf( '--ws-circle-size:%1$dpx', $this->attributes['circle_size'] ) :
|
||||
'';
|
||||
$story_styles .= $this->is_view_type( 'carousel' ) ? sprintf( '--ws-story-max-width:%1$dpx', $this->width ) : '';
|
||||
|
||||
/**
|
||||
* Filters the web stories renderer single story classes.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param string $story_styles Single story classes.
|
||||
*/
|
||||
return apply_filters( 'web_stories_renderer_container_styles', $story_styles );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a story with story's poster image.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function render_story_with_poster(): void {
|
||||
/**
|
||||
* Story object.
|
||||
*
|
||||
* @var Story $story
|
||||
*/
|
||||
$story = $this->current();
|
||||
|
||||
$poster_url = $story->get_poster_portrait();
|
||||
$poster_srcset = $story->get_poster_srcset();
|
||||
$poster_sizes = $story->get_poster_sizes();
|
||||
|
||||
if ( ! $poster_url ) {
|
||||
?>
|
||||
<div class="web-stories-list__story-poster">
|
||||
<div class="web-stories-list__story-poster-placeholder">
|
||||
<a href="<?php echo esc_url( $story->get_url() ); ?>" <?php $this->render_link_attributes(); ?>>
|
||||
<?php echo esc_html( $story->get_title() ); ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<div class="web-stories-list__story-poster">
|
||||
<a href="<?php echo esc_url( $story->get_url() ); ?>" <?php $this->render_link_attributes(); ?>>
|
||||
<img
|
||||
src="<?php echo esc_url( $poster_url ); ?>"
|
||||
alt="<?php echo esc_attr( $story->get_title() ); ?>"
|
||||
width="<?php echo absint( $this->width ); ?>"
|
||||
height="<?php echo absint( $this->height ); ?>"
|
||||
<?php if ( ! empty( $poster_srcset ) ) { ?>
|
||||
srcset="<?php echo esc_attr( $poster_srcset ); ?>"
|
||||
<?php } ?>
|
||||
<?php if ( ! empty( $poster_sizes ) ) { ?>
|
||||
sizes="<?php echo esc_attr( $poster_sizes ); ?>"
|
||||
<?php } ?>
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
>
|
||||
</a>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
$this->get_content_overlay();
|
||||
|
||||
if ( ! $this->context->is_amp() ) {
|
||||
$this->generate_lightbox_html( $story );
|
||||
} else {
|
||||
$this->generate_amp_lightbox_html_amp( $story );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render additional link attributes.
|
||||
*
|
||||
* Allows customization of html attributes in the web stories widget anchor tag loop
|
||||
* Converts array into escaped inline html attributes.
|
||||
*
|
||||
* @since 1.17.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function render_link_attributes(): void {
|
||||
/**
|
||||
* The current story.
|
||||
*
|
||||
* @var Story $story
|
||||
*/
|
||||
$story = $this->current();
|
||||
|
||||
/**
|
||||
* Filters the link attributes added to a story's <a> tag.
|
||||
*
|
||||
* @since 1.17.0
|
||||
*
|
||||
* @param array $attributes Key value array of attribute name to attribute value.
|
||||
* @param Story $story The current story instance.
|
||||
* @param int $position The current story's position within the list.
|
||||
* @param string $view_type The current view type.
|
||||
*/
|
||||
$attributes = apply_filters( 'web_stories_renderer_link_attributes', [], $story, $this->position, $this->get_view_type() );
|
||||
|
||||
$attrs = [];
|
||||
|
||||
if ( ! empty( $attributes ) ) {
|
||||
foreach ( $attributes as $attribute => $value ) {
|
||||
$attrs[] = wp_kses_one_attr( $attribute . '="' . esc_attr( $value ) . '"', 'a' );
|
||||
}
|
||||
}
|
||||
|
||||
$attrs = array_filter( $attrs ); // Filter out empty values rejected by KSES.
|
||||
|
||||
//phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo implode( ' ', $attrs );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the content overlay markup.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function get_content_overlay(): void {
|
||||
/**
|
||||
* Story object.
|
||||
*
|
||||
* @var Story $story
|
||||
*/
|
||||
$story = $this->current();
|
||||
|
||||
if ( empty( $this->content_overlay ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
?>
|
||||
<div class="web-stories-list__story-content-overlay">
|
||||
<?php if ( ! empty( $this->attributes['show_title'] ) ) { ?>
|
||||
<div class="story-content-overlay__title">
|
||||
<?php echo esc_html( $story->get_title() ); ?>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<?php if ( ! empty( $this->attributes['show_excerpt'] ) ) { ?>
|
||||
<div class="story-content-overlay__excerpt">
|
||||
<?php echo esc_html( $story->get_excerpt() ); ?>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<?php if ( ! empty( $story->get_author() ) ) { ?>
|
||||
<div class="story-content-overlay__author">
|
||||
<?php
|
||||
/* translators: byline. %s: author name. */
|
||||
echo esc_html( sprintf( __( 'By %s', 'web-stories' ), $story->get_author() ) );
|
||||
?>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<?php if ( ! empty( $story->get_date() ) ) { ?>
|
||||
<time class="story-content-overlay__date">
|
||||
<?php
|
||||
/* translators: %s: publish date. */
|
||||
echo esc_html( sprintf( __( 'On %s', 'web-stories' ), $story->get_date() ) );
|
||||
?>
|
||||
</time>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate HTML for the non-AMP page request.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param Story $story Current Story.
|
||||
* @return void
|
||||
*/
|
||||
protected function generate_lightbox_html( $story ): void {
|
||||
// Start collecting markup for the lightbox stories. This way we don't have to re-run the loop.
|
||||
ob_start();
|
||||
|
||||
// Collect story links to fill-in non-AMP lightbox 'amp-story-player'.
|
||||
?>
|
||||
<a href="<?php echo esc_url( $story->get_url() ); ?>" <?php $this->render_link_attributes(); ?>><?php echo esc_html( $story->get_title() ); ?></a>
|
||||
<?php
|
||||
|
||||
$this->lightbox_html .= ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Markup for the lightbox used on AMP pages.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param Story $story Current Story.
|
||||
* @return void
|
||||
*/
|
||||
protected function generate_amp_lightbox_html_amp( $story ): void {
|
||||
// Start collecting markup for the lightbox stories. This way we don't have to re-run the loop.
|
||||
ob_start();
|
||||
$lightbox_state = 'lightbox' . $story->get_id() . $this->instance_id;
|
||||
$lightbox_id = 'lightbox-' . $story->get_id() . $this->instance_id;
|
||||
?>
|
||||
<amp-lightbox
|
||||
id="<?php echo esc_attr( $lightbox_id ); ?>"
|
||||
[open]="<?php echo esc_attr( $lightbox_state ); ?>"
|
||||
layout="nodisplay"
|
||||
on="lightboxClose:AMP.setState({<?php echo esc_attr( $lightbox_state ); ?>: false})"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="web-stories-list__lightbox show">
|
||||
<button type="button"
|
||||
class="story-lightbox__close-button"
|
||||
on="tap:<?php echo esc_attr( $lightbox_id ); ?>.close"
|
||||
aria-label="<?php esc_attr_e( 'Close', 'web-stories' ); ?>"
|
||||
>
|
||||
<span class="story-lightbox__close-button--stick"></span>
|
||||
<span class="story-lightbox__close-button--stick"></span>
|
||||
</button>
|
||||
<amp-story-player
|
||||
width="3.6"
|
||||
height="6"
|
||||
layout="responsive"
|
||||
>
|
||||
<a href="<?php echo esc_url( $story->get_url() ); ?>" <?php $this->render_link_attributes(); ?>><?php echo esc_html( $story->get_title() ); ?></a>
|
||||
</amp-story-player>
|
||||
</div>
|
||||
</amp-lightbox>
|
||||
<?php
|
||||
$this->lightbox_html .= ob_get_clean();
|
||||
}
|
||||
}
|
191
wp-content/plugins/web-stories/includes/Renderer/Story/Embed.php
Normal file
191
wp-content/plugins/web-stories/includes/Renderer/Story/Embed.php
Normal file
@@ -0,0 +1,191 @@
|
||||
<?php
|
||||
/**
|
||||
* Class Embed
|
||||
*
|
||||
* @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\Renderer\Story;
|
||||
|
||||
use Google\Web_Stories\AMP_Story_Player_Assets;
|
||||
use Google\Web_Stories\Assets;
|
||||
use Google\Web_Stories\Context;
|
||||
use Google\Web_Stories\Embed_Base;
|
||||
use Google\Web_Stories\Model\Story;
|
||||
|
||||
/**
|
||||
* Class Embed
|
||||
*/
|
||||
class Embed {
|
||||
/**
|
||||
* Current post.
|
||||
*
|
||||
* @var Story Post object.
|
||||
*/
|
||||
protected Story $story;
|
||||
|
||||
/**
|
||||
* Assets instance.
|
||||
*
|
||||
* @var Assets Assets instance.
|
||||
*/
|
||||
private Assets $assets;
|
||||
|
||||
/**
|
||||
* Context instance.
|
||||
*
|
||||
* @var Context Context instance.
|
||||
*/
|
||||
private Context $context;
|
||||
|
||||
/**
|
||||
* Embed constructor.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param Story $story Story instance.
|
||||
* @param Assets $assets Assets instance.
|
||||
* @param Context $context Context instance.
|
||||
*/
|
||||
public function __construct( Story $story, Assets $assets, Context $context ) {
|
||||
$this->assets = $assets;
|
||||
$this->story = $story;
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the block output in default context.
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param array<string,string|int> $args Array of Argument to render.
|
||||
* @return string Rendered block type output.
|
||||
*/
|
||||
public function render( array $args = [] ): string {
|
||||
$defaults = [
|
||||
'align' => 'none',
|
||||
'class' => 'wp-block-web-stories-embed',
|
||||
'height' => 600,
|
||||
'width' => 360,
|
||||
];
|
||||
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
$align = sprintf( 'align%s', $args['align'] );
|
||||
$class = $args['class'];
|
||||
$url = $this->story->get_url();
|
||||
$title = $this->story->get_title();
|
||||
$poster = $this->story->get_poster_portrait();
|
||||
$poster_srcset = $this->story->get_poster_srcset();
|
||||
$poster_sizes = $this->story->get_poster_sizes();
|
||||
|
||||
$wrapper_style = sprintf(
|
||||
'--aspect-ratio: %F; --width: %dpx; --height: %dpx',
|
||||
0 !== $args['height'] ? $args['width'] / $args['height'] : 1,
|
||||
(int) $args['width'],
|
||||
(int) $args['height']
|
||||
);
|
||||
|
||||
// This CSS is used for AMP and non-AMP.
|
||||
$this->assets->enqueue_style_asset( Embed_Base::SCRIPT_HANDLE );
|
||||
|
||||
if ( $this->context->is_amp() ) {
|
||||
ob_start();
|
||||
?>
|
||||
<div class="<?php echo esc_attr( "$class web-stories-embed web-stories-embed-amp $align" ); ?>">
|
||||
<div class="wp-block-embed__wrapper" style="<?php echo esc_attr( $wrapper_style ); ?>">
|
||||
<amp-story-player
|
||||
width="<?php echo esc_attr( $args['width'] ); ?>"
|
||||
height="<?php echo esc_attr( $args['height'] ); ?>"
|
||||
layout="intrinsic">
|
||||
<a href="<?php echo esc_url( $url ); ?>">
|
||||
<?php if ( $poster ) { ?>
|
||||
<img
|
||||
src="<?php echo esc_url( $poster ); ?>"
|
||||
width="<?php echo esc_attr( $args['width'] ); ?>"
|
||||
height="<?php echo esc_attr( $args['height'] ); ?>"
|
||||
alt="<?php echo esc_attr( $title ); ?>"
|
||||
<?php if ( ! empty( $poster_srcset ) ) { ?>
|
||||
srcset="<?php echo esc_attr( $poster_srcset ); ?>"
|
||||
<?php } ?>
|
||||
<?php if ( ! empty( $poster_sizes ) ) { ?>
|
||||
sizes="<?php echo esc_attr( $poster_sizes ); ?>"
|
||||
<?php } ?>
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-amp-story-player-poster-img
|
||||
/>
|
||||
<?php
|
||||
} else {
|
||||
echo esc_html( $title );
|
||||
}
|
||||
?>
|
||||
</a>
|
||||
</amp-story-player>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
return (string) ob_get_clean();
|
||||
}
|
||||
$this->assets->enqueue_style( AMP_Story_Player_Assets::SCRIPT_HANDLE );
|
||||
$this->assets->enqueue_script( AMP_Story_Player_Assets::SCRIPT_HANDLE );
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="<?php echo esc_attr( "$class web-stories-embed $align" ); ?>">
|
||||
<div class="wp-block-embed__wrapper" style="<?php echo esc_attr( $wrapper_style ); ?>">
|
||||
<amp-story-player>
|
||||
<a href="<?php echo esc_url( $url ); ?>">
|
||||
<?php if ( $poster ) { ?>
|
||||
<img
|
||||
src="<?php echo esc_url( $poster ); ?>"
|
||||
width="<?php echo esc_attr( $args['width'] ); ?>"
|
||||
height="<?php echo esc_attr( $args['height'] ); ?>"
|
||||
alt="<?php echo esc_attr( $title ); ?>"
|
||||
<?php if ( ! empty( $poster_srcset ) ) { ?>
|
||||
srcset="<?php echo esc_attr( $poster_srcset ); ?>"
|
||||
<?php } ?>
|
||||
<?php if ( ! empty( $poster_sizes ) ) { ?>
|
||||
sizes="<?php echo esc_attr( $poster_sizes ); ?>"
|
||||
<?php } ?>
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-amp-story-player-poster-img
|
||||
/>
|
||||
<?php
|
||||
} else {
|
||||
echo esc_html( $title );
|
||||
}
|
||||
?>
|
||||
</a>
|
||||
</amp-story-player>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
return (string) ob_get_clean();
|
||||
}
|
||||
}
|
269
wp-content/plugins/web-stories/includes/Renderer/Story/HTML.php
Normal file
269
wp-content/plugins/web-stories/includes/Renderer/Story/HTML.php
Normal file
@@ -0,0 +1,269 @@
|
||||
<?php
|
||||
/**
|
||||
* Class HTML
|
||||
*
|
||||
* @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\Renderer\Story;
|
||||
|
||||
use Google\Web_Stories\Model\Story;
|
||||
|
||||
/**
|
||||
* Class HTML
|
||||
*/
|
||||
class HTML {
|
||||
/**
|
||||
* Current post.
|
||||
*
|
||||
* @var Story Post object.
|
||||
*/
|
||||
protected Story $story;
|
||||
|
||||
/**
|
||||
* HTML constructor.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param Story $story Story object.
|
||||
*/
|
||||
public function __construct( Story $story ) {
|
||||
$this->story = $story;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the story.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return string The complete HTML markup for the story.
|
||||
*/
|
||||
public function render(): string {
|
||||
$markup = $this->story->get_markup();
|
||||
$markup = $this->fix_incorrect_charset( $markup );
|
||||
$markup = $this->fix_malformed_script_link_tags( $markup );
|
||||
$markup = $this->replace_html_head( $markup );
|
||||
$markup = wp_replace_insecure_home_url( $markup );
|
||||
$markup = $this->print_analytics( $markup );
|
||||
$markup = $this->print_social_share( $markup );
|
||||
|
||||
return $markup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix incorrect <meta charset> tags.
|
||||
*
|
||||
* React/JSX outputs the charset attribute name as "charSet",
|
||||
* but libdom and the AMP toolbox only recognize lowercase "charset"
|
||||
*
|
||||
* @since 1.28.0
|
||||
*
|
||||
* @param string $content Story markup.
|
||||
* @return string Filtered content
|
||||
*/
|
||||
public function fix_incorrect_charset( string $content ): string {
|
||||
return (string) preg_replace( '/<meta charSet="utf-8"\s?\/>/i', '<meta charset="utf-8"/>', $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix malformed <a> tags in the <head>.
|
||||
*
|
||||
* On certain environments like WordPress.com VIP, there is additional KSES
|
||||
* hardening that prevents saving `<script>` tags to the database, despite
|
||||
* this plugin allowing them ({@see KSES}).
|
||||
*
|
||||
* There, script tags somehow get transformed to `<a>` tags before saving
|
||||
* to the database.
|
||||
* This of course breaks the markup completely as `<a>` is not allowed in the `<head>`,
|
||||
* thus the DOMDocument parser moves them to the `<body>`, breaking the DOM structure.
|
||||
*
|
||||
* Since we cannot prevent the broken `<a>`/`<script>` tags upon saving
|
||||
* and not during sanitization, this method is an attempt to fix them
|
||||
* *before* they're sanitized.
|
||||
*
|
||||
* Turns `<a href="https://cdn.ampproject.org/v0.js">https://cdn.ampproject.org/v0.js</a>`
|
||||
* into `<script async src="https://cdn.ampproject.org/v0.js"></script>`
|
||||
* and `<a href="https://cdn.ampproject.org/v0/amp-story-1.0.js">https://cdn.ampproject.org/v0/amp-story-1.0.js</a>`
|
||||
* into `<script async src="https://cdn.ampproject.org/v0/amp-story-1.0.js" custom-element="amp-story"></script>`.
|
||||
*
|
||||
* @since 1.13.0
|
||||
*
|
||||
* @param string $content Story markup.
|
||||
* @return string Filtered content
|
||||
*/
|
||||
protected function fix_malformed_script_link_tags( string $content ): string {
|
||||
$replaced_content = preg_replace_callback(
|
||||
'/<a[^>]+href="(?P<href>[^"]+)"[^>]*>\1<\/a>/m',
|
||||
static function ( $matches ) {
|
||||
if ( str_starts_with( $matches['href'], 'https://cdn.ampproject.org/' ) ) {
|
||||
$script_url = $matches['href'];
|
||||
|
||||
// Turns `<a href="https://cdn.ampproject.org/v0.js">https://cdn.ampproject.org/v0.js</a>`
|
||||
// into `<script async src="https://cdn.ampproject.org/v0.js"></script>`.
|
||||
if ( 'https://cdn.ampproject.org/v0.js' === $script_url ) {
|
||||
return "<script async src=\"$script_url\"></script>"; // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript
|
||||
}
|
||||
|
||||
// Extract 'amp-story' from 'https://cdn.ampproject.org/v0/amp-story-1.0.js'.
|
||||
$sub_matches = [];
|
||||
preg_match( '/v0\/(?P<custom_element>[\w-]+)-[\d.]+\.js/', $script_url, $sub_matches );
|
||||
$custom_element = $sub_matches['custom_element'];
|
||||
|
||||
// Turns `<a href="https://cdn.ampproject.org/v0/amp-story-1.0.js">https://cdn.ampproject.org/v0/amp-story-1.0.js</a>`
|
||||
// into <script async src="https://cdn.ampproject.org/v0/amp-story-1.0.js" custom-element="amp-story"></script>.
|
||||
return "<script async src=\"$script_url\" custom-element=\"$custom_element\"></script>"; // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript
|
||||
}
|
||||
|
||||
return $matches[0];
|
||||
},
|
||||
$content
|
||||
);
|
||||
|
||||
// On errors the return value of preg_replace_callback() is null.
|
||||
return $replaced_content ?: $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full HTML <head> markup for a given story besides boilerplate.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return string Filtered content.
|
||||
*/
|
||||
protected function get_html_head_markup(): string {
|
||||
ob_start();
|
||||
?>
|
||||
<meta name="amp-story-generator-name" content="Web Stories for WordPress" />
|
||||
<meta name="amp-story-generator-version" content="<?php echo esc_attr( WEBSTORIES_VERSION ); ?>" />
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Prints scripts or data in the head tag on the front end.
|
||||
*/
|
||||
do_action( 'web_stories_story_head' );
|
||||
|
||||
return (string) ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces markers in HTML <head> with dynamic content.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $content Story markup.
|
||||
* @return string Filtered content.
|
||||
*/
|
||||
protected function replace_html_head( string $content ): string {
|
||||
$start_tag = '<meta name="web-stories-replace-head-start"/>';
|
||||
$end_tag = '<meta name="web-stories-replace-head-end"/>';
|
||||
|
||||
// Replace malformed meta tags with correct tags.
|
||||
$content = (string) preg_replace( '/<meta name="web-stories-replace-head-start\s?"\s?\/?>/i', $start_tag, $content );
|
||||
$content = (string) preg_replace( '/<meta name="web-stories-replace-head-end\s?"\s?\/?>/i', $end_tag, $content );
|
||||
|
||||
$start_tag_pos = strpos( $content, $start_tag );
|
||||
$end_tag_pos = strpos( $content, $end_tag );
|
||||
|
||||
if ( false !== $start_tag_pos && false !== $end_tag_pos ) {
|
||||
$end_tag_pos += \strlen( $end_tag );
|
||||
$content = substr_replace( $content, $this->get_html_head_markup(), $start_tag_pos, $end_tag_pos - $start_tag_pos );
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print analytics code before closing `</amp-story>`.
|
||||
*
|
||||
* @since 1.2.0
|
||||
*
|
||||
* @param string $content String to replace.
|
||||
*/
|
||||
protected function print_analytics( string $content ): string {
|
||||
ob_start();
|
||||
|
||||
/**
|
||||
* Fires before the closing <amp-story> tag.
|
||||
*
|
||||
* Can be used to print <amp-analytics> configuration.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
do_action( 'web_stories_print_analytics' );
|
||||
|
||||
$output = (string) ob_get_clean();
|
||||
|
||||
return str_replace( '</amp-story>', $output . '</amp-story>', $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* Print amp-story-social-share before closing `</amp-story>`.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param string $content String to replace.
|
||||
*/
|
||||
protected function print_social_share( string $content ): string {
|
||||
$share_providers = [
|
||||
[
|
||||
'provider' => 'twitter',
|
||||
],
|
||||
[
|
||||
'provider' => 'linkedin',
|
||||
],
|
||||
[
|
||||
'provider' => 'email',
|
||||
],
|
||||
[
|
||||
'provider' => 'system',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Filters the list of sharing providers in the Web Stories sharing dialog.
|
||||
*
|
||||
* @since 1.3.0
|
||||
*
|
||||
* @link https://amp.dev/documentation/components/amp-social-share/?format=stories#pre-configured-providers
|
||||
*
|
||||
* @param array[] $share_providers List of sharing providers.
|
||||
*/
|
||||
$share_providers = apply_filters( 'web_stories_share_providers', $share_providers );
|
||||
|
||||
if ( empty( $share_providers ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
$config = [
|
||||
'shareProviders' => $share_providers,
|
||||
];
|
||||
$social_share = sprintf(
|
||||
'<amp-story-social-share layout="nodisplay"><script type="application/json">%s</script></amp-story-social-share>',
|
||||
wp_json_encode( $config )
|
||||
);
|
||||
|
||||
|
||||
return str_replace( '</amp-story>', $social_share . '</amp-story>', $content );
|
||||
}
|
||||
}
|
111
wp-content/plugins/web-stories/includes/Renderer/Story/Image.php
Normal file
111
wp-content/plugins/web-stories/includes/Renderer/Story/Image.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/**
|
||||
* Class Image
|
||||
*
|
||||
* @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\Renderer\Story;
|
||||
|
||||
use Google\Web_Stories\Model\Story;
|
||||
|
||||
/**
|
||||
* Class Image
|
||||
*/
|
||||
class Image {
|
||||
/**
|
||||
* Current post.
|
||||
*
|
||||
* @var Story Post object.
|
||||
*/
|
||||
protected Story $story;
|
||||
|
||||
|
||||
/**
|
||||
* Image constructor.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param Story $story Story Object.
|
||||
*/
|
||||
public function __construct( Story $story ) {
|
||||
$this->story = $story;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the block as an image.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param array<string,string|int> $args Array of Argument to render.
|
||||
* @return string Rendered block type output.
|
||||
*/
|
||||
public function render( array $args = [] ): string {
|
||||
$defaults = [
|
||||
'align' => 'none',
|
||||
'class' => 'wp-block-web-stories-embed',
|
||||
'height' => 600,
|
||||
'width' => 360,
|
||||
];
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
$align = sprintf( 'align%s', $args['align'] );
|
||||
$class = $args['class'];
|
||||
|
||||
$url = $this->story->get_url();
|
||||
$title = $this->story->get_title();
|
||||
$poster = $this->story->get_poster_portrait();
|
||||
$poster_srcset = $this->story->get_poster_srcset();
|
||||
$poster_sizes = $this->story->get_poster_sizes();
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="<?php echo esc_attr( $class ); ?> <?php echo esc_attr( $align ); ?>">
|
||||
<a href="<?php echo esc_url( $url ); ?>">
|
||||
<?php if ( ! empty( $poster ) ) { ?>
|
||||
<img
|
||||
src="<?php echo esc_url( $poster ); ?>"
|
||||
width="<?php echo esc_attr( $args['width'] ); ?>"
|
||||
height="<?php echo esc_attr( $args['height'] ); ?>"
|
||||
alt="<?php echo esc_attr( $title ); ?>"
|
||||
<?php if ( ! empty( $poster_srcset ) ) { ?>
|
||||
srcset="<?php echo esc_attr( $poster_srcset ); ?>"
|
||||
<?php } ?>
|
||||
<?php if ( ! empty( $poster_sizes ) ) { ?>
|
||||
sizes="<?php echo esc_attr( $poster_sizes ); ?>"
|
||||
<?php } ?>
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
<?php
|
||||
} else {
|
||||
echo esc_html( $title );
|
||||
}
|
||||
?>
|
||||
</a>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
return (string) ob_get_clean();
|
||||
}
|
||||
}
|
@@ -0,0 +1,221 @@
|
||||
<?php
|
||||
/**
|
||||
* Class Singleton
|
||||
*
|
||||
* @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 2023 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\Renderer\Story;
|
||||
|
||||
use Google\Web_Stories\AMP_Story_Player_Assets;
|
||||
use Google\Web_Stories\Assets;
|
||||
use Google\Web_Stories\Embed_Base;
|
||||
use Google\Web_Stories\Model\Story;
|
||||
use Google\Web_Stories\Renderer\Stories\Renderer;
|
||||
|
||||
/**
|
||||
* Class Singleton
|
||||
*/
|
||||
class Singleton {
|
||||
/**
|
||||
* Number of instances invoked. Kept it static to keep track.
|
||||
*/
|
||||
protected static int $instances = 0;
|
||||
|
||||
/**
|
||||
* Current post.
|
||||
*
|
||||
* @var Story Post object.
|
||||
*/
|
||||
protected Story $story;
|
||||
|
||||
/**
|
||||
* Assets instance.
|
||||
*
|
||||
* @var Assets Assets instance.
|
||||
*/
|
||||
private Assets $assets;
|
||||
|
||||
/**
|
||||
* Object ID for the Renderer class.
|
||||
* To enable support for multiple carousels and lightboxes
|
||||
* on the same page, we needed to identify each Renderer instance.
|
||||
*
|
||||
* This variable is used to add appropriate class to the Web Stories
|
||||
* wrapper.
|
||||
*/
|
||||
protected int $instance_id = 0;
|
||||
|
||||
/**
|
||||
* Singleton constructor.
|
||||
*
|
||||
* @since 1.30.0
|
||||
*
|
||||
* @param Story $story Story instance.
|
||||
* @param Assets $assets Assets instance.
|
||||
*/
|
||||
public function __construct( Story $story, Assets $assets ) {
|
||||
$this->assets = $assets;
|
||||
$this->story = $story;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the block output in default context.
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
*
|
||||
* @since 1.30.0
|
||||
*
|
||||
* @param array<string,string|int> $args Array of Argument to render.
|
||||
* @return string Rendered block type output.
|
||||
*/
|
||||
public function render( array $args = [] ): string {
|
||||
++self::$instances;
|
||||
$this->instance_id = self::$instances;
|
||||
|
||||
$defaults = [
|
||||
'align' => 'none',
|
||||
'class' => 'wp-block-web-stories-embed',
|
||||
'height' => 600,
|
||||
'width' => 360,
|
||||
];
|
||||
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
|
||||
$args['align'] = ! empty( $args['align'] ) ? $args['align'] : 'none';
|
||||
$align = sprintf( 'align%s', $args['align'] );
|
||||
$class = $args['class'];
|
||||
$wrapper_style = sprintf(
|
||||
'--aspect-ratio: %F; --width: %dpx; --height: %dpx',
|
||||
0 !== $args['height'] ? $args['width'] / $args['height'] : 1,
|
||||
(int) $args['width'],
|
||||
(int) $args['height']
|
||||
);
|
||||
|
||||
$this->assets->enqueue_style( AMP_Story_Player_Assets::SCRIPT_HANDLE );
|
||||
$this->assets->enqueue_script( AMP_Story_Player_Assets::SCRIPT_HANDLE );
|
||||
$this->assets->enqueue_script_asset( Renderer::LIGHTBOX_SCRIPT_HANDLE );
|
||||
$this->assets->enqueue_style_asset( Embed_Base::SCRIPT_HANDLE );
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="<?php echo esc_attr( "$class web-stories-singleton $align" ); ?>" data-id="<?php echo esc_attr( 'singleton-' . $this->instance_id ); ?>">
|
||||
<div class="wp-block-embed__wrapper" style="<?php echo esc_attr( $wrapper_style ); ?>">
|
||||
<?php $this->render_story_with_poster( $args ); ?>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
$data = [
|
||||
'controls' => [
|
||||
[
|
||||
'name' => 'close',
|
||||
'position' => 'start',
|
||||
],
|
||||
[
|
||||
'name' => 'skip-next',
|
||||
],
|
||||
],
|
||||
'behavior' => [
|
||||
'autoplay' => false,
|
||||
],
|
||||
];
|
||||
|
||||
?>
|
||||
<div class="web-stories-singleton__lightbox-wrapper <?php echo esc_attr( 'ws-lightbox-singleton-' . $this->instance_id ); ?>">
|
||||
<div class="web-stories-singleton__lightbox">
|
||||
<amp-story-player width="3.6" height="6" layout="responsive">
|
||||
<script type="application/json">
|
||||
<?php echo wp_json_encode( $data ); ?>
|
||||
</script>
|
||||
<a href="<?php echo esc_url( $this->story->get_url() ); ?>"><?php echo esc_html( $this->story->get_title() ); ?></a>
|
||||
</amp-story-player>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
return (string) ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a story with story's poster image.
|
||||
*
|
||||
* @since 1.30.0
|
||||
*
|
||||
* @param array<string,string|int> $args Array of Argument to render.
|
||||
*/
|
||||
protected function render_story_with_poster( array $args ): void {
|
||||
$poster_url = $this->story->get_poster_portrait();
|
||||
$poster_srcset = $this->story->get_poster_srcset();
|
||||
$poster_sizes = $this->story->get_poster_sizes();
|
||||
|
||||
if ( ! $poster_url ) {
|
||||
?>
|
||||
<div class="web-stories-singleton-poster">
|
||||
<div class="web-stories-singleton-poster-placeholder">
|
||||
<a href="<?php echo esc_url( $this->story->get_url() ); ?>">
|
||||
<?php echo esc_html( $this->story->get_title() ); ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<div class="web-stories-singleton-poster">
|
||||
<a href="<?php echo esc_url( $this->story->get_url() ); ?>">
|
||||
<img
|
||||
src="<?php echo esc_url( $poster_url ); ?>"
|
||||
alt="<?php echo esc_attr( $this->story->get_title() ); ?>"
|
||||
width="<?php echo absint( $args['width'] ); ?>"
|
||||
height="<?php echo absint( $args['height'] ); ?>"
|
||||
<?php if ( ! empty( $poster_srcset ) ) { ?>
|
||||
srcset="<?php echo esc_attr( $poster_srcset ); ?>"
|
||||
<?php } ?>
|
||||
<?php if ( ! empty( $poster_sizes ) ) { ?>
|
||||
sizes="<?php echo esc_attr( $poster_sizes ); ?>"
|
||||
<?php } ?>
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
>
|
||||
</a>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
$this->render_content_overlay();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the content overlay markup.
|
||||
*
|
||||
* @since 1.30.0
|
||||
*/
|
||||
protected function render_content_overlay(): void {
|
||||
?>
|
||||
<div class="web-stories-singleton-overlay">
|
||||
<div class="web-stories-singleton-overlay__title">
|
||||
<?php echo esc_html( $this->story->get_title() ); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user