The code below will loop through everywhere year and check to see if each month has posts. If so, it will add a link to the month. If not, it will just print the month without a link. You will need to edit the actual link as I am not sure about your websites’ permalink structure.
//Grab the earliest year available
$yearliest_year = $wpdb->get_results(
"SELECT YEAR(post_date) AS year
FROM $wpdb->posts
WHERE post_status="publish"
AND post_type="post"
ORDER BY post_date
ASC LIMIT 1
");
//If there are any posts
if($yearliest_year){
//This year
$this_year = date('Y');
//Setup months
$months = array(1 => "January", 2 => "February", 3 => "March" , 4 => "April", 5 => "May", 6 => "June", 7 => "July", 8 => "August", 9 => "September", 10 => "October", 11 => "November", 12 => "December");
$current_year = $yearliest_year[0]->year;
//Loop through every year and check each monnth of each year for posts
while($current_year <= $this_year){
echo "<h3>" . $current_year . "</h3>";
echo "<ul>";
foreach($months as $month_num => $month){
//Checks to see if a month a has posts
if($search_month = $wpdb->query(
"SELECT MONTHNAME(post_date) as month
FROM $wpdb->posts
WHERE MONTHNAME(post_date) = '$month'
AND YEAR(post_date) = $current_year
AND post_type="post"
AND post_status="publish"
LIMIT 1
")){
//Month has post -> link it
echo "<li>
<a href="" . get_bloginfo("url') . "https://wordpress.stackexchange.com/" . $current_year . "https://wordpress.stackexchange.com/" . $month_num . "https://wordpress.stackexchange.com/"><span class="archive-month">" . $month . "</span></a>
</li>";
}else{
//Month does not have post -> just print it
echo "<li>
<span class="archive-month">" . $month . "</span>
</li>";
}
}
echo "</ul>";
$current_year++;
}
}else{
echo "No Posts Found.";
}