Om de AJAX filter te laten werken icm een load more button moeten er verschillende zaken worden gedaan. We gaan bepaalde posts inladen in een wrapper en de layout van een enkele post zal in een apart bestand komen omdat die moet worden aangeroepen via verschillende functies.

Maak een map “partials” in de root map van het thema en maak een bestand genaamd content-<posttype>.php. Het principe kan op meerdere post types worden toegepast.

  <?php if (get_the_post_thumbnail_url()):
      $url = get_the_post_thumbnail_url();
    else:
      $url = get_field('fallback_afbeelding_nieuws','options');
    endif;
    ?>
    <div class="col-12 col-md-4 nwsblck">
         <a href="<?php the_permalink(); ?>">
         <div class="blgmg" style="background: url('<?php echo $url; ?>') no-repeat center center; background-size: cover;">
         </div>
         <div class="blgcntnt">
           <h2 class="eq"><?php the_title(); ?></h2>
           <date><?php echo get_the_date( get_option('date_format') ); ?></date>
         </div>
       </a>
     </div>

Maak een JS bestand met de naam loadmore.js code om meer te laden. Deze moet in “<theme>/assets/js/”

jQuery(function($){

	/*
	 * Load More
	 */
	$('#ldmr').click(function(){

		$.ajax({
			url : wbmz_loadmore_params.ajaxurl, // AJAX handler
			data : {
				'action': 'loadmorebutton', // the parameter for admin-ajax.php
				'query': wbmz_loadmore_params.posts, // loop parameters passed by wp_localize_script()
				'page' : wbmz_loadmore_params.current_page // current page
			},
			type : 'POST',
			beforeSend : function ( xhr ) {
				$('#ldmr').text('Laden...'); // some type of preloader
			},
			success : function( posts ){
				if( posts ) {

					$('#ldmr').text( 'Meer laden' );
					$('#posts_wrap').append( posts ); // insert new posts
					$('.eq').matchHeight('remove'); // verwijder matchheight
        	$('.eq').matchHeight(); // voer matchheight opnieuw uit
					wbmz_loadmore_params.current_page++;

					if ( wbmz_loadmore_params.current_page == wbmz_loadmore_params.max_page )
						$('#ldmr').hide(); // if last page, HIDE the button

				} else {
					$('#ldmr').hide(); // if no data, HIDE the button as well
				}
			}
		});
		return false;
	});

	/*
	 * Filter
	 */
	$('#filters').submit(function(){

		$.ajax({
			url : wbmz_loadmore_params.ajaxurl,
			data : $('#filters').serialize(), // form data
			dataType : 'json', // this data type allows us to receive objects from the server
			type : 'POST',
			beforeSend : function(xhr){
				$('#filters').find('#zkn').text('Filtering...');
			},
			success : function( data ){

				// when filter applied:
				// set the current page to 1
				wbmz_loadmore_params.current_page = 1;
				wbmz_loadmore_params.posts = data.posts;
				wbmz_loadmore_params.max_page = data.max_page;

				// change the button label back
				$('#filters').find('#zkn').text('Filteren');

				// insert the posts to the container
				$('#posts_wrap').html(data.content);
				$('.eq').matchHeight('remove'); // verwijder matchheight
        $('.eq').matchHeight(); // voer matchheight opnieuw uit
				// verberg meer laden knop indien er geen posts meer zijn
				if ( data.max_page < 2 ) {
					$('#ldmr').hide();
				} else {
					$('#ldmr').show();
				}
			}
		});

		// do not submit the form
		return false;

	});

});

Vervolgens moet het stuk code worden aangeroepen door het thema. Dat kan met onderstaande code in de functions.php

add_action( 'wp_enqueue_scripts', 'wbmz_loadmore_script_and_styles');

