Получить список годов, когда были опубликованы записи
Я хочу создать список записей из произвольного типа записи (Custom Post Type) и добавить фильтры, по которым пользователь сможет фильтровать этот список.
Я добавил фильтры для всех категорий, используя функцию get_terms(). Теперь я хочу добавить фильтры по годам, поэтому мне нужен способ получить список всех годов, в которых была опубликована хотя бы одна запись...
Мне нужно что-то вроде:
$years = get_all_years_with_posts();
// возвращает array( 2011, 2013, 2014 )
Я знаю, что могу получить все записи, проверить их год публикации и вручную построить список, но нет ли другого способа?
Ваш вопрос довольно старый, но я хотел бы добавить реальное решение. Вот функция, которая вернёт массив годов, в которые у вас были опубликованы записи. Вы можете поместить эту функцию в файл functions.php или в плагин — как вам удобно.
function get_posts_years_array() {
global $wpdb;
$result = array();
$years = $wpdb->get_results(
$wpdb->prepare(
"SELECT YEAR(post_date) FROM {$wpdb->posts} WHERE post_status = 'publish' GROUP BY YEAR(post_date) DESC"
),
ARRAY_N
);
if ( is_array( $years ) && count( $years ) > 0 ) {
foreach ( $years as $year ) {
$result[] = $year[0];
}
}
return $result;
}
Для пользовательских типов записей потребуется небольшая модификация — просто добавьте AND wp_posts.post_type = 'my_cpt'
в соответствующий участок запроса.

Мне потребовалось немного его доработать. Кажется, prepare() требует указания хотя бы одного аргумента формата %s (см. https://wordpress.stackexchange.com/a/270970/11914). Но решение сработало, я поставил плюс.

@idleberg Потому что на момент публикации моего ответа другой участник неправильно понял вопрос. Он привёл пример получения всех записей, отсортированных по году, но автор вопроса хотел получить список годов, в которых есть записи.

Это работает, однако, запрос получает все записи без учета их типа — убедитесь, что применяете фильтр по типу записи (WHERE post_type = 'posts'), иначе запрос вернет также и страницы.

При включенном режиме отладки этот код вызывает уведомление 'Аргумент запроса в wpdb::prepare() должен содержать плейсхолдер'. Пожалуйста, отредактируйте этот ответ, добавив плейсхолдеры.

Вы можете использовать эту функцию, чтобы получить все года записей в виде массива, который затем можно использовать в цикле.
$terms_year = array(
'post_type' => array('ВАШ_ПОЛЬЗОВАТЕЛЬСКИЙ_ТИП_ЗАПИСИ'),
);
$years = array();
$query_year = new WP_Query( $terms_year );
if ( $query_year->have_posts() ) :
while ( $query_year->have_posts() ) : $query_year->the_post();
$year = get_the_date('Y');
if(!in_array($year, $years)){
$years[] = $year;
}
endwhile;
wp_reset_postdata();
endif;
// Вывод годов там, где вам нужно
echo '<pre>';
print_r($years);
echo '</pre>';

Вы можете использовать функцию WP и шорткод следующим образом:
add_shortcode( 'archives', '_get_archived_posts' );
function _get_archived_posts( $atts ) {
$a = shortcode_atts( array(
'type' => 'yearly',
'limit' => '',
'format' => '',
'before' => '',
'after' => '',
'show_post_count' => false,
'echo' => 0,
'order' => 'DESC'
), $atts, 'filter_archives_sc' );
return wp_get_archives($a);
}

// Получить все года публикации записей;
function get_posts_years_array($post_type = 'post') {
global $wpdb;
$result = array();
$query_prepare = $wpdb->prepare("SELECT YEAR(post_date) FROM ($wpdb->posts) WHERE post_status = 'publish' AND post_type = %s GROUP BY YEAR(post_date) DESC", $post_type);
$years = $wpdb->get_results($query_prepare);
if ( is_array( $years ) && count( $years ) > 0 ) {
foreach ( $years as $year ) {
$result[] = json_decode(json_encode($year), true);
}
}
return $result;
}

Я взял решение от @Gavin и улучшил его, добавив поддержку любых типов записей и любых статусов:
/**
* Получить массив доступных годов для любого типа записей с любыми статусами
* @see https://wordpress.stackexchange.com/a/273627/18713
*/
private function get_years_with_posts(
string $post_type = 'post',
array $post_stati = ['publish']
): array {
/** @var wpdb $wpdb */
global $wpdb;
/** Конвертируем массив $post_stati в эквивалент MySql IN */
$post_status_in = "('" . implode("', '", array_map('esc_sql', $post_stati)) . "')";
/** Подготавливаем запрос с выбранным типом записи */
$query = $wpdb->prepare(
"SELECT YEAR(post_date)
FROM {$wpdb->posts}
WHERE post_status IN $post_status_in
AND post_type = %s
GROUP BY YEAR(post_date) DESC",
$post_type
);
$years = $wpdb->get_results($query, ARRAY_N);
return array_column($years, 0);
}
Пример использования: Получить все опубликованные и запланированные записи типа event
:
$available_years = get_years_with_posts('event', ['publish', 'future']);
