Skip to content

Commit e649dab

Browse files
committed
Improve AMP implementation of infinite scroll
1 parent c663b90 commit e649dab

File tree

4 files changed

+158
-224
lines changed

4 files changed

+158
-224
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
/**
3+
* Infinite scroll sanitizer for AMP pages.
4+
*
5+
* @package Jetpack
6+
* @since 9.1.0
7+
*/
8+
9+
/**
10+
* This class makes the necessary changes to an AMP page when making an amp-next-page request.
11+
*/
12+
final class Jetpack_AMP_Infinite_Scroll_Sanitizer extends AMP_Base_Sanitizer {
13+
14+
/**
15+
* @var array {
16+
* @type string $footer_xpaths
17+
* @type string[] $next_page_hide_xpaths
18+
* }
19+
*/
20+
protected $args;
21+
22+
/**
23+
* XPath.
24+
*
25+
* @var DOMXPath
26+
*/
27+
private $xpath;
28+
29+
/**
30+
* Sanitize.
31+
*/
32+
public function sanitize() {
33+
$this->xpath = new DOMXPath( $this->dom );
34+
35+
// Abort if there is no amp-next-page in the document.
36+
$next_page_element = $this->xpath->query( '//amp-next-page[ @class = "jetpack-infinite-scroll" ]' )->item( 0 );
37+
if ( ! $next_page_element instanceof DOMElement ) {
38+
return;
39+
}
40+
41+
// Abort amp-next-page if no footer element discovered.
42+
$footer_elements = array();
43+
if ( ! empty( $this->args['footer_xpaths'] ) ) {
44+
foreach ( $this->args['footer_xpaths'] as $footer_xpath ) {
45+
$footer_elements = array_merge( $footer_elements, iterator_to_array( $this->xpath->query( $footer_xpath ) ) );
46+
}
47+
}
48+
if ( empty( $footer_elements ) ) {
49+
return;
50+
}
51+
52+
// Abort if the amp-next-page lacks a div[footer] element.
53+
$footer_container = $this->xpath->query( './div[ @footer ]', $next_page_element )->item( 0 );
54+
if ( ! $footer_container instanceof DOMElement ) {
55+
return;
56+
}
57+
58+
// Make sure amp-next-page is at the end of the body.
59+
$body = $this->dom->getElementsByTagName( 'body' )->item( 0 );
60+
$next_page_element->parentNode->removeChild( $next_page_element );
61+
$body->appendChild( $next_page_element );
62+
63+
// Move the footer to be inside of <amp-next-page>.
64+
foreach ( $footer_elements as $footer_element ) {
65+
$footer_element->parentNode->removeChild( $footer_element );
66+
$footer_container->appendChild( $footer_element );
67+
}
68+
69+
$this->hide_next_page_elements();
70+
}
71+
72+
/**
73+
* Hide next page elements.
74+
*/
75+
private function hide_next_page_elements() {
76+
if ( isset( $this->args['next_page_hide_xpaths'] ) && is_array( $this->args['next_page_hide_xpaths'] ) ) {
77+
$xpaths = $this->args['next_page_hide_xpaths'];
78+
} else {
79+
$xpaths = array();
80+
}
81+
$xpaths[] = '//div[ @id = "wpadminbar" ]';
82+
83+
foreach ( $xpaths as $next_page_hide_xpath ) {
84+
/** @var DOMElement $element */
85+
foreach ( $this->xpath->query( $next_page_hide_xpath ) as $element ) {
86+
$element->setAttribute( 'next-page-hide', '' ); // @todo Also hidden?
87+
}
88+
}
89+
}
90+
}

modules/infinite-scroll/infinity.php

