Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slideshow Block: AMP Compatibility #13009

Merged
merged 25 commits into from
Oct 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7798351
Slideshow block, AMP compatibility, initial commit.
jeffersonrabb Jul 8, 2019
4d36cc0
Background image data URIs don't seem to work in AMP unless spaces ar…
jeffersonrabb Jul 9, 2019
399667b
Aria labels for next and previous buttons.
jeffersonrabb Jul 9, 2019
e9afb43
Slideshow pagination control in AMP.
jeffersonrabb Jul 9, 2019
a166b78
Safer global for Slideshow ID.
jeffersonrabb Jul 9, 2019
2fe9c56
Attribute and caption escaping.
jeffersonrabb Jul 9, 2019
3b3eb3c
Extract Slideshow AMP rendering to a separate function.
jeffersonrabb Jul 9, 2019
5d52ab4
Use wp_get_attachment_image() and let image sanitizer manage. Use 'la…
jeffersonrabb Jul 9, 2019
ba5e923
Additional attribute escaping.
jeffersonrabb Jul 9, 2019
9d02095
Bug fix: remove autoplay override used for testing.
jeffersonrabb Jul 9, 2019
188f089
Unnecessary style removal.
jeffersonrabb Jul 10, 2019
cabea0d
Autoplay pause/play button implementation for AMP.
jeffersonrabb Sep 29, 2019
3cfa901
Set AMP Carousel dimensions based on the aspect ratio of the first im…
jeffersonrabb Sep 29, 2019
6e225a7
Use static variable instead of Global for Slideshow block unique ID.
jeffersonrabb Sep 29, 2019
63815f2
Some refactoring to reduce size of individual functions.
jeffersonrabb Sep 29, 2019
3e8b991
Further refactoring to reduce function length.
jeffersonrabb Sep 29, 2019
c7964a8
Remove negative top margin for next/prev buttons in AMP requests.
jeffersonrabb Sep 29, 2019
64107c7
Selected state for Slideshow block bullets in AMP requests.
jeffersonrabb Sep 30, 2019
adeb84e
Remove short array syntax.
jeffersonrabb Sep 30, 2019
9f5952f
Bug fix: incorrect element ID used in autoplay pause/play buttons.
jeffersonrabb Sep 30, 2019
e4c02de
Improvements to formatted string statements.
jeffersonrabb Sep 30, 2019
80e89e1
Escaping improvements for Slideshow block bullets.
jeffersonrabb Sep 30, 2019
4cd6190
Check for existence of image dimensions, use 800x600 as fallback.
jeffersonrabb Sep 30, 2019
15ab418
Use Jetpack_Gutenberg's block_classes to generate block class list.
jeffersonrabb Sep 30, 2019
9fcd5eb
Improved approach to translating bullet ARIA labels.
jeffersonrabb Oct 1, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions extensions/blocks/slideshow/slideshow.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,166 @@
*/
function jetpack_slideshow_block_load_assets( $attr, $content ) {
Jetpack_Gutenberg::load_assets_as_required( 'slideshow' );
if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) {
return jetpack_slideshow_block_render_amp( $attr );
}
return $content;
}

/**
* Render slideshow block for AMP
*
* @param array $attr Array containing the slideshow block attributes.
*
* @return string
*/
function jetpack_slideshow_block_render_amp( $attr ) {
static $wp_block_jetpack_slideshow_id = 0;
$wp_block_jetpack_slideshow_id++;

$ids = empty( $attr['ids'] ) ? array() : $attr['ids'];
$autoplay = empty( $attr['autoplay'] ) ? false : $attr['autoplay'];

$extras = array(
'wp-amp-block',
$autoplay ? 'wp-block-jetpack-slideshow__autoplay' : null,
$autoplay ? 'wp-block-jetpack-slideshow__autoplay-playing' : null,
);
$classes = Jetpack_Gutenberg::block_classes( 'slideshow', $attr, $extras );

return sprintf(
'<div class="%1$s" id="wp-block-jetpack-slideshow__%2$d"><div class="wp-block-jetpack-slideshow_container swiper-container">%3$s%4$s%5$s</div></div>',
esc_attr( $classes ),
absint( $wp_block_jetpack_slideshow_id ),
jetpack_slideshow_block_amp_carousel( $attr, $wp_block_jetpack_slideshow_id ),
$autoplay ? jetpack_slideshow_block_autoplay_ui( $wp_block_jetpack_slideshow_id ) : '',
jetpack_slideshow_block_bullets( $ids, $wp_block_jetpack_slideshow_id )
);
}

