-
-
Save dkjensen/5190c554420ea2f19987a3f31ac95785 to your computer and use it in GitHub Desktop.
<?php | |
/** | |
* Add data attributes to the query block to describe the block query. | |
* | |
* @param string $block_content Default query content. | |
* @param array $block Parsed block. | |
* @return string | |
*/ | |
function query_render_block( $block_content, $block ) { | |
global $wp_query; | |
if ( 'core/query' === $block['blockName'] ) { | |
$query_id = $block['attrs']['queryId']; | |
$container_end = strpos( $block_content, '>' ); | |
$inherit = $block['attrs']['query']['inherit'] ?? false; | |
// Account for inherited query loops | |
if ( $inherit && $wp_query && isset( $wp_query->query_vars ) && is_array( $wp_query->query_vars ) ) { | |
$block['attrs']['query'] = query_replace_vars( $wp_query->query_vars ); | |
} | |
$paged = absint( $_GET[ 'query-' . $query_id . '-page' ] ?? 1 ); | |
$block_content = substr_replace( $block_content, ' data-paged="' . esc_attr( $paged ) . '" data-attrs="' . esc_attr( json_encode( $block ) ) . '"', $container_end, 0 ); | |
} | |
return $block_content; | |
} | |
\add_filter( 'render_block', __NAMESPACE__ . '\query_render_block', 10, 2 ); | |
/** | |
* Replace the pagination block with a View More button. | |
* | |
* @param string $block_content Default pagination content. | |
* @param array $block Parsed block. | |
* @return string | |
*/ | |
function query_pagination_render_block( $block_content, $block ) { | |
if ( 'core/query-pagination' === $block['blockName'] ) { | |
$block_content = sprintf( '<a href="#" class="view-more-query button">%s</a>', esc_html__( 'View More' ) ); | |
} | |
return $block_content; | |
} | |
\add_filter( 'render_block', __NAMESPACE__ . '\query_pagination_render_block', 10, 2 ); | |
/** | |
* AJAX function render more posts. | |
* | |
* @return void | |
*/ | |
function query_pagination_render_more_query() { | |
$block = json_decode( stripslashes( $_GET['attrs'] ), true ); | |
$paged = absint( $_GET['paged'] ?? 1 ); | |
if ( $block ) { | |
$block['attrs']['query']['offset'] += $block['attrs']['query']['perPage'] * $paged; | |
\add_filter( 'query_loop_block_query_vars', function( $query ) { | |
// Only return published posts. | |
$query['post_status'] = 'publish'; | |
return $query; | |
} ); | |
echo render_block( $block ); | |
} | |
exit; | |
} | |
add_action( 'wp_ajax_query_render_more_pagination', __NAMESPACE__ . '\query_pagination_render_more_query' ); | |
add_action( 'wp_ajax_nopriv_query_render_more_pagination', __NAMESPACE__ . '\query_pagination_render_more_query' ); | |
/** | |
* Replace WP_Query vars format with block attributes format | |
* | |
* @param array $vars WP_Query vars. | |
* @return array | |
*/ | |
function query_replace_vars( $vars ) { | |
$updated_vars = [ | |
'postType' => $vars['post_type'] ?? 'post', | |
'perPage' => $vars['posts_per_page'] ?? get_option( 'posts_per_page', 10 ), | |
'pages' => $vars['pages'] ?? 0, | |
'offset' => 0, | |
'order' => $vars['order'] ?? 'DESC', | |
'orderBy' => $vars['order_by'] ?? '', | |
'author' => $vars['author'] ?? '', | |
'search' => $vars['search'] ?? '', | |
'exclude' => $vars['exclude'] ?? array(), | |
'sticky' => $vars['sticky'] ?? '', | |
'inherit' => false | |
]; | |
return $updated_vars; | |
} |
( function( $ ) { | |
$( '.view-more-query' ).on( 'click', function( e ) { | |
e.preventDefault(); | |
const self = $( this ); | |
const queryEl = $( this ).closest( '.wp-block-query' ); | |
const postTemplateEl = queryEl.find( '.wp-block-post-template' ); | |
if ( queryEl.length && postTemplateEl.length ) { | |
const block = JSON.parse( queryEl.attr( 'data-attrs' ) ); | |
const maxPages = block.attrs.query.pages || 0; | |
$.ajax( { | |
url: i18n.ajax_url, | |
dataType: 'json html', | |
data: { | |
action: 'query_render_more_pagination', | |
attrs: queryEl.attr( 'data-attrs' ), | |
paged: queryEl.attr( 'data-paged' ), | |
}, | |
complete( xhr ) { | |
const nextPage = Number( queryEl.attr( 'data-paged' ) ) + 1; | |
if ( maxPages > 0 && nextPage >= maxPages ) { | |
self.remove(); | |
} | |
queryEl.attr( 'data-paged', nextPage ); | |
if ( xhr.responseJSON ) { | |
console.log( xhr.responseJSON ); // eslint-disable-line | |
} else { | |
const htmlEl = $( xhr.responseText ); | |
if ( htmlEl.length ) { | |
const html = htmlEl.find( '.wp-block-post-template' ).html() || ''; | |
if ( html.length ) { | |
postTemplateEl.append( html ); | |
return; | |
} | |
} | |
self.remove(); | |
} | |
}, | |
} ); | |
} | |
} ); | |
}( jQuery ) ); |
Hey @dkjensen, I noticed another issue when using it on the search template as there are no $vars['search'] available so it just loads all posts as normal when clicked on so I adjusted my $updated_vars to reflect that issue, and used the get_query_var('s') instead and this is currently working great so thought I'd share. I also have my tax query checks too.
function query_replace_vars( $vars ) {
$updated_vars = [
'postType' => $vars['post_type'] ?? 'post',
'perPage' => $vars['posts_per_page'] ?? get_option( 'posts_per_page', 10 ),
'pages' => $vars['pages'] ?? 0,
'offset' => 0,
'order' => $vars['order'] ?? 'DESC',
'orderBy' => $vars['order_by'] ?? 'date',
'author' => $vars['author'] ?? '',
'exclude' => $vars['exclude'] ?? array(),
'sticky' => $vars['sticky'] ?? 'exclude',
'inherit' => false,
];
// get the search term from the query string
$search_term = get_query_var('s');
if ($search_term) {
$updated_vars['search'] = $search_term;
}
if ($vars['cat'] ) {
$updated_vars['taxQuery']['category'] = [$vars['cat']];
}
if ($vars['tag'] ) {
$updated_vars['taxQuery']['post_tag'] = [$vars['tag']];
}
return $updated_vars;
}
One item I am working on is making the "Load More" button hidden if there is no 2nd page of posts initially or when loading up the next set as it still shows if there's no more and only when you click again, does it remove itself. It looks like I'd have to try to identify if the core/query-pagination-next inner block has any items inside. I'm not sure how the actual core/query-pagination is doing it as it doesn't display if there aren't any more posts when not using the "Load More" button.
Thanks so much again!
@dkjensen is there a way to prevent showing the View More link in case the page has no posts to show. (For example after a search)
@damianoporta You could try this:
* Replace the pagination block with a View More button.
*
* @param string $block_content Default pagination content.
* @param array $block Parsed block.
* @return string
*/
function query_pagination_render_block( $block_content, $block ) {
if ( 'core/query-pagination' === $block['blockName'] ) {
if ( $block_content ) {
$block_content = sprintf( '<a href="#" class="view-more-query button">%s</a>', esc_html__( 'View More' ) );
}
}
return $block_content;
}
\add_filter( 'render_block', __NAMESPACE__ . '\query_pagination_render_block', 10, 2 );```
Curious if anyone has tried using this with a query block variation? I'm attempting to and having trouble getting the load more to actually work. This has been very helpful though, thanks for everyones input!
@hannahmwool that would be great!
Thanks so much @dkjensen I just discovered that filter today after filtering through main queries and such and was planning to mention it here and share today so It's great to see where you implemented it!
Also sharing my vanilla JS version of the jQuery part for anyone who may want to use it. I left in my scroll to the newly added posts function in case that is helpful for anyone. I also have a class added to new items as I like to bring them in in certain ways, figured the class may be helpful and can be removed also. Would definitely welcome any improvements for the below.