Разработка запасного варианта для пустых результатов wp_query на основе дат публикации

Вопрос или проблема

Я пытаюсь настроить “резервный” запрос для wp_query. Я хочу получить первый пост, которому ровно год, но если такого не существует, получить первый пост, которому один год и один день. И я хочу сохранить этот HTML в поле Advanced Custom Field on_this_day_1_year_ago (для повышения эффективности базы данных).

Первый пример кода работает для первого поста, которому год, и сохраняет HTML в поле on_this_day_1_year_ago.

Второй пример кода с резервным запросом к посту, которому год и один день, не работает и не выдает никаких ошибок PHP. Что в нем не так?

Я знаю, что мой код со strtotime неряшливый, и вся эта функция требует больших затрат для базы данных.

Это то, с чего я начал; wp_query для поста, которому 1 год, и это работает.

$one_year_ago = date('Y-m-d', strtotime('-1 year'));

$args = array(
      'post_type' => 'post',  
      'posts_per_page' => 1,
      'post_status' => 'publish',
      'orderby' => 'date',
      'order' => 'DESC',
      'date_query' => array(
            array(
                'year'  => date('Y', strtotime($one_year_ago)),
                'month' => date('m', strtotime($one_year_ago)),
                'day'   => date('d', strtotime($one_year_ago)),
            ),
       ),
 );
$query = new WP_Query( $args ); 

ob_start();

    while( $query->have_posts() ) {
        $query->the_post();

        echo '<a href="' . get_permalink() '">';    
        the_title();
        echo '</a>';
    }
        endwhile;
        wp_reset_postdata();

$this_day_one_year_ago = ob_get_clean();

// Сохранение в пользовательское поле ACF
update_field('on_this_day_1_year_ago', $this_day_one_year_ago, 'option');

Это объединенный запрос с резервным вариантом к посту, которому один год и один день, который не работает. Есть идеи?

date_default_timezone_set('America/Chicago');
$one_year_ago = date('Y-m-d', strtotime('-1 year'));
$one_year_ago_plus_day = date('Y-m-d', strtotime('-367 days'));


function output_posts( $query ){

// получение вывода для сохранения в поле Advanced Custom Field

ob_start();

    while( $query->have_posts() ) {
        $query->the_post();

        echo '<a href="' . get_permalink() '">';    
        the_title();
        echo '</a>';
    }

    wp_reset_postdata();   

$this_day_one_year_ago = ob_get_clean();

// сохранить в пользовательское поле

update_field('on_this_day_1_year_ago', $this_day_one_year_ago, 'option');

}

// аргументы для 1 года назад

$args = array(
      'post_type' => 'post',  
      'posts_per_page' => 1,
      'post_status' => 'publish',
      'orderby' => 'date',
      'order' => 'DESC',
      'date_query' => array(
           array(
           'year'  => date('Y', strtotime($one_year_ago)),
           'month' => date('m', strtotime($one_year_ago)),
           'day'   => date('d', strtotime($one_year_ago)),
            ),
       ),
);

$query = new WP_Query( $args );

// Если в запросе есть посты

if( $query->have_posts() ) {

    output_posts( $query );    


// или резервный вариант на -367 дней

} else {

    // аргументы для 1 года и 1 дня назад

    $args = array(
        'post_type' => 'post',  
        'posts_per_page' => 1,
        'post_status' => 'publish',
        'orderby' => 'date',
        'order' => 'DESC',
        'date_query' => array(
         array(
        'year'  => date('Y', strtotime($one_year_ago_plus_day)),
        'month' => date('m', strtotime($one_year_ago_plus_day)),
        'day'   => date('d', strtotime($one_year_ago_plus_day)),
            ),
       ),
);

    $fallback = new WP_Query( $args );

    if ( $fallback->have_posts() ){

        output_posts( $fallback );       
    }
} 

PHP strtotime() принимает некоторые странные строковые значения, которые мы можем использовать в комбинации с ключевым словом ‘before’ в WP_Query date_query. Например, мы можем получить X постов до 1 года назад со следующего дня:

