Skip to main content

WordPress Front-end AJAX Pagination with Search and Sort

Step 1: Create a custom page in WordPress
  • Go to your Dashboard > Pages > Add New
  • Name the page anything you want, ex: My Posts
  • In your Dashboard > Settings > Permalinks, make sure Common Settings is set to Post Name
  • In your newly created page, copy the page slag: if you used “My Posts” as your page name, the slag would be my-posts
  • In your WordPress theme create a file called page-my-posts.php  Notice how we attached the slag to the “page-“, this will allow us to add custom scripts that will only apply to this specific page.
  • Go to your browser and navigate to your new page. ex. http://example.com/my-posts It should show you a blank white page, if not then you did something incorrectly.

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
 ---Open the new page and paste the following code template:
<?php get_header(); ?>
    <div class  ="col-md-12 content">
        <div class = "content">
            <form class = "post-list">
                <input type = "hidden" value = "" />
            </form>
            <?php if ( have_posts() ) while ( have_posts() ) : the_post(); ?>
                <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
                    <h1 class="entry-title"><?php the_title(); ?></h1>                                                                               
                    <hr />
                    <article class="entry-content clear">
                        <?php the_content(); ?>
                    </article>
                </article>
            <?php endwhile; ?>
         
            <article class="navbar-form navbar-left">
                <div class="form-group">
                    <input type="text" class="form-control post_search_text" placeholder="Enter a keyword">
                </div>
                <input type = "submit" value = "Search" class = "btn btn-success post_search_submit" />
            </article>
         
            <br class = "clear" />
         
            <script type="text/javascript">
            var ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>';
         
            function cvf_load_all_posts(page, th_name, th_sort){
                $(".cvf_universal_container").html('<p><img src = "<?php bloginfo('template_url'); ?>/images/loading.gif" class = "loader" /></p>');
             
                var post_data = {
                    page: page,
                    search: $('.post_search_text').val(),
                    th_name: th_name,
                    th_sort: th_sort
                };
             
                $('form.post-list input').val(JSON.stringify(post_data));
             
                var data = {
                    action: "demo_load_my_posts",
                    data: JSON.parse($('form.post-list input').val())
                };
             
                $.post(ajaxurl, data, function(response) {
                    if($(".cvf_universal_container").html(response)){
                        $('.table-post-list th').each(function() {
                            // Append the button indicator
                            $(this).find('span.glyphicon').remove(); 
                            if($(this).hasClass('active')){
                                if(JSON.parse($('form.post-list input').val()).th_sort == 'DESC'){
                                    $(this).append(' <span class="glyphicon glyphicon-chevron-down"></span>');
                                } else {
                                    $(this).append(' <span class="glyphicon glyphicon-chevron-up"></span>');
                                }
                            }
                        });
                    }
                });
            }
         
            jQuery(document).ready(function($) {                                                             
             
                // Initialize default item to sort and it's sort order
             
                // Check if our hidden form input is not empty, meaning it's not the first time viewing the page.
                if($('form.post-list input').val()){
                    // Submit hidden form input value to load previous page number
                    data = JSON.parse($('form.post-list input').val());
                    cvf_load_all_posts(data.page, data.th_name, data.th_sort);
                } else {
                    // Load first page
                    cvf_load_all_posts(1, 'post_title', 'ASC');
                }
             
                var th_active = $('.table-post-list th.active');
                var th_name = $(th_active).attr('id');
                var th_sort = $(th_active).hasClass('DESC') ? 'ASC': 'DESC';
                         
                // Search
                $('body').on('click', '.post_search_submit', function(){
                    cvf_load_all_posts(1, th_name, th_sort);
                });
                // Search when Enter Key is triggered
                $(".post_search_text").keyup(function (e) {
                    if (e.keyCode == 13) {
                        cvf_load_all_posts(1, th_name, th_sort);
                    }
                });
             
                // Pagination Clicks                   
                $('.cvf_universal_container .cvf-universal-pagination li.active').live('click',function(){
                    var page = $(this).attr('p');
                    var current_sort = $(th_active).hasClass('DESC') ? 'DESC': 'ASC';
                    cvf_load_all_posts(page, th_name, current_sort);             
                });

                // Sorting Clicks
                $('body').on('click', '.table-post-list th', function(e) {
                    e.preventDefault();                          
                    var th_name = $(this).attr('id');
                                                     
                    if(th_name){
                        // Remove all TH tags with an "active" class
                        if($('.table-post-list th').removeClass('active')) {
                            // Set "active" class to the clicked TH tag
                            $(this).addClass('active');
                        }
                        if(!$(this).hasClass('DESC')){
                            cvf_load_all_posts(1, th_name, 'DESC');
                            $(this).addClass('DESC');
                        } else {
                            cvf_load_all_posts(1, th_name, 'ASC');
                            $(this).removeClass('DESC');
                        }
                    }
                })
            });
            </script>
         
            <table class = "table table-striped table-post-list no-margin">
                <tr>
                    <th width = "25%" class = "active" id = "post_title"><u><a href = "#">Post Name</a></u></th>
                    <th width = "60%">Description</th>
                    <th width = "15%" id = "post_date"><u><a href = "#">Post Date</a></u></th>
                </tr>
            </table>
         
            <div class = "cvf_pag_loading no-padding">
                <div class = "cvf_universal_container">
                    <div class="cvf-universal-content"></div>
                </div>
            </div>
        </div>
    </div>
 
