User filter posts by year

Here is a solution I came up with. There are several ways to make this work. Please feel free to reply with any suggestions.

  1. Create a shortcode to generate the select drop down menu in your theme/functions.php file. The drop down menu form element has javascript to redirect the user to /?Year=value for whatever year was selected.
<?php

/*
 *
 * Create a Year select drop down menu
 * Usage: [year_select min_year="2000" max_year="2022"]
 *
 */
function year_select_shortcode( $atts = array() ) {
        // set up default parameters
        extract(shortcode_atts(array(
                'min_year' => '2000',
                'max_year' => date("Y"),
                'base_dir' => '/custom_archive/'
        ), $atts));

        // Convert arguments to integers, make sure they fit in acceptable ranges
        $min_year = (int)$min_year;
        $max_year = (int)$max_year;
        $select_year = (int)$_GET['Year'];

        if ( $min_year < 1980 ) $min_year = 1980;
        if ( $max_year > date("Y") ) $max_year = date("Y");
        if ( $select_year < $min_year or $select_year > $max_year) $select_year = 0;

        // select drop down has some javascript to re-direct the user
        $output .= '<select name="Year" id="Year" onchange="if (this.value) window.location.href=this.value">\n';
        $output .= '<option value="' . $base_dir . '"';
        if ( $select_year == 0 ) $output .= ' selected="selected"';
        $output .= '>All</option>\n';

        // Loop through year range and add a select option
        for ( $i = $max_year; $i >= $min_year; $i-- ) {
                $output .= '<option value="' . $base_dir . '?Year=" . $i . ""';
                if ( $i == $select_year ) $output .= ' selected="selected"';
                $output .= '>' . $i . '</option>\n';
        }
        $output .= '</select>';
        return $output;
}
add_shortcode( 'year_select', 'year_select_shortcode');

?>
  1. Add to functions.php a custom query to work with the data from the select short code defined above. The query will look for the $_GET[‘Year’] variable, and filter out the posts that pertain to that year. For my purposes, the year variable is compared against a custom date field so need to build a meta query.
<?php

add_action( 'elementor/query/custom_archive_query', function( $query ) {
        // Make sure input year is in the right range
        $select_year = (int)$_GET['Year'];
        if ( $select_year < 1980 ) $select_year = 0;
        if ( $select_year > date("Y") ) $select_year = date("Y");

        // Get current meta Query
        $meta_query = $query->get( 'meta_query' );
        // If there is no meta query when this filter runs, it should be initialized as an empty array.
        if ( ! $meta_query ) {
                $meta_query = [];
        }

        // Restrict to cartoon post types
        $query->set( 'post_type', 'custom_archive' );

        // Append our meta query
        if($select_year > 0){
                $meta_query[] = [
                        'key' => 'custom_archive',
                        'value' => $select_year,
                        'compare' => 'like',
                ];
                $query->set( 'meta_query', $meta_query);
        }
        wp_reset_postdata();
});
?>
  1. Enter custom_archive_query into the elementor posts Query ID field and voila: the user selects a date from the drop down menu, gets re-directed to a url with a $_GET[‘Year’] parameter set which gets built into the posts query.

Hope this helps someone else.