1

I am using ajax to load posts based on a filter. Should there be more than 9, I have pagination coming into play. While pagination calls the correct number of pages, the links themselves do not work. Instead they go to a page that ends with the site url + /wp-admin/admin-ajax.php?paged=2. That that page is blank with a 0 on it. That's it.

When I use javascript to dynamically overwrite the pagination link into them the correct links, the page only goes the same original page.

Any help is appreciated.

the ajax code in my functions.php

add_action( 'wp_ajax_myfilter', 'posts_filter_function' );
add_action( 'wp_ajax_nopriv_myfilter', 'posts_filter_function' );

function posts_filter_function() {

$args = array(
    'order'          => 'DESC',
    'post_type'      => 'post',
    'post_status'    => 'publish',
    'posts_per_page' => 9,
    'paged' => ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1,
);

// for categories!
if( isset( $_POST['categoryfilter'] ) )
    $args['tax_query'] = array(
        array(
            'taxonomy' => 'category',
            'field'    => 'id',
            'terms'    => $_POST['categoryfilter']
        )
    );

// for topics!
// if( isset( $_POST['topicfilter'] ) )
// $args['tax_query'] = array(
//  array(
//      'taxonomy' => 'topics',
//      'field' => 'id',
//      'terms' => $_POST['topicfilter']
//  )
// );

$query = new WP_Query( $args );
$backup_image = get_field( 'featured_image_global', 'option' );
?>
<div class="news-grid grid-x small-up-1 medium-up-3">
    <?php
    if ( $query->have_posts() ) :
        while ( $query->have_posts() ) : $query->the_post();
            $image = get_the_post_thumbnail_url( $post->ID, 'featured-large' );
            if ( $image ) {
                $image = get_the_post_thumbnail_url( $post->ID, 'featured-large' );
            } else {
                $image = $backup_image;
            }
            ?>
            <div class="cell posts__filter--item">
                <a href="<?php echo esc_html( get_post_permalink( $post->ID ) ); ?>">
                    <div class="card">
                        <div class="card-section">
                        <img
                        src="<?php echo esc_attr( $image ); ?>"
                        alt="<?php echo esc_html( get_post_meta( get_post_thumbnail_id( $post->ID ), '_wp_attachment_image_alt', true ) ); ?>">

                            <p class='date'><?php echo esc_html( get_the_date( 'd M \'y', $post->ID ) ); ?></p>
                            <h4><?php echo esc_html( get_the_title( $post->ID ) ); ?></h4>
                            <p class='author'><?php echo esc_html( post_authors( $post ) ); ?></p>
                        </div>
                    </div>
                </a>
            </div>
            <?php
        endwhile;
        ?>
    </div>
            <div class="pagination--container">
        <?php
        echo paginate_links(
            array(
                'base'      => get_home_url() . '/news/' . '%_%',
                'format'    => '?paged=%#%',
                'current'   => max( 1, get_query_var( 'paged' ) ),
                'total'     => $query->max_num_pages,
                'prev_text' => '1',
                'next_text' => '1',
            )
        );
        ?>
    </div>
        <?php
        wp_reset_postdata();
    else :
        echo '<h2 class="no-posts">No posts found</h2>';
    endif;
    die();
}

The filter form in my filter.php

$categories = get_terms(
array(
    'taxonomy'   => 'category',
    'hide_empty' => true,
    'orderby'    => 'name',
)
);

$topics = get_terms(
array(
    'taxonomy'   => 'topics',
    'hide_empty' => true,
    'orderby'    => 'name',
)
);
?>

<form
action="<?php echo site_url() ?>/wp-admin/admin-ajax.php"
method="POST"
class="searchandfilter"
id="filter">

<section class='postfilter'>
    <div class="postfilter--filters flex-container flex-dir-column large-flex-dir-row">

        <div class="flex-child-auto">
            <input type="hidden">
            <p class="">Filter By:</p>
        </div>

        <div class="ui-group flex-child-auto">
            <select class="select--topic postform" name="topicfilter">
                <option value="All">Topic</option>
                <?php
                foreach ( $topics as $topic ) {
                    ?>
                <option value="<?php echo esc_html( $topic->term_id ); ?>"><?php echo esc_html( $topic->name ); ?></option>
                    <?php
                }
                ?>
            </select>
        </div>

        <div class="ui-group flex-child-auto">
            <select class="select--category postform" name="categoryfilter">
                <option value="All">Category</option>
                <?php
                foreach ( $categories as $category ) {
                    ?>
                <option value="<?php echo esc_html( $category->term_id ); ?>"><?php echo esc_html( $category->name ); ?></option>
                    <?php
                }
                ?>
            </select>
        </div>

        <div class="flex-child-auto ui-group">
            <button class="button button--orange button--filter">
                Submit
            </button>
            <input type="hidden" name="action" value="myfilter">
        </div>
    </div>