+25-117
Original file line numberDiff line numberDiff line change
@@ -1748,136 +1748,46 @@ private function is_exempted_amp_page() {
17481748
* @return void
17491749
*/
17501750
public function amp_load_hooks() {
1751-
if ( $this->is_exempted_amp_page() ) {
1751+
if (
1752+
! class_exists( 'Jetpack_AMP_Support' )
1753+
||
1754+
! Jetpack_AMP_Support::is_amp_request()
1755+
||
1756+
$this->is_exempted_amp_page()
1757+
) {
1758+
// @todo Should also return if theme is not twentynineteen or twentytwenty?
17521759
return;
17531760
}
17541761

1755-
if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) {
1756-
$template = self::get_settings()->render;
1757-
1758-
add_filter( 'jetpack_infinite_scroll_load_scripts_and_styles', '__return_false' );
1759-
1760-
add_action( 'template_redirect', array( $this, 'amp_start_output_buffering' ), 0 );
1761-
add_action( 'shutdown', array( $this, 'amp_output_buffer' ), 1 );
1762-
1763-
if ( is_callable( "amp_{$template}_hooks" ) ) {
1764-
call_user_func( "amp_{$template}_hooks" );
1765-
}
1766-
1767-
// Warms up the amp next page markup.
1768-
// This should be done outside the output buffering callback started in the template_redirect.
1769-
$this->amp_get_footer_template();
1770-
}
1771-
}
1772-
1773-
/**
1774-
* Start the AMP output buffering.
1775-
*
1776-
* @return void
1777-
*/
1778-
public function amp_start_output_buffering() {
1779-
ob_start( array( $this, 'amp_finish_output_buffering' ) );
1780-
}
1762+
add_action( 'wp_footer', array( $this, 'render_amp_next_page' ) );
17811763

1782-
/**
1783-
* Flush the AMP output buffer.
1784-
*
1785-
* @return void
1786-
*/
1787-
public function amp_output_buffer() {
1788-
if ( ob_get_contents() ) {
1789-
ob_end_flush();
1790-
}
1791-
}
1764+
add_filter( 'jetpack_infinite_scroll_load_scripts_and_styles', '__return_false' );
17921765

1793-
/**
1794-
* Filter the AMP output buffer contents.
1795-
*
1796-
* @param string $buffer Contents of the output buffer.
1797-
*
1798-
* @return string|false
1799-
*/
1800-
public function amp_finish_output_buffering( $buffer ) {
1801-
// Hide WordPress admin bar on next page load.
1802-
$buffer = preg_replace(
1803-
'/id="wpadminbar"/',
1804-
'$0 next-page-hide',
1805-
$buffer
1766+
require_once __DIR__ . '/class-jetpack-amp-infinite-scroll-sanitizer.php';
1767+
add_filter(
1768+
'amp_content_sanitizers',
1769+
function ( $sanitizers ) {
1770+
$sanitizers['Jetpack_AMP_Infinite_Scroll_Sanitizer'] = array();
1771+
return $sanitizers;
1772+
},
1773+
0
18061774
);
18071775

1808-
/**
1809-
* Get the theme footers.
1810-
*
1811-
* @module infinite-scroll
1812-
*
1813-
* @since 9.0.0
1814-
*
1815-
* @param array array() An array to store multiple markup entries to be added to the footer.
1816-
* @param string $buffer The contents of the output buffer.
1817-
*/
1818-
$footers = apply_filters( 'jetpack_amp_infinite_footers', array(), $buffer );
1819-
1820-
/**
1821-
* Filter the output buffer.
1822-
* Themes can leverage this hook to add custom markup on next page load.
1823-
*
1824-
* @module infinite-scroll
1825-
*
1826-
* @since 9.0.0
1827-
*
1828-
* @param string $buffer The contents of the output buffer.
1829-
*/
1830-
$buffer = apply_filters( 'jetpack_amp_infinite_output', $buffer );
1776+
$template = self::get_settings()->render;
18311777

1832-
// Add the amp next page markup.
1833-
$buffer = preg_replace(
1834-
'~</body>~',
1835-
$this->amp_get_footer_template( $footers ) . '$0',
1836-
$buffer
1837-
);
1838-
1839-
return $buffer;
1840-
}
1841-
1842-
/**
1843-
* Get AMP next page markup with the custom footers.
1844-
*
1845-
* @param string[] $footers The theme footers.
1846-
*
1847-
* @return string
1848-
*/
1849-
protected function amp_get_footer_template( $footers = array() ) {
1850-
static $template = null;
1851-
1852-
if ( null === $template ) {
1853-
$template = $this->amp_footer_template();
1778+
if ( is_callable( "amp_{$template}_hooks" ) ) {
1779+
call_user_func( "amp_{$template}_hooks" );
18541780
}
1855-
1856-
if ( empty( $footers ) ) {
1857-
return $template;
1858-
}
1859-
1860-
return preg_replace(
1861-
'/%%footer%%/',
1862-
implode( '', $footers ),
1863-
$template
1864-
);
18651781
}
18661782

18671783
/**
18681784
* AMP Next Page markup.
1869-
*
1870-
* @return string
18711785
*/
1872-
protected function amp_footer_template() {
1873-
ob_start();
1786+
public function render_amp_next_page() {
1787+
$config = $this->amp_next_page();
18741788
?>
1875-
<amp-next-page max-pages="<?php echo esc_attr( $this->amp_get_max_pages() ); ?>">
1876-
<script type="application/json">
1877-
[
1878-
<?php echo wp_json_encode( $this->amp_next_page() ); ?>
1879-
]
1880-
</script>
1789+
<amp-next-page class="jetpack-infinite-scroll" max-pages="<?php echo esc_attr( $this->amp_get_max_pages() ); ?>">
1790+
<script type="application/json"><?php echo wp_json_encode( array( $config ) ); ?></script>
18811791
<div separator>
18821792
<?php
18831793
echo wp_kses_post(
@@ -1915,11 +1825,9 @@ protected function amp_footer_template() {
19151825
</template>
19161826
</div>
19171827
<div footer>
1918-
%%footer%%
19191828
</div>
19201829
</amp-next-page>
19211830
<?php
1922-
return ob_get_clean();
19231831
}
19241832

19251833
/**

modules/theme-tools/compat/twentynineteen.php

+21-46
Original file line numberDiff line numberDiff line change
@@ -131,62 +131,37 @@ function twentynineteen_jetpack_body_classes( $classes ) {
131131
* @return void
132132
*/
133133
function amp_twentynineteen_infinite_scroll_render_hooks() {
134-
add_filter( 'jetpack_amp_infinite_footers', 'twentynineteen_amp_infinite_footers', 10, 2 );
135-
add_filter( 'jetpack_amp_infinite_output', 'twentynineteen_amp_infinite_output' );
136134
add_filter( 'jetpack_amp_infinite_older_posts', 'twentynineteen_amp_infinite_older_posts' );
137135
}
138136

139137
/**
140-
* Get the theme specific footers.
138+
* Add arguments to the infinite scroll sanitizer.
141139
*
142-
* @param array $footers The footers of the themes.
143-
* @param string $buffer Contents of the output buffer.
144-
*
145-
* @return mixed
146-
*/
147-
function twentynineteen_amp_infinite_footers( $footers, $buffer ) {
148-
// Collect the footer wrapper.
149-
preg_match(
150-
'/<footer id="colophon".*<!-- #colophon -->/s',
151-
$buffer,
152-
$footer
153-
);
154-
$footers[] = reset( $footer );
155-
156-
return $footers;
157-
}
158-
159-
/**
160-
* Hide and remove various elements from next page load.
161-
*
162-
* @param string $buffer Contents of the output buffer.
163-
*
164-
* @return string
140+
* @param array $sanitizers Sanitizers.
141+
* @return array Sanitizers.
165142
*/
166-
function twentynineteen_amp_infinite_output( $buffer ) {
167-
// Hide site header on next page load.
168-
$buffer = preg_replace(
169-
'/id="masthead"/',
170-
'$0 next-page-hide',
171-
$buffer
172-
);
173-
174-
// Hide pagination on next page load.
175-
$buffer = preg_replace(
176-
'/class=".*navigation pagination.*"/',
177-
'$0 next-page-hide hidden',
178-
$buffer
179-
);
143+
function twentynineteen_filter_amp_infinite_scroll_sanitizers( $sanitizers ) {
144+
if ( ! array_key_exists( 'Jetpack_AMP_Infinite_Scroll_Sanitizer', $sanitizers ) ) {
145+
return $sanitizers;
146+
}
180147

181-
// Remove the footer as it will be added back to amp next page footer.
182-
$buffer = preg_replace(
183-
'/<footer id="colophon".*<!-- #colophon -->/s',
184-
'',
185-
$buffer
148+
$sanitizers['Jetpack_AMP_Infinite_Scroll_Sanitizer'] = array_merge(
149+
$sanitizers['Jetpack_AMP_Infinite_Scroll_Sanitizer'],
150+
array(
151+
// Formerly twentynineteen_amp_infinite_footers.
152+
'footer_xpaths' => array(
153+
'//footer[ @id = "colophon" ]',
154+
),
155+
'next_page_hide_xpaths' => array(
156+
'//*[ @id = "masthead" ]',
157+
'//*[ contains( @class, "navigation pagination" ) ]',
158+
),
159+
)
186160
);
187161

188-
return $buffer;
162+
return $sanitizers;
189163
}
164+
add_filter( 'amp_content_sanitizers', 'twentynineteen_filter_amp_infinite_scroll_sanitizers' );
190165

191166
/**
192167
* Filter the AMP infinite scroll older posts button

0 commit comments

Comments
 (0)