$tomorrow_a_year_ago = wp_date( 'Y-m-d', strtotime( '-1 year +1 day' ) );
$args = array(
    'post_type'     => 'post',
    'posts_per_page'    => 5,
    'post_status'       => 'publish',
    'orderby'           => 'date',
    'order'         => 'DESC',
    'date_query'        => array(
            array(
                'before' => $tomorrow_a_year_ago, // Равен или меньше
            ),
        ),
);
$query = new WP_Query( $args );

Пока есть хотя бы 1 пост до (или в) даты год назад, вы получите какой-либо результат. WP_Query создаст следующее SQL условие:

wp_posts.post_date < '2024-01-18 00:00:00'

Так как мы запрашиваем все посты до определенной даты, может случиться так, что следующий пост на самом деле старше года и месяца, или даже старше, если публикация происходит неравномерно в течение года. Следующий кодовый сниппет гарантирует, что следующий найденный пост будет старше, максимум, на 1 год и 7 дней, но не больше.

$days_ago_limit     = -7; // 7 дней назад
$post_to_display    = null;

foreach( $query->posts as $post ) {

    // Создание объекта DateTime на основе разницы между 2 датами.
    $dateDiff = date_diff(
        date_create( $tomorrow_a_year_ago ), // Объект DateTime
        date_create( $post->post_date )      // Объект DateTime
    );

    // Удаление положительного символа, оставление отрицательного.
    $day_diff = (int)ltrim( $dateDiff->format( '%R%a' ), '+' ); // %R = +/- | %a = [0-9]

    // Если day_diff находится между сегодня и X дней назад.
    if( $day_diff <= 0 && $day_diff >= $days_ago_limit ) {
        $post_to_display = $post;
        break; // Прерывание цикла
    }

}

// У нас есть пост для отображения...
if( $post_to_display ) {
    // Делать что-то
}

Лично я бы не сохранял HTML в базе данных, а вместо этого сохранил бы данные. Это обеспечило бы большую гибкость. Допустим, клиент хочет изменить внешний вид вывода, ну, если вы уже сохранили вывод в базе данных, вам придется пересохранять вывод для X постов.

Вместо этого, если мы просто сохраним данные, мы можем позволить плагину/теме/шаблонам структурировать и стилизовать данные по мере необходимости. Я бы рекомендовал просто сохранить ID WP_Post, чтобы если клиент обновил пост по какой-либо причине, мы могли бы получить последние данные.

// У нас есть пост для отображения...
// Функция существует на случай, если нам нужно отключить ACF.
if( function_exists( 'update_field' ) && $post_to_display ) {
    update_field( 'on_this_day_1_year_ago', $post_to_display->ID, 'option' );
}

Тогда при выводе:

