Хук add_action для абсолютно нового поста?

1 февр. 2011 г., 07:47:33
Просмотры: 43.1K
Голосов: 22

publish_post запускается, когда пост публикуется или когда он редактируется и его статус "опубликован". Аргументы функции действия: ID поста.

-Документация Plugin API

Я добавил хук publish_post в WordPress плагин, который я пишу. Функция, вызываемая хуком, должна изменять категории нескольких постов, используя функцию wp_update_post.

Однако этот хук не работает, так как результат выполнения wp_update_post всегда равен 0. Я предполагаю, что выполнение wp_update_post вызывает другой экземпляр моего хука, потому что он повторно публикует пост... что, я думаю, приводит к "...или если он редактируется и его статус "опубликован"" из утверждения выше.

Есть ли другой action-хук, который будет вызываться только тогда, когда добавляется совершенно новый пост, а не редактируется?

<?php
 /* 
 Plugin Name: Category Switcher Plugin
 Plugin URI: http://www.example.com
 Description: Когда создается новый пост, этот плагин вызовет 
 Version: 0.1
 Author: Me
 License: GPL2 
?>
<?php
class categoryShifter {
  function shiftCategories($post_ID) {

    $maxNumPostsFirstTeir = 4;

    $first_teir_cat = "Свежие новости 1";
    $second_teir_cat = "Устаревшие новости 2";  

    $firephp = FirePHP::getInstance(true);

    $firephp->info('НАЧАЛО: categoryShifter.shiftCategories()');

    $firephp->log($post_ID, 'post_ID: ');
    $firephp->trace('трассировка до этого места');    

    $first_teir_id = categoryShifter::getIDForCategory($first_teir_cat, $firephp); 
    $second_teir_id = categoryShifter::getIDForCategory($second_teir_cat, $firephp);

    $firephp->log($first_teir_id, '$first_teir_id');
    $firephp->log($second_teir_id, '$second_teir_id');   

    $qPostArgs = array(
      'numberposts' => 100,
      'order' => 'DESC', 
      'orderby' => 'post_date',
      'post_type' => 'post',
      'post_status' => 'published', 
      'category_name' => $first_teir_cat
    );

    $firstTeirPosts = get_posts($qPostArgs);   
    $firephp->log($firstTeirPosts, 'получены посты:');

    $firephp->log(sizeof($firstTeirPosts), 'размер');


    // ПРИМЕЧАНИЕ: Похоже, это работает.
    for($i = sizeof($firstTeirPosts)-1; $i > $maxNumPostsFirstTeir-4; $i--) 
    {
      $newCats = array($second_teir_id);
      $editingId = $firstTeirPosts->ID;
      $result = wp_set_post_categories($editingId, $newCats); /* ПРИМЕЧАНИЕ: В настоящее время не работает... возвращает массив с $second_teir_id в нем. */
      $firephp->log($result, 'Результат'); 
    }

    /*
    $my_post = array();
    $my_post['ID'] = 132;
    $my_post['post_category'] = array($second_teir_id);


    $firephp->log('До', 'До'); 
    if(wp_update_post( $my_post ) == 0) {
        $firephp->Error('Фатальная ошибка, Пост не обновлен', 'ошибка');
    }
    $firephp->log('После', 'После');
    */
    return $post_ID;
  }


  function getIDForCategory($cat_name, $logger) {
    $logger->Info("Начало: getIDForCategory()");

    $cats = get_categories();      

    $whichCatId = "";

    foreach($cats as $single_cat) {
      if($single_cat->name == $cat_name) {
       $whichCatId = $single_cat->term_id;
       break;
      }
    }
    $logger->Info("Конец: getIDForCategory()");
    return (int)$whichCatId;
  }
}

/* Хук создания поста */
/* add_action('publish_post', array('categoryShifter','shiftCategories')); */
add_action('wp_insert_post', array('categoryShifter', 'shiftCategories'));
?>

Я переключился на использование хука wp_insert_post на данный момент... но я всё ещё не могу заставить функцию wp_set_post_categories изменять категории постов.

Я понимаю, что мне, вероятно, нужно будет обновить этот код, чтобы он учитывал существующие категории поста и изменял только те, которые указаны в плагине, но пока это просто альфа-версия.

4
Комментарии

@leeand00 - Не могли бы вы опубликовать свой код как обновление к вашему ответу, чтобы мы могли лучше понять, что нужно исправить?