/**
* Generate amp-carousel markup
*
* @param array $attr Array of block attributes.
* @param int $block_ordinal The ordinal number of the block, used in unique ID.
*
* @return string amp-carousel markup.
*/
function jetpack_slideshow_block_amp_carousel( $attr, $block_ordinal ) {
$ids = empty( $attr['ids'] ) ? array() : $attr['ids'];
$first_image = wp_get_attachment_metadata( $ids[0] );
$delay = empty( $attr['delay'] ) ? 3 : absint( $attr['delay'] );
$autoplay = empty( $attr['autoplay'] ) ? false : $attr['autoplay'];
$width = empty( $first_image['width'] ) ? 800 : $first_image['width'];
$height = empty( $first_image['height'] ) ? 600 : $first_image['height'];
return sprintf(
'<amp-carousel width="%1$d" height="%2$d" layout="responsive" type="slides" data-next-button-aria-label="%3$s" data-prev-button-aria-label="%4$s" controls loop %5$s id="wp-block-jetpack-slideshow__amp-carousel__%6$s" on="slideChange:wp-block-jetpack-slideshow__amp-pagination__%6$s.toggle(index=event.index, value=true)">%7$s</amp-carousel>',
esc_attr( $width ),
esc_attr( $height ),
esc_attr__( 'Next Slide', 'jetpack' ),
esc_attr__( 'Previous Slide', 'jetpack' ),
$autoplay ? 'autoplay delay=' . esc_attr( $delay * 1000 ) : '',
absint( $block_ordinal ),
implode( '', jetpack_slideshow_block_slides( $ids, $width, $height ) )
);
}

/**
* Generate array of slides markup
*
* @param array $ids Array of image ids.
* @param int $width Width of the container.
* @param int $height Height of the container.
*
* @return array Array of slides markup.
*/
function jetpack_slideshow_block_slides( $ids = array(), $width = 400, $height = 300 ) {
return array_map(
function( $id ) use ( $width, $height ) {
$caption = wp_get_attachment_caption( $id );
$figcaption = $caption ? sprintf(
'<figcaption class="wp-block-jetpack-slideshow_caption gallery-caption">%s</figcaption>',
wp_kses_post( $caption )
) : '';
$image = wp_get_attachment_image(
$id,
array( $width, $height ),
false,
array(
'class' => 'wp-block-jetpack-slideshow_image',
'object-fit' => 'contain',
)
);
return sprintf(
'<div class="wp-block-jetpack-slideshow_slide"><figure>%s%s</figure></div>',
$image,
$figcaption
);
},
$ids
);
}

/**
* Generate array of bullets markup
*
* @param array $ids Array of image ids.
* @param int $block_ordinal The ordinal number of the block, used in unique ID.
*
* @return array Array of bullets markup.
*/
function jetpack_slideshow_block_bullets( $ids = array(), $block_ordinal = 0 ) {
$buttons = array_map(
function( $index ) {
$aria_label = sprintf(
/* translators: %d: Slide number. */
__( 'Go to slide %d', 'jetpack' ),
absint( $index + 1 )
);
return sprintf(
'<button option="%d" class="swiper-pagination-bullet" tabindex="0" role="button" aria-label="%s" %s></button>',
absint( $index ),
esc_attr( $aria_label ),
0 === $index ? 'selected' : ''
);
},
array_keys( $ids )
);

return sprintf(
'<amp-selector id="wp-block-jetpack-slideshow__amp-pagination__%1$d" class="wp-block-jetpack-slideshow_pagination swiper-pagination swiper-pagination-bullets amp-pagination" on="select:wp-block-jetpack-slideshow__amp-carousel__%1$d.goToSlide(index=event.targetOption)" layout="container">%2$s</amp-selector>',
absint( $block_ordinal ),
implode( '', $buttons )
);
}

/**
* Generate autoplay play/pause UI.
*
* @param int $block_ordinal The ordinal number of the block, used in unique ID.
*
* @return string Autoplay UI markup.
*/
function jetpack_slideshow_block_autoplay_ui( $block_ordinal = 0 ) {
$block_id = sprintf(
'wp-block-jetpack-slideshow__%d',
absint( $block_ordinal )
);
$amp_carousel_id = sprintf(
'wp-block-jetpack-slideshow__amp-carousel__%d',
absint( $block_ordinal )
);
$autoplay_pause = sprintf(
'<a aria-label="%s" class="wp-block-jetpack-slideshow_button-pause" role="button" on="tap:%s.toggleAutoplay(toggleOn=false),%s.toggleClass(class=wp-block-jetpack-slideshow__autoplay-playing,force=false)"></a>',
esc_attr__( 'Pause Slideshow', 'jetpack' ),
esc_attr( $amp_carousel_id ),
esc_attr( $block_id )
);
$autoplay_play = sprintf(
'<a aria-label="%s" class="wp-block-jetpack-slideshow_button-play" role="button" on="tap:%s.toggleAutoplay(toggleOn=true),%s.toggleClass(class=wp-block-jetpack-slideshow__autoplay-playing,force=true)"></a>',
esc_attr__( 'Play Slideshow', 'jetpack' ),
esc_attr( $amp_carousel_id ),
esc_attr( $block_id )
);
return $autoplay_pause . $autoplay_play;
}
51 changes: 44 additions & 7 deletions extensions/blocks/slideshow/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,21 @@
outline: 0;
}