function wbmz_loadmore_script_and_styles() {
	// absolutely need it, because we will get $wp_query->query_vars and $wp_query->max_num_pages from it.
	global $wp_query;

	// when you use wp_localize_script(), do not enqueue the target script immediately
	wp_register_script( 'wbmzloadmore', get_stylesheet_directory_uri() . '/assets/js/loadmore.js', array('jquery') );

	// passing parameters here
	// actually the <script> tag will be created and the object "misha_loadmore_params" will be inside it
	wp_localize_script( 'wbmzloadmore', 'wbmz_loadmore_params', array(
		'ajaxurl' => site_url() . '/wp-admin/admin-ajax.php', // WordPress AJAX
		'posts' => json_encode( $wp_query->query_vars ), // everything about your loop is here
		'current_page' => $wp_query->query_vars['paged'] ? $wp_query->query_vars['paged'] : 1,
		'max_page' => $wp_query->max_num_pages
	) );

 	wp_enqueue_script( 'wbmzloadmore' );
}

Dan de actie om daadwerkelijk de posts te laden en te filteren d.m.v. AJAX

add_action('wp_ajax_loadmorebutton', 'wbmz_loadmore_ajax_handler');
add_action('wp_ajax_nopriv_loadmorebutton', 'wbmz_loadmore_ajax_handler');

    function wbmz_loadmore_ajax_handler(){

    	// prepare our arguments for the query
    	$params = json_decode( stripslashes( $_POST['query'] ), true ); // query_posts() takes care of the necessary sanitization
    	$params['paged'] = $_POST['page'] + 1; // we need next page to be loaded
    	$params['post_status'] = 'publish';

    	// it is always better to use WP_Query but not here
    	query_posts( $params );

      if( have_posts() ) :
        while( have_posts() ): the_post();
          // Gebruik het content-<posttype>.php bestand voor content ivm custom post types
          get_template_part( 'partials/content', get_post_type() );
        endwhile;
      endif;
    	die; // here we exit the script and even no wp_reset_query() required!
    }

    add_action('wp_ajax_wbmzfilter', 'wbmz_filter_function');
    add_action('wp_ajax_nopriv_wbmzfilter', 'wbmz_filter_function');

    function wbmz_filter_function(){

    	$params = array(
    		'posts_per_page' => $_POST['number_of_results'],
    		'orderby' => 'date',
    		'order'	=> 'DESC'
    	);
      if( isset( $_POST['categoryfilter'] ) && !empty( $_POST['categoryfilter'] ) )
  		$params['tax_query'] = array(
  			array(
  				'taxonomy' => 'category',
  				'field' => 'id',
  				'terms' => $_POST['categoryfilter']
  			)
  		);

    	query_posts( $params );

    	global $wp_query;

    	if( have_posts() ) :

     		ob_start(); // start buffering because we do not need to print the posts now

        if( have_posts() ) :
          while( have_posts() ): the_post();
             // Gebruik het content-<posttype>.php bestand voor content ivm custom post types
        	   get_template_part( 'partials/content', get_post_type() );
          endwhile;
      	endif;

     		$posts_html = ob_get_contents(); // we pass the posts to variable
       		ob_end_clean(); // clear the buffer
    	else:
    		$posts_html = '<p>Er zijn geen posts gevonden.</p>';
    	endif;

    	// geen wp_reset_query() nodig

     	echo json_encode( array(
    		'posts' => json_encode( $wp_query->query_vars ),
    		'max_page' => $wp_query->max_num_pages,
    		'found_posts' => $wp_query->found_posts,
    		'content' => $posts_html
    	) );

    	die();
    }

Het formulier om de filters weer te geven (zijn meerdere toe te voegen)

<form id="filters" action="#">
          	<?php /*
            <label for="number_of_results">Per page</label>
          	<select name="number_of_results" id="number_of_results">
          		<option><?php echo get_option( 'posts_per_page' ) ?></option><!-- it is from Settings > Reading -->
          		<option>5</option>
          		<option>10</option>
          		<option value="-1">All</option>
          	</select>
            <?php */
            		if( $terms = get_terms( array( 'taxonomy' => 'category', 'orderby' => 'name', 'hide_empty' => true ) ) ) :

            			echo '<select name="categoryfilter" id="selectcat"><option value="">Select category...</option>';
            			foreach ( $terms as $term ) :
            				echo '<option value="' . $term->term_id . '">' . $term->name . '</option>'; // ID of the category as the value of an option
            			endforeach;
            			echo '</select>';
            		endif;
            	?>
	<!-- required hidden field for admin-ajax.php -->
	<input type="hidden" name="action" value="wbmzfilter" />

	<button id="zkn">Filteren</button>
