Create side bar widget showing list of years as hyperlinks for a custom post type

First, create the custom WordPress widget. This will query all the years that have at least one post for your custom post type “Meeting.” Save the following code in your theme’s functions.php file:

class Meeting_Archive_Widget extends WP_Widget {

    public function __construct() {
        parent::__construct('meeting_archive', 'Meeting Archive', array('description' => 'List Meetings by Year'));
    }

    public function widget($args, $instance) {
        global $wpdb;
        $query = "SELECT YEAR(post_date) AS `year` FROM $wpdb->posts WHERE post_type="meeting" AND post_status="publish" GROUP BY `year` ORDER BY post_date DESC";
        $years = $wpdb->get_results($query);
        
        echo $args['before_widget'];
        echo $args['before_title'] . 'Meeting Archives' . $args['after_title'];

        echo '<ul>';
        foreach ($years as $year) {
            echo '<li><a href="' . get_post_type_archive_link('meeting') . '?year=" . $year->year . "">' . $year->year . '</a></li>';
        }
        echo '</ul>';

        echo $args['after_widget'];
    }
}

add_action('widgets_init', function(){
    register_widget('Meeting_Archive_Widget');
});

Next, modify the main Meetings query on your archive page to account for the year URL parameter. You could add this code also in your functions.php:

add_action('pre_get_posts', function($query){
    if (!is_admin() && $query->is_main_query() && is_post_type_archive('meeting')) {
        if (isset($_GET['year'])) {
            $query->set('year', $_GET['year']);
        }
    }
});

What this does is look for the year parameter in the URL and filters the meetings post type displayed based on that year.

And that’s it! I haven’t tested the code but in theory that should do the trick for you. If you encounter some issues just adjust the code accordingly.