Creating a WP archive with custom field filter

Last updated Nov 18, 2022

Overview

This video tutorial will cover the basics of creating a WP archive that displays posts filtered by a checkbox custom field. Please watch the video first, and use the code below to kick start your project!

Usage

This snippet of code is placed within the functions.php file and modifies the WP_Query args based on the available $_GET params.

functions.php

// array of filters (field key => field name)
$GLOBALS['my_query_filters'] = array( 
    'field_1'   => 'city', 
    'field_2'   => 'bedrooms'
);


// action
add_action('pre_get_posts', 'my_pre_get_posts', 10, 1);

function my_pre_get_posts( $query ) {
    
    // bail early if is in admin
    if( is_admin() ) return;
    
    
    // bail early if not main query
    // - allows custom code / plugins to continue working
    if( !$query->is_main_query() ) return;
    
    
    // get meta query
    $meta_query = $query->get('meta_query');

    
    // loop over filters
    foreach( $GLOBALS['my_query_filters'] as $key => $name ) {
        
        // continue if not found in url
        if( empty($_GET[ $name ]) ) {
            
            continue;
            
        }
        
        
        // get the value for this filter
        // eg: http://www.website.com/events?city=melbourne,sydney
        $value = explode(',', $_GET[ $name ]);
        
        
        // append meta query
        $meta_query[] = array(
            'key'       => $name,
            'value'     => $value,
            'compare'   => 'IN',
        );
        
    } 
    
    
    // update meta query
    $query->set('meta_query', $meta_query);

}

This snippet of code is used within a template file that is shown on the archive page for your post type.

archive-property.php

<div id="archive-filters">
<?php foreach( $GLOBALS['my_query_filters'] as $key => $name ): 
    
    // get the field's settings without attempting to load a value
    $field = get_field_object($key, false, false);
    
    
    // set value if available
    if( isset($_GET[ $name ]) ) {
        
        $field['value'] = explode(',', $_GET[ $name ]);
        
    }
    
    
    // create filter
    ?>
    <div class="filter" data-filter="<?php echo $name; ?>">
        <?php create_field( $field ); ?>
    </div>
    
<?php endforeach; ?>
</div>

<script type="text/javascript">
(function($) {
    
    // change
    $('#archive-filters').on('change', 'input[type="checkbox"]', function(){

        // vars
        var url = '<?php echo home_url('property'); ?>';
            args = {};
            
        
        // loop over filters
        $('#archive-filters .filter').each(function(){
            
            // vars
            var filter = $(this).data('filter'),
                vals = [];
            
            
            // find checked inputs
            $(this).find('input:checked').each(function(){
    
                vals.push( $(this).val() );
    
            });
            
            
            // append to args
            args[ filter ] = vals.join(',');
            
        });
        
        
        // update url
        url += '?';
        
        
        // loop over args
        $.each(args, function( name, value ){
            
            url += name + '=' + value + '&';
            
        });
        
        
        // remove last &
        url = url.slice(0, -1);
        
        
        // reload page
        window.location.replace( url );
        

    });

})(jQuery);
</script>

Related