1

On my CPT archive page I have custom "sort by" form that works perfectly but breaks with my pagination - here is example from my archive-listing.php file:

        <div class="col-xxl-9 col-xl-9 col-lg-8 col-md-7">
            
            <?php
            if ( have_posts() ) : 
                global $wp_query;
                $paged = ! empty( $wp_query->query_vars['paged'] ) ? $wp_query->query_vars['paged'] : 1;
                $per_page = $wp_query->query_vars['posts_per_page'];
                $prev_posts = ( $paged - 1 ) * $per_page;
                $from = 1 + $prev_posts;
                $to = count( $wp_query->posts ) + $prev_posts;
                $total = $wp_query->found_posts; ?>
            
                <div class="viewItems">
                    <div class="row align-items-center">
                        <div class="col-12 col-lg-6">
                            <strong>
                            
                                <?php
                                if ( 1 == $total ) {
                                    echo 'Showing one result';
                                } else {
                                    printf( 'Showing %s - %s of %s results', $from, $to, $total );
                                }
                                ?>                                  
                                
                            </strong>
                        </div>

                        <div class="col-12 col-lg-6">
                            <div class="select-itms">

                                <?php wpse_288655_display_form(); ?>

                            </div>
                        </div>
                    </div>
                </div>

                <div class="gridView">
                    <div id="response">
                        <div class="row">
                            
                            <?php
                            while ( have_posts() ) : the_post();
                                echo '<div class="col-xl-4 col-lg-6 col-md-12 col-sm-6">';
                                get_template_part( 'content', 'listing' );
                                echo '</div>';
                            endwhile;
                            ?>
                            
                        </div>
                    </div>
                </div>

                <div class="row justify-content-center">
                    <div class="col-lg-12">
                        <div class="pagination mt-60">

                            <?php
                            global $wp_query;
                            $total_pages = $wp_query->max_num_pages;

                            if ( $total_pages > 1 ) {

                                $current_page = max( 1, get_query_var( 'paged' ) );

                                echo paginate_links( array(
                                    'base' => get_pagenum_link( 1 ) . '%_%',
                                    'format' => '/page/%#%',
                                    'current' => $current_page,
                                    'total' => $total_pages,
                                    'prev_text' => '<i class="las la-angle-left"></i>',
                                    'next_text' => '<i class="las la-angle-right"></i>',
                                    'type'      => 'list',
                                    'end_size'  => 3,
                                    'mid_size'  => 3,
                                ) );
                            }
                            ?>

                        </div>
                    </div>
                </div>
            
            <?php
            endif;
            ?>
            
        </div>

sorting form code in functions.php source :

<?php
/**
 * Display sort form
 */
function wpse_288655_display_form() {

    /**
     * Get all params from url which are not part of our sort form
     * and display it in form as hidden inputs.
     */
    $search_param = filter_input( INPUT_GET, 's', FILTER_SANITIZE_STRING );

    /**
     * Current order value to select proper field
     */
    $value = filter_input( INPUT_GET, 'order', FILTER_SANITIZE_STRING );
    ?>

    <form method="get">
        <?php wpse_288655_display_select('order', 'Sort by:', wpse_288655_get_order_by_options(), $value ); ?>

        <?php
            /**
             * Display all params from url which do not apply to our sort form
             */
        ?>
        <input type="hidden" name="s" value="<?php esc_attr_e( $search_param ); ?>">

        <button type="submit"><?php esc_html_e('Sort'); ?></button>
    </form>
    <?php
}

/**
 * Get sort options
 */
function wpse_288655_get_order_by_options(){

    return array(
        '' => '',
        'newest' => __('Newest'),
        'oldest' => __('Oldest'),
        'most_expensive' => __('Most Expensive'),
        'least_expensive' => __('Least Expensive'),
        'largest' => __('Largest'),
        'smallest' => __('Smallest'),
    );
}

/**
 * Display select field
 */
function wpse_288655_display_select( $name, $label, $options, $value = '' ) {
    ?>
    <label><?php esc_html_e( $label ) ?></label>
    <select name="<?php esc_attr_e( $name ) ?>">
        <?php wpse_288655_display_options( $options, $value ); ?>
    </select>
    <?php
}

/**
 * Display select options
 */
function wpse_288655_display_options( $options, $value ) {

    foreach( $options as $option_value => $option_label ):
        $selected = ( $option_value === $value ) ? ' selected' : '';
        ?>
        <option value="<?php esc_attr_e( $option_value ) ?>"<?php esc_attr_e( $selected ) ?>><?php esc_html_e( $option_label ) ?></option>
        <?php

    endforeach;
}

/**
 * Sort posts using pre_get_posts filter
 */
function wpse_288655_order_posts( $query ) {

    /**
     * Execute query only when we are on search page and this is main query
     */
    if ( $query->is_search() && $query->is_main_query() ) {

        $value = filter_input( INPUT_GET, 'order', FILTER_SANITIZE_STRING );
        $order_by_options = wpse_288655_get_order_by_options();

        if( isset( $order_by_options[ $value ] ) && !empty( $value ) ) {

            switch( $value ) {
                case 'newest':

                    $query->set( 'order', 'desc' );
                    $query->set( 'orderby', 'date' );

                    break;

                case 'oldest':

                    $query->set( 'order', 'asc' );
                    $query->set( 'orderby', 'date' );

                    break;
                case 'most_expensive':

                    $query->set( 'meta_key', 'price' ); // Your custom meta_key

                    $query->set( 'order', 'desc' );
                    $query->set( 'orderby', 'meta_value_num' );

                    break;
                case 'least_expensive':

                    $query->set( 'meta_key', 'price' ); // Your custom meta_key

                    $query->set( 'order', 'asc' );
                    $query->set( 'orderby', 'meta_value_num' );

                    break;
                case 'largest':

                    $query->set( 'meta_key', 'size' ); // Your custom meta_key

                    $query->set( 'order', 'desc' );
                    $query->set( 'orderby', 'meta_value_num' );

                    break;
                case 'smallest':

                    $query->set( 'meta_key', 'size' ); // Your custom meta_key

                    $query->set( 'order', 'asc' );
                    $query->set( 'orderby', 'meta_value_num' );

                    break;
                default:
                    break;
            }
        }
    }
}
add_filter('pre_get_posts', 'wpse_288655_order_posts');

It creates links like example.com/listings/?order=oldest/page/2, but you stay on the first page

1
  • 1
    This happens because you create a new query. See this answer on how to do it correctly.
    – fuxia
    Commented Aug 8 at 17:44

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.