<?php get_footer(); ?>



------------------functions.php

add_action( 'wp_ajax_demo_load_my_posts', 'demo_load_my_posts' );
add_action( 'wp_ajax_nopriv_demo_load_my_posts', 'demo_load_my_posts' );
function demo_load_my_posts() {
     
    global $wpdb;
 
    $msg = '';
 
    if( isset( $_POST['data']['page'] ) ){
        // Always sanitize the posted fields to avoid SQL injections
        $page = sanitize_text_field($_POST['data']['page']); // The page we are currently at
        $name = sanitize_text_field($_POST['data']['th_name']); // The name of the column name we want to sort
        $sort = sanitize_text_field($_POST['data']['th_sort']); // The order of our sort (DESC or ASC)
        $cur_page = $page;
        $page -= 1;
        $per_page = 15; // Number of items to display per page
        $previous_btn = true;
        $next_btn = true;
        $first_btn = true;
        $last_btn = true;
        $start = $page * $per_page;
     
        // The table we are querying from  
        $posts = $wpdb->prefix . "posts";
     
        $where_search = '';
     
        // Check if there is a string inputted on the search box
        if( ! empty( $_POST['data']['search']) ){
            // If a string is inputted, include an additional query logic to our main query to filter the results
            $where_search = ' AND (post_title LIKE "%%' . $_POST['data']['search'] . '%%" OR post_content LIKE "%%' . $_POST['data']['search'] . '%%") ';
        }
     
        // Retrieve all the posts
        $all_posts = $wpdb->get_results($wpdb->prepare("
            SELECT * FROM $posts WHERE post_type = 'post' AND post_status = 'publish' $where_search
            ORDER BY $name $sort LIMIT %d, %d"
, $start, $per_page ) );
     
        $count = $wpdb->get_var($wpdb->prepare("
            SELECT COUNT(ID) FROM "
. $posts . " WHERE post_type = 'post' AND post_status = 'publish' $where_search", array() ) );
     
        // Check if our query returns anything.
        if( $all_posts ):
            $msg .= '<table class = "table table-striped table-hover table-file-list">';
         
            // Iterate thru each item
            foreach( $all_posts as $key => $post ):
                $msg .= '
                <tr>
                    <td width = "25%"><a href = "'
. get_permalink( $post->ID ) . '">' . $post->post_title . '</a></td>
                    <td width = "60%">'
. $post->post_excerpt . '</td>
                    <td width = "15%">'
. $post->post_date . '</td>
                </tr>'
;      
            endforeach;
         
            $msg .= '</table>';
     
        // If the query returns nothing, we throw an error message
        else:
            $msg .= '<p class = "bg-danger">No posts matching your search criteria were found.</p>';
         
        endif;

        $msg = "<div class='cvf-universal-content'>" . $msg . "</div><br class = 'clear' />";
     
        $no_of_paginations = ceil($count / $per_page);

        if ($cur_page >= 7) {
            $start_loop = $cur_page - 3;
            if ($no_of_paginations > $cur_page + 3)
                $end_loop = $cur_page + 3;
            else if ($cur_page <= $no_of_paginations && $cur_page > $no_of_paginations - 6) {
                $start_loop = $no_of_paginations - 6;
                $end_loop = $no_of_paginations;
            } else {
                $end_loop = $no_of_paginations;
            }
        } else {
            $start_loop = 1;
            if ($no_of_paginations > 7)
                $end_loop = 7;
            else
                $end_loop = $no_of_paginations;
        }
       
        $pag_container .= "
        <div class='cvf-universal-pagination'>
            <ul>"
;

        if ($first_btn && $cur_page > 1) {
            $pag_container .= "<li p='1' class='active'>First</li>";
        } else if ($first_btn) {
            $pag_container .= "<li p='1' class='inactive'>First</li>";
        }

        if ($previous_btn && $cur_page > 1) {
            $pre = $cur_page - 1;
            $pag_container .= "<li p='$pre' class='active'>Previous</li>";
        } else if ($previous_btn) {
            $pag_container .= "<li class='inactive'>Previous</li>";
        }
        for ($i = $start_loop; $i <= $end_loop; $i++) {

            if ($cur_page == $i)
                $pag_container .= "<li p='$i' class = 'selected' >{$i}</li>";
            else
                $pag_container .= "<li p='$i' class='active'>{$i}</li>";
        }
     
        if ($next_btn && $cur_page < $no_of_paginations) {
            $nex = $cur_page + 1;
            $pag_container .= "<li p='$nex' class='active'>Next</li>";
        } else if ($next_btn) {
            $pag_container .= "<li class='inactive'>Next</li>";
        }

        if ($last_btn && $cur_page < $no_of_paginations) {
            $pag_container .= "<li p='$no_of_paginations' class='active'>Last</li>";
        } else if ($last_btn) {
            $pag_container .= "<li p='$no_of_paginations' class='inactive'>Last</li>";
        }

        $pag_container = $pag_container . "
            </ul>
        </div>"
;
     
        echo
        '<div class = "cvf-pagination-content">' . $msg . '</div>' .
        '<div class = "cvf-pagination-nav">' . $pag_container . '</div>';
     
    }
 
    exit();
 
}