MikeSchinkel MikeSchinkel
1 февр. 2011 г. 07:49:24

@Mike Вот обновление!

leeand00 leeand00
1 февр. 2011 г. 08:12:22

@MikeSchinkel Иногда это просто потому, что у меня еще не было возможности проверить предложенные ответы, и я не хотел отмечать тот, который окажется неподходящим... но я вернусь и посмотрю, что можно сделать!

leeand00 leeand00
1 февр. 2011 г. 18:28:44

@MikeSchinkel Хорошо, я привел их в порядок и выбрал лучшие ответы, извините за это, я не осознавал, насколько запустил этот конкретный StackExchange.

leeand00 leeand00
1 февр. 2011 г. 18:34:37
Все ответы на вопрос 6
4
22
// Хук для новых записей при публикации
add_action('new_to_publish', 'your_function');
// Хук для черновиков при публикации
add_action('draft_to_publish', 'your_function');
// Хук для записей на модерации при публикации
add_action('pending_to_publish', 'your_function');
1 февр. 2011 г. 08:50:56
Комментарии

А что насчёт действия wp_insert_post? http://core.trac.wordpress.org/browser/tags/3.3.1/wp-includes/post.php#L2656

soulseekah soulseekah
23 мар. 2012 г. 11:56:58

Но будут ли они запускаться снова, если, например, статус изменится с опубликованного обратно на черновик, а затем снова на опубликованный?

brandonjp brandonjp
27 июл. 2019 г. 19:07:05

@soulseekah Хук wp_insert_post будет вызван снова при редактировании существующей записи и сохранении. Проверено на WordPress 5.9. Я знаю, что ваш комментарий от 2012 года, но на случай, если кому-то интересно.

vee vee
1 февр. 2022 г. 08:32:59

@vee, вероятно, черновики создаются при каждом сохранении.

soulseekah soulseekah
2 февр. 2022 г. 10:43:11
2
22

Я тщательно изучил ядро WordPress и перепробовал все возможные варианты. wp_transition_post_status(), new_to_publish(), new_{post_type}(), wp_insert_post().

Все эти методы, в конечном счете, ненадежны.

wp_transition_post_status() ненадежен, потому что новый статус "publish" является статусом по умолчанию как для создания новых записей, так и для обновления существующих. Старый статус также ненадежен для определения новой записи, так как он может быть draft, auto-draft, publish и т.д.

new_to_publish() не работает для пользовательских типов записей.

new_{post_type} передает только параметр $post, и невозможно определить, создается новая запись или обновляется существующая.

wp_insert_post() имеет параметр $update, который должен быть TRUE при обновлении существующих записей и FALSE при создании новых, но он ненадежен, так как возвращает TRUE для новых записей из-за auto-draft.

Решение: Использование метаполя записи

В итоге я использовал пользовательское метаполе, которое назвал check_if_run_once, чтобы выполнить некоторую логику только один раз:

/**
*   Выполнить действие при создании новой книги
*/
function new_book($post_id, $post, $update) {
    if ( $post->post_type == 'book' && $post->post_status == 'publish' && empty(get_post_meta($post_id, 'check_if_run_once')) ) {
        # Новая запись

        # Выполнить действия здесь...

        # Обновить метаполе, чтобы код не выполнялся повторно
        update_post_meta( $post_id, 'check_if_run_once', true );
    }
}
add_action( 'wp_insert_post', 'new_book', 10, 3 );

Дополнительно, если вам нужно обновить существующие записи метаполем "check_if_run_once", чтобы код выше не выполнялся для записей, созданных до добавления этой функции, можно сделать следующее:

/**
*   Временная функция для обновления существующих записей метаполем "check_if_run_once"
*   Для использования войдите на сайт как администратор и добавьте ?debug к URL.
*/
function temporary_function() {
    if (current_user_can('manage_options')) {
        $posts = get_posts(array(
            'post_type' => 'book',
            'posts_per_page' => -1, // Возможно, потребуется пагинация в зависимости от количества записей
            'fields' => 'ids'
        ));
        foreach($posts as $post_id) {
            update_post_meta($post_id, 'check_if_run_once', true);
        }
    }
}
if (isset($_GET['debug'])) {
    add_action('init', 'temporary_function');
}
30 июл. 2018 г. 03:50:24
Комментарии

