Skip to content

Instantly share code, notes, and snippets.

@dkjensen
Last active April 3, 2024 21:05
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save dkjensen/5190c554420ea2f19987a3f31ac95785 to your computer and use it in GitHub Desktop.
Save dkjensen/5190c554420ea2f19987a3f31ac95785 to your computer and use it in GitHub Desktop.
WordPress Gutenberg Query Loop View More AJAX
<?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 ) );
@damianoporta
Copy link

@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)

@dkjensen
Copy link
Author

dkjensen commented Mar 18, 2024

@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 );```

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment