Skip to content

Commit eb2fdf3

Browse files
authored
Shortcodes: fix [archiveorg] query parameter handling (#49195)
1 parent 8ee5aa3 commit eb2fdf3

3 files changed

Lines changed: 107 additions & 8 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Significance: patch
2+
Type: bugfix
3+
4+
Shortcodes: fix [archiveorg] so query parameters such as playlist, autoplay, and poster produce valid Archive.org embed URLs.

projects/plugins/jetpack/modules/shortcodes/archiveorg.php

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ function jetpack_archiveorg_shortcode( $atts ) {
6060
'height' => 480,
6161
'autoplay' => 0,
6262
'poster' => '',
63+
'playlist' => 0,
6364
),
6465
$atts
6566
);
@@ -70,6 +71,23 @@ function jetpack_archiveorg_shortcode( $atts ) {
7071

7172
$id = $atts['id'];
7273

74+
// Allow extra query parameters to be baked into the identifier, e.g. "myitem&playlist=1" or "myitem?playlist=1".
75+
// In some environments a the_content filter encodes "&" to "&" before do_shortcode runs, so the
76+
// parser receives "myitem&playlist=1" — normalize that back before splitting. The sibling function
77+
// jetpack_archiveorg_embed_to_shortcode() splits on "&" for the same reason.
78+
$id = str_replace( '&', '&', $id );
79+
$id_extra_args = array();
80+
if ( preg_match( '/^([^?&]*)[?&](.*)$/', $id, $id_match ) ) {
81+
$id = $id_match[1];
82+
wp_parse_str( $id_match[2], $id_extra_args );
83+
}
84+
85+
// Re-check after the split — an identifier that's only a query string (e.g. "?playlist=1") leaves $id empty
86+
// and would otherwise produce an item-less embed URL.
87+
if ( '' === $id ) {
88+
return '<!-- error: missing archive.org ID -->';
89+
}
90+
7391
if ( ! $atts['width'] ) {
7492
$width = absint( $content_width );
7593
} else {
@@ -82,22 +100,29 @@ function jetpack_archiveorg_shortcode( $atts ) {
82100
$height = (int) $atts['height'];
83101
}
84102

103+
$query_args = array();
85104
if ( $atts['autoplay'] ) {
86-
$autoplay = '&autoplay=1';
87-
} else {
88-
$autoplay = '';
105+
$query_args['autoplay'] = 1;
89106
}
90-
91107
if ( $atts['poster'] ) {
92-
$poster = '&poster=' . $atts['poster'];
93-
} else {
94-
$poster = '';
108+
$query_args['poster'] = $atts['poster'];
109+
}
110+
if ( $atts['playlist'] ) {
111+
$query_args['playlist'] = 1;
112+
}
113+
114+
// Explicit shortcode attributes take precedence over query parameters baked into the identifier.
115+
$query_args = array_merge( $id_extra_args, $query_args );
116+
117+
$url = 'https://archive.org/embed/' . $id;
118+
if ( ! empty( $query_args ) ) {
119+
$url = add_query_arg( $query_args, $url );
95120
}
96121

97122
return sprintf(
98123
'<div class="embed-archiveorg" style="text-align:center;"><iframe title="%s" src="%s" width="%s" height="%s" style="border:0;" webkitallowfullscreen="true" mozallowfullscreen="true" allowfullscreen></iframe></div>',
99124
esc_attr__( 'Archive.org', 'jetpack' ),
100-
esc_url( "https://archive.org/embed/{$id}{$autoplay}{$poster}" ),
125+
esc_url( $url ),
101126
esc_attr( $width ),
102127
esc_attr( $height )
103128
);

projects/plugins/jetpack/tests/php/modules/shortcodes/Jetpack_Shortcodes_ArchiveOrg_Test.php

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,76 @@ public function test_shortcode_single_element() {
4646
$this->assertStringContainsString( "iframe title=\"$title\" src=\"https://archive.org/embed/$id\" width=\"600\" height=\"300\"", $shortcode_content );
4747
}
4848

49+
/**
50+
* Verify that autoplay and poster attributes render as a proper query string.
51+
*/
52+
public function test_shortcode_autoplay_and_poster() {
53+
$content = "[archiveorg id='Wonderfu1958' autoplay=1 poster='http://archive.org/img.png']";
54+
$shortcode_content = do_shortcode( $content );
55+
$this->assertStringContainsString( 'src="https://archive.org/embed/Wonderfu1958?autoplay=1&#038;poster=http://archive.org/img.png"', $shortcode_content );
56+
}
57+
58+
/**
59+
* Verify that the playlist attribute renders as a proper query parameter.
60+
*/
61+
public function test_shortcode_playlist_attribute() {
62+
$content = "[archiveorg id='sentidodelobjeto' playlist=1]";
63+
$shortcode_content = do_shortcode( $content );
64+
$this->assertStringContainsString( 'src="https://archive.org/embed/sentidodelobjeto?playlist=1"', $shortcode_content );
65+
}
66+
67+
/**
68+
* Verify that query parameters baked into the identifier with "&" are converted to a proper query string.
69+
*/
70+
public function test_shortcode_query_string_in_id_with_ampersand() {
71+
$shortcode_content = do_shortcode( '[archiveorg sentidodelobjeto&playlist=1 width=640 height=300]' );
72+
$this->assertStringContainsString( 'src="https://archive.org/embed/sentidodelobjeto?playlist=1"', $shortcode_content );
73+
}
74+
75+
/**
76+
* Verify that query parameters baked into the identifier with "?" pass through correctly.
77+
*/
78+
public function test_shortcode_query_string_in_id_with_question_mark() {
79+
$shortcode_content = do_shortcode( '[archiveorg sentidodelobjeto?playlist=1 width=640 height=300]' );
80+
$this->assertStringContainsString( 'src="https://archive.org/embed/sentidodelobjeto?playlist=1"', $shortcode_content );
81+
}
82+
83+
/**
84+
* Verify that an HTML-encoded "&amp;" baked into the identifier is normalized before splitting,
85+
* matching what reaches do_shortcode in environments where the_content encodes ampersands first.
86+
*/
87+
public function test_shortcode_query_string_in_id_with_html_encoded_ampersand() {
88+
$shortcode_content = do_shortcode( '[archiveorg sentidodelobjeto&amp;playlist=1 width=640 height=300]' );
89+
$this->assertStringContainsString( 'src="https://archive.org/embed/sentidodelobjeto?playlist=1"', $shortcode_content );
90+
}
91+
92+
/**
93+
* Verify that an identifier consisting of only a query string returns the missing-ID error
94+
* rather than producing an item-less embed URL.
95+
*/
96+
public function test_shortcode_returns_error_when_id_is_only_a_query_string() {
97+
$this->assertEquals( '<!-- error: missing archive.org ID -->', do_shortcode( '[archiveorg ?playlist=1]' ) );
98+
$this->assertEquals( '<!-- error: missing archive.org ID -->', do_shortcode( '[archiveorg &playlist=1]' ) );
99+
}
100+
101+
/**
102+
* Verify that a query parameter supplied both via the identifier and as a shortcode attribute
103+
* appears only once in the rendered URL.
104+
*/
105+
public function test_shortcode_dedupes_duplicate_query_params_from_id_and_atts() {
106+
$shortcode_content = do_shortcode( '[archiveorg myitem&playlist=1 playlist=1]' );
107+
$this->assertStringContainsString( 'src="https://archive.org/embed/myitem?playlist=1"', $shortcode_content );
108+
$this->assertSame( 1, substr_count( $shortcode_content, 'playlist=1' ) );
109+
}
110+
111+
/**
112+
* Verify that a "#" fragment in the identifier stays after the query string rather than swallowing it.
113+
*/
114+
public function test_shortcode_places_query_before_fragment_in_id() {
115+
$shortcode_content = do_shortcode( '[archiveorg myitem#frag&playlist=1]' );
116+
$this->assertStringContainsString( 'src="https://archive.org/embed/myitem?playlist=1#frag"', $shortcode_content );
117+
}
118+
49119
/**
50120
* Verify that rendering the archiveorg-book shortcode returns an ArchiveOrg book.
51121
*

0 commit comments

Comments
 (0)