Почему этот ответ не получил больше голосов и не был выбран как правильный? Принятый ответ ничего не объясняет и не учитывает, что люди часто используют это для CPT и т.д..

Bram Hammer Bram Hammer
8 июл. 2021 г. 21:00:47

Спасибо, чувак, реально. Вот это ответ!

Marco Floriano Marco Floriano
27 февр. 2024 г. 16:16:09
0

Точное отслеживание создания новой записи на самом деле сложнее, чем кажется. Технически существует несколько способов, которыми запись может быть создана или обновлена, а также множество не столь очевидных вещей, которые технически также являются записями (например, ревизии).

WordPress предоставляет динамические хуки, которые отслеживают не только создание записи, но и то, чем она была и чем стала. См. Переходы статусов записей в Кодексе.

1 февр. 2011 г. 08:51:01
4

Больше экспериментируя, чем следуя документации, я нашел рабочее решение (для WP 3.3). Хук transition_post_status срабатывает с параметром $new_status, установленным в "auto-draft", при создании нового поста.

function my_post_new($new_status, $old_status=null, $post=null){
    if ($new_status == "auto-draft"){
        // здесь выполняем нужные действия
    }
}
add_action('transition_post_status', 'my_post_new');
23 мар. 2012 г. 11:38:50
Комментарии

Это будет срабатывать каждый раз при сохранении авто-черновика, т.е. примерно каждую минуту во время редактирования.

soulseekah soulseekah
23 мар. 2012 г. 11:54:27

Верное замечание. В моем случае это не проблема, но для других может быть важно, в зависимости от того, что вы делаете.

PapaFreud PapaFreud
23 мар. 2012 г. 12:50:24

хотел проголосовать за, но пока не могу. так что респект тут, @PapaFreud. кстати, теперь это задокументировано на http://codex.wordpress.org/Post_Status_Transitions. еще раз, спасибо, чувак

Ana Ban Ana Ban
22 мая 2012 г. 15:30:02

@soulseekah Интересный момент, который ты поднял. Я проверил это, и статус auto-draft присваивается как $new_status записи при её создании (т.е. при нажатии "Добавить новую"), только один раз. Как только срабатывает первая процедура AUTOSAVE через 1 минуту, значение $new_status обновляется до draft. $old_status остаётся NULL до тех пор, пока запись не будет сохранена вручную или опубликована. Так что технически это будет работать и не срабатывать каждый раз, когда редактор автоматически сохраняет вашу работу. В качестве дополнительной меры вы можете проверить, что $old_status равен NULL, чтобы убедиться -> if ($new_status == "auto-draft" && $old_status === NULL)

Adam Adam
22 мая 2013 г. 16:57:23
0

Я обнаружил, что лучшим вариантом будет проверять статус записи при вызове wp_insert_post.

Когда создаётся новая запись, её первоначальный статус — auto-draft.

if (!function_exists('benyonsFunction')) {
    function benyonsFunction($postId, $post) {
        if ($post->post_status == "auto-draft") {
            error_log('НОВАЯ ЗАПИСЬ!!!');
        }
    }
}

add_action('wp_insert_post', 'benyonsFunction', 10, 2);

Этот error_log сработает только один раз.

5 февр. 2020 г. 11:49:20
2

Наиболее чистый и надежный способ обработки этого для известного типа записи - использовать хук {$new_status}_{$post->post_type}, который предоставляет старый статус и сравнить его с "publish".

Например, если вы хотите выполнить действие при создании новой "страницы", вы должны использовать:

add_action( 'publish_page', function( int $post_id, \WP_Post $post, string $old_status ) {
    if ( 'publish' === $old_status ) {
        // Ничего делать не нужно.
        return;
    }
    // Здесь размещается бизнес-логика.
}, 10, 3 );
18 февр. 2023 г. 00:46:36
Комментарии

Нет, это будет срабатывать каждый раз, когда страница переходит из любого статуса в 'publish', поэтому это будет происходить гораздо чаще, чем только при первом создании.

Christophvh Christophvh
31 мар. 2023 г. 16:42:18

Почему ваша страница переходит в статус "publish" более одного раза? После публикации страница становится доступной, и её статус обычно не меняется, если только вы не перемещаете её в "trash" для удаления с сайта.

Mat Lipe Mat Lipe
1 апр. 2023 г. 17:59:21