&.wp-amp-block {
& > .wp-block-jetpack-slideshow_container {
opacity: 1;
}
}
&.wp-amp-block.wp-block-jetpack-slideshow__autoplay {
&.wp-block-jetpack-slideshow__autoplay-playing .wp-block-jetpack-slideshow_button-pause,
.wp-block-jetpack-slideshow_button-play {
display: block;
}
&.wp-block-jetpack-slideshow__autoplay-playing .wp-block-jetpack-slideshow_button-play {
display: none;
}
}

.wp-block-jetpack-slideshow_container {
width: 100%;
overflow: hidden;
Expand Down Expand Up @@ -59,7 +74,9 @@

.wp-block-jetpack-slideshow_button-prev,
.wp-block-jetpack-slideshow_button-next,
.wp-block-jetpack-slideshow_button-pause {
.wp-block-jetpack-slideshow_button-pause,
.wp-block-jetpack-slideshow_button-play,
.amp-carousel-button {
background-color: rgba( 0, 0, 0, 0.5 );
background-position: center;
background-repeat: no-repeat;
Expand All @@ -84,6 +101,10 @@
}
}

.amp-carousel-button {
margin: 0;
}

.wp-block-jetpack-slideshow_button-prev,
.wp-block-jetpack-slideshow_button-next {
display: none;
Expand All @@ -92,19 +113,22 @@
&.swiper-container-rtl .swiper-button-prev.swiper-button-white,
&.swiper-container-rtl .wp-block-jetpack-slideshow_button-prev,
.swiper-button-next.swiper-button-white,
.wp-block-jetpack-slideshow_button-next {
background-image: url( "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M5.88 4.12L13.76 12l-7.88 7.88L8 22l10-10L8 2z' fill='white'/%3E%3Cpath fill='none' d='M0 0h24v24H0z'/%3E%3C/svg%3E" );
.wp-block-jetpack-slideshow_button-next,
.amp-carousel-button-next {
background-image: url( "data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M5.88%204.12L13.76%2012l-7.88%207.88L8%2022l10-10L8%202z'%20fill='white'/%3E%3Cpath%20fill='none'%20d='M0 0h24v24H0z'/%3E%3C/svg%3E" );
}

&.swiper-container-rtl .swiper-button-next.swiper-button-white,
&.swiper-container-rtl .wp-block-jetpack-slideshow_button-next,
.swiper-button-prev.swiper-button-white,
.wp-block-jetpack-slideshow_button-prev {
background-image: url( "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M18 4.12L10.12 12 18 19.88 15.88 22l-10-10 10-10z' fill='white'/%3E%3Cpath fill='none' d='M0 0h24v24H0z'/%3E%3C/svg%3E" );
.wp-block-jetpack-slideshow_button-prev,
.amp-carousel-button-prev {
background-image: url( "data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M18%204.12L10.12%2012%2018%2019.88%2015.88%2022l-10-10%2010-10z'%20fill='white'/%3E%3Cpath%20fill='none'%20d='M0 0h24v24H0z'/%3E%3C/svg%3E" );
}

.wp-block-jetpack-slideshow_button-play,
.wp-block-jetpack-slideshow_button-pause {
background-image: url( "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M6 19h4V5H6v14zm8-14v14h4V5h-4z' fill='white'/%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3C/svg%3E" );
background-image: url( "data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M6%2019h4V5H6v14zm8-14v14h4V5h-4z'%20fill='white'/%3E%3Cpath%20d='M0%200h24v24H0z'%20fill='none'/%3E%3C/svg%3E" );
display: none;
margin-top: 0;
position: absolute;
Expand All @@ -113,8 +137,9 @@
z-index: 1;
}

.wp-block-jetpack-slideshow_button-play,
.wp-block-jetpack-slideshow_autoplay-paused .wp-block-jetpack-slideshow_button-pause {
background-image: url( "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M8 5v14l11-7z' fill='white'/%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3C/svg%3E" );
background-image: url( "data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M8%205v14l11-7z'%20fill='white'/%3E%3Cpath%20d='M0 0h24v24H0z'%20fill='none'/%3E%3C/svg%3E" );
}

&[data-autoplay='true'] .wp-block-jetpack-slideshow_button-pause {
Expand Down Expand Up @@ -171,6 +196,7 @@
}
}

.swiper-pagination-bullet[selected],
.swiper-pagination-bullet-active {
background-color: currentColor;
opacity: 1;
Expand All @@ -179,6 +205,17 @@
}
}

.wp-block-jetpack-slideshow_pagination.amp-pagination {
text-align: center;
.swiper-pagination-bullet {
margin: 0 4px;
border-radius: 100%;
display: inline-block;
padding: 0;
border: 0;
}
}

@media ( min-width: $break-small ) {
.wp-block-jetpack-slideshow {
.wp-block-jetpack-slideshow_button-prev,
Expand Down