Skip to content

Commit 9c853ca

Browse files
authored
Merge pull request #3659 from ampproject/add/gallery-shortcode-captions
Enable captions on Gallery shortcodes
2 parents d267863 + c7d5d6e commit 9c853ca

14 files changed

Lines changed: 698 additions & 203 deletions

bin/build-plugin-zip.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ cd "$BUILD_DIR"
4040

4141
# Run the build.
4242
status "Installing dependencies... 📦"
43-
composer install
43+
composer install -o
4444
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true npm install
4545

4646
status "Generating build... ⚙️"

composer.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,10 @@
4444
"PHP-CSS-Parser: Fix parsing CSS selectors which contain commas <https://github.com/sabberworm/PHP-CSS-Parser/pull/138>": "https://github.com/sabberworm/PHP-CSS-Parser/commit/fa139f65c5b098ae652c970b25e6eb03fc495eb4.diff"
4545
}
4646
}
47+
},
48+
"autoload": {
49+
"psr-4": {
50+
"Amp\\AmpWP\\": "src/"
51+
}
4752
}
4853
}

contributing/engineering.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ This will create an `amp.zip` in the plugin directory which you can install. The
308308
1. Create changelog draft on [Wiki page](https://github.com/ampproject/amp-wp/wiki/Release-Changelog-Draft).
309309
1. Check out the branch intended for release (`develop` for major, `x.y` for minor) and pull latest commits.
310310
1. Bump plugin versions in `amp.php` (×2: the metadata block in the header and also the `AMP__VERSION` constant).
311-
1. Do `npm install && composer selfupdate && composer install`.
311+
1. Do `npm install && composer selfupdate && composer install -o`.
312312
1. Do `npm run build` and install the `amp.zip` onto a normal WordPress install running a stable release build; do smoke test to ensure it works.
313313
1. [Draft new release](https://github.com/ampproject/amp-wp/releases/new) on GitHub targeting the required branch (`develop` for major, `x.y` for minor).
314314
1. Use the new plugin version as the tag (e.g. `1.2-beta3` or `1.2.1-RC1`)
@@ -334,7 +334,7 @@ Contributors who want to make a new release, follow these steps:
334334
1. For major release, draft blog post about the new release.
335335
1. For minor releases, make sure all merged commits in `develop` have been also merged onto release branch.
336336
1. Check out the branch intended for release (`develop` for major, `x.y` for minor) and pull latest commits.
337-
1. Do `npm install && composer selfupdate && composer install`.
337+
1. Do `npm install && composer selfupdate && composer install -o`.
338338
1. Bump plugin versions in `amp.php` (×2: the metadata block in the header and also the `AMP__VERSION` constant). Verify via `npx grunt shell:verify_matching_versions`. Ensure patch version number is supplied for major releases, so `1.2-RC1` should bump to `1.2.0`.
339339
1. Do `npm run build` and install the `amp.zip` onto a normal WordPress install running a stable release build; do smoke test to ensure it works.
340340
1. Optionally do sanity check by comparing the `build` directory with the previously-deployed plugin on WordPress.org for example: `svn export https://plugins.svn.wordpress.org/amp/trunk /tmp/amp-trunk; diff /tmp/amp-trunk/ ./build/` (instead of straight `diff`, it's best to use a GUI like `idea diff`, `phpstorm diff`, or `opendiff`).

includes/embeds/class-amp-gallery-embed.php

Lines changed: 24 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
* @package AMP
66
*/
77

8+
use Amp\AmpWP\Component\DOMElementList;
9+
use Amp\AmpWP\Component\Carousel;
10+
811
/**
912
* Class AMP_Gallery_Embed_Handler
1013
*
@@ -129,25 +132,14 @@ public function shortcode( $attr ) {
129132
'width' => $width,
130133
'height' => $height,
131134
'alt' => trim( wp_strip_all_tags( get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ) ) ), // Logic from wp_get_attachment_image().
135+
'id' => $attachment_id,
132136
];
133137
}
134138

135139
$args = [
136-
'images' => $urls,
140+
'images' => $urls,
141+
'lightbox' => ! empty( $atts['lightbox'] ),
137142
];
138-
if ( ! empty( $atts['lightbox'] ) ) {
139-
$args['lightbox'] = true;
140-
$lightbox_tag = AMP_HTML_Utils::build_tag(
141-
'amp-image-lightbox',
142-
[
143-
'id' => AMP_Base_Sanitizer::AMP_IMAGE_LIGHTBOX_ID,
144-
'layout' => 'nodisplay',
145-
'data-close-button-aria-label' => __( 'Close', 'amp' ),
146-
]
147-
);
148-
/* We need to add lightbox tag, too. @todo Could there be a better alternative for this? */
149-
return $this->render( $args ) . $lightbox_tag;
150-
}
151143

152144
return $this->render( $args );
153145
}
@@ -211,6 +203,7 @@ public function maybe_override_gallery( $html, $attributes ) {
211203
* @return string Rendered.
212204
*/
213205
public function render( $args ) {
206+
$dom = new DOMDocument();
214207
$this->did_convert_elements = true;
215208

216209
$args = wp_parse_args(
@@ -224,11 +217,7 @@ public function render( $args ) {
224217
return '';
225218
}
226219

227-
$max_aspect_ratio = 0;
228-
$carousel_width = 0;
229-
$carousel_height = 0;
230-
231-
$images = [];
220+
$images = new DOMElementList();
232221
foreach ( $args['images'] as $props ) {
233222
$image_atts = [
234223
'src' => $props['url'],
@@ -241,47 +230,38 @@ public function render( $args ) {
241230
$image_atts['srcset'] = $props['srcset'];
242231
}
243232

244-
$this_aspect_ratio = $props['width'] / $props['height'];
245-
if ( $this_aspect_ratio > $max_aspect_ratio ) {
246-
$max_aspect_ratio = $this_aspect_ratio;
247-
$carousel_width = $props['width'];
248-
$carousel_height = $props['height'];
249-
}
250-
251233
if ( ! empty( $args['lightbox'] ) ) {
252234
$image_atts['lightbox'] = '';
253-
$image_atts['on'] = 'tap:' . AMP_Img_Sanitizer::AMP_IMAGE_LIGHTBOX_ID;
254-
$image_atts['role'] = 'button';
255-
$image_atts['tabindex'] = 0;
256235
}
257-
$image = AMP_HTML_Utils::build_tag(
236+
$image = AMP_DOM_Utils::create_node(
237+
$dom,
258238
'amp-img',
259239
$image_atts
260240
);
261241

262242
if ( ! empty( $props['href'] ) ) {
263-
$image = AMP_HTML_Utils::build_tag(
243+
$previous_image = $image;
244+
$image = AMP_DOM_Utils::create_node(
245+
$dom,
264246
'a',
265247
[
266248
'href' => $props['href'],
267-
],
268-
$image
249+
]
269250
);
251+
$image->appendChild( $previous_image );
270252
}
271253

272-
$images[] = $image;
254+
$caption = isset( $props['id'] ) ? wp_get_attachment_caption( $props['id'] ) : '';
255+
$images = $images->add( $image, $caption );
273256
}
274257

275-
return AMP_HTML_Utils::build_tag(
276-
'amp-carousel',
277-
[
278-
'width' => $carousel_width,
279-
'height' => $carousel_height,
280-
'type' => 'slides',
281-
'layout' => 'responsive',
282-
],
283-
implode( PHP_EOL, $images )
284-
);
258+
$amp_carousel = new Carousel( $dom, $images );
259+
$carousel_node = $amp_carousel->get_dom_element();
260+
261+
// Prevent an error in get_content_from_dom_node() when it calls $node->parentNode->insertBefore().
262+
$dom->appendChild( $carousel_node );
263+
264+
return AMP_DOM_Utils::get_content_from_dom_node( $dom, $carousel_node );
285265
}
286266

287267
/**

includes/sanitizers/class-amp-gallery-block-sanitizer.php

Lines changed: 12 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,16 @@
55
* @package AMP
66
*/
77

8+
use Amp\AmpWP\Component\DOMElementList;
9+
use Amp\AmpWP\Component\Carousel;
10+
811
/**
912
* Class AMP_Gallery_Block_Sanitizer
1013
*
1114
* Modifies gallery block to match the block's AMP-specific configuration.
1215
*/
1316
class AMP_Gallery_Block_Sanitizer extends AMP_Base_Sanitizer {
1417

15-
/**
16-
* Value used for width of amp-carousel.
17-
*
18-
* @since 1.0
19-
*
20-
* @const int
21-
*/
22-
const FALLBACK_WIDTH = 600;
23-
24-
/**
25-
* Value used for height of amp-carousel.
26-
*
27-
* @since 1.0
28-
*
29-
* @const int
30-
*/
31-
const FALLBACK_HEIGHT = 480;
32-
3318
/**
3419
* Tag.
3520
*
@@ -93,12 +78,6 @@ public function sanitize() {
9378
}
9479

9580
foreach ( $nodes as $node ) {
96-
/**
97-
* Element
98-
*
99-
* @var DOMElement $node
100-
*/
101-
10281
// In WordPress 5.3, the Gallery block's <ul> is wrapped in a <figure class="wp-block-gallery">, so look for that node also.
10382
$gallery_node = isset( $node->parentNode ) && AMP_DOM_Utils::has_class( $node->parentNode, self::$class ) ? $node->parentNode : $node;
10483
$attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $gallery_node );
@@ -128,128 +107,33 @@ public function sanitize() {
128107
continue;
129108
}
130109

131-
$images = [];
110+
$images = new DOMElementList();
132111

133112
// If it's not AMP lightbox, look for links first.
134113
if ( ! $is_amp_lightbox ) {
135114
foreach ( $node->getElementsByTagName( 'a' ) as $element ) {
136-
$images[] = $element;
115+
$images = $images->add( $element, $this->possibly_get_caption_text( $element ) );
137116
}
138117
}
139118

140119
// If not linking to anything then look for <amp-img>.
141-
if ( empty( $images ) ) {
120+
if ( 0 === count( $images ) ) {
142121
foreach ( $node->getElementsByTagName( 'amp-img' ) as $element ) {
143-
$images[] = $element;
122+
$images = $images->add( $element, $this->possibly_get_caption_text( $element ) );
144123
}
145124
}
146125

147126
// Skip if no images found.
148-
if ( empty( $images ) ) {
127+
if ( 0 === count( $images ) ) {
149128
continue;
150129
}
151130

152-
list( $width, $height ) = $this->get_carousel_dimensions( $node );
153-
154-
$amp_carousel = AMP_DOM_Utils::create_node(
155-
$this->dom,
156-
'amp-carousel',
157-
[
158-
'width' => $width,
159-
'height' => $height,
160-
'type' => 'slides',
161-
'layout' => 'responsive',
162-
]
163-
);
164-
165-
foreach ( $images as $image ) {
166-
$slide = AMP_DOM_Utils::create_node(
167-
$this->dom,
168-
'div',
169-
[ 'class' => 'slide' ]
170-
);
171-
172-
// Ensure the image fills the entire <amp-carousel>, so the possible caption looks right.
173-
if ( 'amp-img' === $image->tagName ) {
174-
$image->setAttribute( 'layout', 'fill' );
175-
$image->setAttribute( 'object-fit', 'cover' );
176-
} elseif ( isset( $image->firstChild->tagName ) && 'amp-img' === $image->firstChild->tagName ) {
177-
// If the <amp-img> is wrapped in an <a>.
178-
$image->firstChild->setAttribute( 'layout', 'fill' );
179-
$image->firstChild->setAttribute( 'object-fit', 'cover' );
180-
}
181-
182-
$possible_caption_text = $this->possibly_get_caption_text( $image );
183-
$slide->appendChild( $image );
184-
185-
// Wrap the caption in a <div> and <span>, and append it to the slide.
186-
if ( $possible_caption_text ) {
187-
$caption_wrapper = AMP_DOM_Utils::create_node(
188-
$this->dom,
189-
'div',
190-
[ 'class' => 'amp-wp-gallery-caption' ]
191-
);
192-
$caption_span = AMP_DOM_Utils::create_node( $this->dom, 'span', [] );
193-
$text_node = $this->dom->createTextNode( $possible_caption_text );
194-
195-
$caption_span->appendChild( $text_node );
196-
$caption_wrapper->appendChild( $caption_span );
197-
$slide->appendChild( $caption_wrapper );
198-
}
199-
200-
$amp_carousel->appendChild( $slide );
201-
}
202-
203-
$gallery_node->parentNode->replaceChild( $amp_carousel, $gallery_node );
131+
$amp_carousel = new Carousel( $this->dom, $images );
132+
$gallery_node->parentNode->replaceChild( $amp_carousel->get_dom_element(), $gallery_node );
204133
}
205134
$this->did_convert_elements = true;
206135
}
207136

208-
/**
209-
* Get carousel height by containing images.
210-
*
211-
* @param DOMElement $element The UL element.
212-
* @return array {
213-
* Dimensions.
214-
*
215-
* @type int $width Width.
216-
* @type int $height Height.
217-
* }
218-
*/
219-
protected function get_carousel_dimensions( $element ) {
220-
/**
221-
* Elements.
222-
*
223-
* @var DOMElement $image
224-
*/
225-
$images = $element->getElementsByTagName( 'amp-img' );
226-
$num_images = $images->length;
227-
228-
$max_aspect_ratio = 0;
229-
$carousel_width = 0;
230-
$carousel_height = 0;
231-
232-
if ( 0 === $num_images ) {
233-
return [ self::FALLBACK_WIDTH, self::FALLBACK_HEIGHT ];
234-
}
235-
foreach ( $images as $image ) {
236-
if ( ! is_numeric( $image->getAttribute( 'width' ) ) || ! is_numeric( $image->getAttribute( 'height' ) ) ) {
237-
continue;
238-
}
239-
$width = (float) $image->getAttribute( 'width' );
240-
$height = (float) $image->getAttribute( 'height' );
241-
242-
$this_aspect_ratio = $width / $height;
243-
if ( $this_aspect_ratio > $max_aspect_ratio ) {
244-
$max_aspect_ratio = $this_aspect_ratio;
245-
$carousel_width = $width;
246-
$carousel_height = $height;
247-
}
248-
}
249-
250-
return [ $carousel_width, $carousel_height ];
251-
}
252-
253137
/**
254138
* Set lightbox related attributes to <amp-img> within gallery.
255139
*
@@ -280,7 +164,7 @@ protected function add_lightbox_attributes_to_image_nodes( $element ) {
280164
* Gets the caption of an image, if it exists.
281165
*
282166
* @param DOMElement $element The element for which to search for a caption.
283-
* @return string|null The caption for the image, or null.
167+
* @return string The caption for the image, or ''.
284168
*/
285169
public function possibly_get_caption_text( $element ) {
286170
$caption_tag = 'figcaption';
@@ -293,6 +177,6 @@ public function possibly_get_caption_text( $element ) {
293177
return $element->parentNode->nextSibling->textContent;
294178
}
295179

296-
return null;
180+
return '';
297181
}
298182
}

phpcs.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
<rule ref="WordPress.Files.FileName.InvalidClassFileName">
2424
<exclude-pattern>tests/*</exclude-pattern>
25+
<exclude-pattern>src/*</exclude-pattern>
2526
<exclude-pattern>includes/admin/class-amp-customizer.php</exclude-pattern>
2627
<exclude-pattern>includes/embeds/class-amp-dailymotion-embed.php</exclude-pattern>
2728
<exclude-pattern>includes/embeds/class-amp-facebook-embed.php</exclude-pattern>
@@ -46,6 +47,7 @@
4647
<exclude-pattern>includes/actions/class-amp-paired-post-actions.php</exclude-pattern>
4748
</rule>
4849
<rule ref="WordPress.Files.FileName.NotHyphenatedLowercase">
50+
<exclude-pattern>src/*</exclude-pattern>
4951
<exclude-pattern>includes/templates/single-amp_story.php</exclude-pattern>
5052
</rule>
5153
<rule ref="WordPress.NamingConventions.ValidVariableName">
@@ -79,6 +81,11 @@
7981
</properties>
8082
</rule>
8183

84+
<!-- Enforce PascalCase file names in src/ only. -->
85+
<rule ref="Squiz.Classes.ClassFileName">
86+
<include-pattern>src/*</include-pattern>
87+
</rule>
88+
8289
<!-- Include sniffs for PHP cross-version compatibility. -->
8390
<config name="testVersion" value="5.4-"/>
8491
<rule ref="PHPCompatibilityWP">

0 commit comments

Comments
 (0)