</section>

The jquery code

 $('#filter').submit(function(){
  var filter = $('#filter');
  var text = $('.no-posts');
  var currentPosts = $('#response');
  $.ajax({
    url:filter.attr('action'),
    data:filter.serialize(), // form data
    type:filter.attr('method'), // POST
    beforeSend:function(xhr){
      text.text('Loading Posts...');
      text[0].style.margin = '10rem auto';
      currentPosts[0].style.display = 'none';
    },
    success:function(data){
      text.text('');
      text[0].style.margin = 0;
      currentPosts[0].style.display = 'block';
      $('#response').html(data); // insert data
    }
  });
  return false;
});
Marsel Gray
  • 33
  • 1
  • 7
  • Have you tried changing the `'base'` property in the `paginate_links` function? – Emiel Zuurbier Aug 14 '19 at 17:49
  • Hey Emiel. Yeah I have. I've tried `'base' => get_pagenum_link(1) . '%_%',` – Marsel Gray Aug 14 '19 at 18:05
  • Alright, I've been in your situation a couple of times and did the same thing of changing the links manually with JS. But now I look at it I think that the `'base'` property is the culprit. Try hardcoding the base property with the url of your pagination page with `'%_%'` appended to see what I mean. – Emiel Zuurbier Aug 14 '19 at 18:21
  • Possible duplicate of [WordPress Pagination not working with AJAX](https://stackoverflow.com/questions/20150653/wordpress-pagination-not-working-with-ajax) – Emiel Zuurbier Aug 14 '19 at 18:34
  • I appreciate you looking at it this. I tried doing what you just mentioned which gave me the classic `404 page not found` – Marsel Gray Aug 14 '19 at 18:36
  • Hey Emiel, thanks for sharing that link for the possible duplicate. I had already checked that one out and used it to correct pagination links themselves but it still left me with the problem in my second paragraph: `When I use javascript to dynamically overwrite the pagination link into them the correct links, the page only goes the same original page.` . Basically it goes to /page/2 but with the same original 9 posts – Marsel Gray Aug 15 '19 at 13:36
  • Could you add the code that overwrites the `href` attribute on the links? – Emiel Zuurbier Aug 15 '19 at 13:46
  • definitely, I updated the above code. It starts in the first code block at `
    ` but your suspicions about the base were correct. I ended changing it somewhat to `'base' => get_home_url() . '/news/' . '%_%',`
    – Marsel Gray Aug 15 '19 at 14:20
  • Nice, does that mean you solved your problem? I've added an answer which will make the `base` property dynamic in your code. For our future projects ;). – Emiel Zuurbier Aug 16 '19 at 08:28

1 Answers1

1

The problem is the'base' property which will refer from the page it is being rendered on. If you use str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ) ,as is mentioned in the WordPress documentation, it will create an URL from the current page, which in the admin-ajax.php file will become /wp-admin/admin-ajax.php.

So we need to make the base property dynamic.

Dynamic input field

In your form add another hidden input element that refers to the page that you are on. This way we don't have to change the JS and can add or remove input fields in the HTML if we want to.

<?php
global $wp;
$base = home_url( $wp->request ); // Gets the current page we are on.
?>

<input type="hidden" name="base" value="<?php echo $base; ?>"/>

This input can send the URL to the AJAX function and use it as a the base property for the paginate_links function.

Check for the base value in your posts_filter_function function.

// Fallback if there is not base set.
$fallback_base = str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) );

// Set the base.
$base = isset( $_POST[ 'base' ] ) ? trailingslashit( $_POST[ 'base' ] ) . '%_%' : $fallback_base;

Then pass the base value as an argument for the paginate_links function.

paginate_links(
    array(
        'base'      => $base,
        'format'    => '?paged=%#%',
        'current'   => max( 1, get_query_var( 'paged' ) ),
        'total'     => $query->max_num_pages,
        'prev_text' => '1',
        'next_text' => '1',
    )
);

So the value of the input field will determine what the base property will become.

Alternative: It is also possible to simply add the current URL in the jQuery Ajax request. Before passing the serialized data in the data attribute add:

'&base=' + location.hostname + location.pathname;

This is less preferable to the input solution since it requires some kind of hardcoding, but might be an option when the HTML can not be manipulated.

Emiel Zuurbier
  • 19,095
  • 3
  • 17
  • 32