---------------css
.cvf_pag_loading {padding: 20px; }
.cvf-universal-pagination ul {margin: 0; padding: 0;}
.cvf-universal-pagination ul li {display: inline; margin: 3px; padding: 4px 8px; background: #FFF; color: black; }
.cvf-universal-pagination ul li.active:hover {cursor: pointer; background: #1E8CBE; color: white; }
.cvf-universal-pagination ul li.inactive {background: #7E7E7E;}
.cvf-universal-pagination ul li.selected {background: #1E8CBE; color: white;}

Comments

Popular posts from this blog

add custom post type

/**  *  * add custom post type  *  */ function my_custom_post_product() {   $labels = array(     'name'               => _x( 'Products', 'post type general name' ),     'singular_name'      => _x( 'Product', 'post type singular name' ),     'add_new'            => _x( 'Add New', 'book' ),     'add_new_item'       => __( 'Add New Product' ),     'edit_item'          => __( 'Edit Product' ),     'new_item'           => __( 'New Product' ),     'all_items'          => __( 'All Products' ),     'vi...

Toolset conditional

[wpv- if evaluate= "'[wpv-current-user info='id']' = '[wpv-post-author format='meta' meta='ID']' OR '[wpv-current-user info='role']' = 'administrator'" ]      //the content you want to hide goes here [/wpv- if ]