if( function_exists( 'get_field' ) {
    
    $ago_post_id = get_field( 'on_this_day_1_year_ago', 'option' );
    if( ! empty( $ago_post_id ) ) {
        
        // Перезаписываем глобальный $post, чтобы функции шаблона работали как ожидается.
        global $post;
        $post = get_post( $ago_post_id );
        setup_postdata( $post );
        
        printf( '<a href="%s">%s</a>', get_permalink(), get_the_title() );
        
        // Сбрасываем глобальный $post обратно в исходное состояние.
        wp_reset_postdata();
        
    }
    
}

.

Ответ или решение

Разработка резервного решения для пустых результатов wp_query, основанного на датах публикации постов в WordPress, представляет собой интересную задачу, которая требует тщательной разработки логики для корректного функционирования. Основная цель — это предоставление альтернативного результата, если изначальный запрос не возвращает результатов. В данном случае, если постов, опубликованных ровно год назад, не найдено, необходимо получить посты, опубликованные год и один день назад.

Теория

В основе резервного решения лежит концепция обработки данных и их корректной выборки с учетом временных меток. Функция wp_query позволяет фокусироваться на различных параметрах, включая типы постов, статус и дату публикации. В данной задаче ключевым элементом является date_query, который предоставляет возможность фильтрации постов по определенным временным параметрам.

Использование функции date_query в WordPress позволяет задать точные временные рамки для выборки постов. Однако, если у нас нет записей, соответствующих первой временной метке, необходимо осуществить второй запрос с изменёнными временными рамками, сохраняя принцип минимального изменения данного параметра (один дополнительный день).

Пример

Изначальная часть кода выполняет стандартный запрос для получения постов, опубликованных ровно год назад:

$one_year_ago = date('Y-m-d', strtotime('-1 year'));

$args = array(
      'post_type' => 'post',
      'posts_per_page' => 1,
      'post_status' => 'publish',
      'orderby' => 'date',
      'order' => 'DESC',
      'date_query' => array(
            array(
                'year'  => date('Y', strtotime($one_year_ago)),
                'month' => date('m', strtotime($one_year_ago)),
                'day'   => date('d', strtotime($one_year_ago)),
            ),
       ),
);
$query = new WP_Query($args);

ob_start();

while($query->have_posts()) {
    $query->the_post();
    echo '<a href="' . get_permalink() . '">';
    the_title();
    echo '</a>';
}
wp_reset_postdata();

$this_day_one_year_ago = ob_get_clean();
update_field('on_this_day_1_year_ago', $this_day_one_year_ago, 'option');

Однако, если результаты отсутствуют, ваш второй код пытается загрузить посты с новой временной меткой (год и один день назад), но это не работает корректно из-за возможных ошибок в реализации условий и повторного использования wp_query.

Применение

Для реализации корректной работы скрипта с использованием запроса с резервным решением, сначала убедитесь, что ваш первый запрос работает стабильно. Затем добавьте резервный запрос, если он не возвращает результатов:

date_default_timezone_set('America/Chicago');
$one_year_ago = date('Y-m-d', strtotime('-1 year'));
$one_year_ago_plus_day = date('Y-m-d', strtotime('-367 days'));

// Если первый запрос возвращает результаты
$args = array(
    'post_type' => 'post',
    'posts_per_page' => 1,
    'post_status' => 'publish',
    'orderby' => 'date',
    'order' => 'DESC',
    'date_query' => array(
        array(
            'year' => date('Y', strtotime($one_year_ago)),
            'month' => date('m', strtotime($one_year_ago)),
            'day' => date('d', strtotime($one_year_ago)),
        ),
    ),
);

$query = new WP_Query($args);

if ($query->have_posts()) {
    output_posts($query);
} else {
    // Второй запрос на посты с датой год и один день назад
    $args['date_query'] = array(
        array(
            'year' => date('Y', strtotime($one_year_ago_plus_day)),
            'month' => date('m', strtotime($one_year_ago_plus_day)),
            'day' => date('d', strtotime($one_year_ago_plus_day)),
        )
    );

    $fallback = new WP_Query($args);

    if ($fallback->have_posts()) {
        output_posts($fallback);
    }
}

Функция output_posts должна обрабатывать вывод и сохранять данные в Advanced Custom Field (ACF).

Сохранение данных в ACF, а не HTML, обеспечивает гибкость в будущем. Например, если понадобится изменить оформление, данные останутся неизменными — изменятся только шаблоны вывода.

Преимущества гибкого подхода

  1. Гибкость обновлений: Сохраняя только идентификатор поста, но не HTML, вы обеспечиваете возможность менять способ отображения без необходимости миграции данных.
  2. Оптимизация производительности: Упрощается логика выборки из базы, так как можно извлечь только необходимые поля.
  3. Готовность к изменениям: Если необходимо будет изменить стиль или формат вывода, это можно будет сделать, не затрагивая данные.

Итак, следуя указанным шагам, вы развиваете более гибкую и масштабируемую систему для обработки и вывода постов.ələri.

Оцените материал
Добавить комментарий

Капча загружается...