2

I am using the default widget in my sidebar Archive which currently displays the archive this way:

Mar 2018
Feb 2018
Jan 2018

However, I'd like it to display this way:

2018
March
February
January

2017
December
November
October

Where the months are links. How do I achieve that? What do I do to my sidebar.php file?

1
  • If you look at the source code of the archive widget you will see that there is a hardcoded single <ul>, making it impossible to split the archive into two loops. Also there is no option to filter the output of wp_get_archives. What you want can certainly be done, but not with the default archives widget.
    – cjbj
    May 3, 2018 at 9:42

2 Answers 2

3
+50

Changing the default widget would be pretty complicated.

However, you can write your own shortcode and function to get your desired list.

I'm guessing you want an unordered list in your widget?

Put this in your theme's functions.php:

add_shortcode('archive_by_year_and_month','get_archive_by_year_and_month');

function get_archive_by_year_and_month($atts=array()){
    global $wpdb;
    $years = $wpdb->get_col("SELECT DISTINCT YEAR(post_date) FROM $wpdb->posts WHERE post_type = 'post' AND post_status = 'publish' ORDER BY post_date DESC");
    if($years){
        $rueckgabe = '<ul>';
        foreach($years as $year){
            $rueckgabe.='<li class="jahr"><a href="'.get_year_link($year).'">'.$year.'</a>';
            $rueckgabe.='<ul class="monthlist">';
            $months = $wpdb->get_col($wpdb->prepare("SELECT DISTINCT MONTH(post_date) FROM $wpdb->posts WHERE post_type='post' AND post_status='publish' AND YEAR(post_date) = %d ORDER BY post_date ASC",$year));
            foreach($months as $month){
                $dateObj   = DateTime::createFromFormat('!m', $month);
                $monthName = $dateObj->format('F'); 
                $rueckgabe.='<li class="month"><a href="'.get_month_link($year,$month).'">'.$monthName.'</a></li>';
            }
            $rueckgabe.='</ul>';
            $rueckgabe.='</li>';
        }
        $rueckgabe.='</ul>';
    }
    return $rueckgabe;
}

Then put a Text-Widget into your sidebar and enter the shortcode:

[archive_by_year_and_month]

Hit save and voila: You should get your list as you desired.

Happy Coding!

1
  • This was ok. It was just that the names of the months did not translate to local language in our case for some reason. Anyways we found another solution in here: wpbeginner.com/wp-themes/…
    – Webninja
    Oct 2, 2018 at 10:18
1

I'm afraid, it would be pretty hard to modify the output of original widget. It uses wp_get_archives function to print the archive and there is no easy way to modify this output. You could try to use get_archives_link, but it can get a little bit messy.

Saying that... There is other, much simpler way - writing your own widget.

class WP_Widget_ArchivesByYear extends WP_Widget {

    public function __construct() {
        $widget_ops = array(
            'classname' => 'widget_archive_by_year',
            'description' => __( 'A monthly archive of your site&#8217;s Posts displayed by year.' ),
            'customize_selective_refresh' => true,
        );
        parent::__construct('archives_by_year', __('Archives by Year'), $widget_ops);
    }

    public function widget( $args, $instance ) {
        global $wpdb;

        $title = apply_filters( 'widget_title', empty( $instance['title'] ) ? __( 'Archives' ) : $instance['title'], $instance, $this->id_base );

        echo $args['before_widget'];
        if ( $title ) {
            echo $args['before_title'] . $title . $args['after_title'];
        }

        $years = $wpdb->get_col("SELECT DISTINCT YEAR(post_date) FROM {$wpdb->posts} WHERE post_type = 'post' AND post_status = 'publish' ORDER BY post_date DESC");

        if ( $years ) :
        ?>
            <ul class="years-list">
                <?php
                    foreach ( $years as $year ) : 
                        $months = $wpdb->get_col( $wpdb->prepare("SELECT DISTINCT MONTH(post_date) FROM {$wpdb->posts} WHERE post_type='post' AND post_status='publish' AND YEAR(post_date) = %d ORDER BY post_date ASC", $year));
                ?>
                    <li class="year">
                        <a href="<?php echo get_year_link($year); ?>"><?php echo $year ?></a>
                        <ul class="months-list">
                            <?php
                                foreach ( $months as $month ) :
                                    $dateObj = DateTime::createFromFormat('!m', $month);
                            ?>
                                <li class="month">
                                    <a href="<?php echo get_month_link($year, $month); ?>"><?php echo $dateObj->format('F'); ?></a>
                                </li>
                            <?php endforeach; ?>
                        </ul>
                    </li>
                <?php endforeach; ?>        
            </ul>
        <?php
        endif;

        echo $args['after_widget'];
    }

    public function update( $new_instance, $old_instance ) {
        $instance = $old_instance;
        $new_instance = wp_parse_args( (array) $new_instance, array( 'title' => '') );
        $instance['title'] = sanitize_text_field( $new_instance['title'] );

        return $instance;
    }


    public function form( $instance ) {
        $instance = wp_parse_args( (array) $instance, array( 'title' => '') );
        $title = sanitize_text_field( $instance['title'] );
        ?>
        <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($title); ?>" /></p>
        <?php
    }
}

PS. I haven't tested that code, so it can contain some typos.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.