</form>

Alle posts moeten worden geladen binnen een bepaalde wrapper. Daarnaast moet de loodmore button er staan

<div id="posts_wrap" class="row">
	          </div>
            <div class="cntr">
              <a class="btn" id="ldmr">Meer posts</a>
            </div>

Eventueel kan met select2 de dropdown worden gestyled en automatisch worden gefilterd indien er een selectie is gemaakt. (en resetten)

<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/js/select2.min.js"></script>
<script>
	function matchStart(params, data) {
    params.term = params.term || '';
    if (data.text.toUpperCase().indexOf(params.term.toUpperCase()) == 0) {
        return data;
    }
    return false;
  }

  jQuery(document).ready(function($) { // voeg select2 toe
    $('#zkn').hide();
    $('#zkn').trigger('click');
  		$('#selectcat').select2({
  		  width: '300px',
  		  placeholder: "Filter op categorie",
  		  allowClear: true,
  		  matcher: function(params, data) {
  		        return matchStart(params, data);
  		    }
  		});
      $('#number_of_results').select2({
  		  width: '300px',
  		  placeholder: "Aantal posts per pagina",
  		  allowClear: false,
  		  matcher: function(params, data) {
  		        return matchStart(params, data);
  		    }
  		});
    	$('select#selectcat').on('select2:select', function () {
    	  $('#zkn').trigger('click');
    	});
      $('select#number_of_results').on('select2:select', function () {
    	  $('#zkn').trigger('click');
    	});
      $("#selectcat").on("select2:unselecting", function(e) { // reset de dropdown en de posts bij klikken kruisje select2
        $('#selectcat').val(null).trigger('change');
        $('#selectcat').select2('close');
        $('#zkn').trigger('click');
      });

  });
</script>

Het is mogelijk om extra filers toe te voegen zoals een range (min-max) of een checkbox of radio

Range (min – max)

// create $args['meta_query'] array if one of the following fields is filled
	if( isset( $_POST['price_min'] ) && $_POST['price_min'] || isset( $_POST['price_max'] ) && $_POST['price_max'] || isset( $_POST['featured_image'] ) && $_POST['featured_image'] == 'on' )
		$args['meta_query'] = array( 'relation'=>'AND' ); // AND means that all conditions of meta_query should be true
 
	// if both minimum price and maximum price are specified we will use BETWEEN comparison
	if( isset( $_POST['price_min'] ) && $_POST['price_min'] && isset( $_POST['price_max'] ) && $_POST['price_max'] ) {
		$args['meta_query'][] = array(
			'key' => '_price',
			'value' => array( $_POST['price_min'], $_POST['price_max'] ),
			'type' => 'numeric',
			'compare' => 'between'
		);
	} else {
		// if only min price is set
		if( isset( $_POST['price_min'] ) && $_POST['price_min'] )
			$args['meta_query'][] = array(
				'key' => '_price',
				'value' => $_POST['price_min'],
				'type' => 'numeric',
				'compare' => '>'
			);
 
		// if only max price is set
		if( isset( $_POST['price_max'] ) && $_POST['price_max'] )
			$args['meta_query'][] = array(
				'key' => '_price',
				'value' => $_POST['price_max'],
				'type' => 'numeric',
				'compare' => '<'
			);
	}
<input type="text" name="price_min" placeholder="Min price" />
	<input type="text" name="price_max" placeholder="Max price" />




Sorteren (vervang stukje in functie)

$args = array(
		'orderby' => 'date', // we will sort posts by date
		'order'	=> $_POST['date'] // ASC or DESC
	);
<label>
		<input type="radio" name="date" value="ASC" /> Date: Ascending
	</label>
	<label>
		<input type="radio" name="date" value="DESC" selected="selected" /> Date: Descending
	</label>

Geef een reactie 0