Модификация post.php

Добрый день!
Мне нужно внести модификацию в файл post.php следующего вида:

сразу после сохранении в БД содержимого нового поста (только строго с post_status = publish, а не inherit) нужно отправлять запрос вида INSERT к собственной кастомной таблице (на добавление ID сохраненного поста).

Собственно, как реализовать непосредственно добавление в кастомную таблицу – тут проблем нет.

Вопроса два:

1. В какую часть post.php следует поместить модификационный код? Я полагаю что в ф-ю wp_insert_post и если да, то куда именно?
2. Как сделать так, чтобы он срабатывал только для post_status = publish?

Я использую WP 2.7.1

Буду раз за помощь или советы!

1. Ни в какую. Ищите в Кодексе Plugins API хук wp_insert_post или что-то в этом роде.
2. Проверять post_status.

в неправильном направлении идешь (вроде)

запрос на сохранение поста реализуется в файле wp-includes/query.php
ищи там что-то вроде
$data = compact(…);
и $wpdb->insert($data)

точно не помню…

PS: респект тем, кто "ковыряет" ВП, а не ставит готовые плагины!

Юрий, не уверен на 100%, никогда не писал и не использовал хуки.
Такой вариант кода подойдёт?

add_action(‘wp_insert_post’,’wp_insert_post_hook’);

function wp_insert_post_hook($post)
{
if ( $post->post_status == ‘publish’)
{
// Код для добавления записи в БД
}

}

Где-то так. Хотя я не уверен в передаче параметров. Проверьте это место тщательно.

Юрий, если вас не затруднит, можете меня немного просвятить в вопросах:

1. куда (в какое место) post.php следует вставить этот код? если не в этот скрипт то куда?
2. нужно ли как-то инициировать и вызывать хук или же add_action сам выполнит всё что необходимо в нужное время?

1. Такие штучки вставляют либо в functions.php Темы, либо в оформляют как плагины. В Вашем случае, насколько я понимаю, это больше похоже на плагин, чем на довесок к шаблону. Ничего военного в плагинах нет, несколько строк в начале скрипта – и просто скрипт превращается в настоящий плагин. Туда же можно поместить создание доп таблицы, задействовав register_activation_hook. Согласитесь, это цивильней, чем каждый раз создавать таблицу через phpmyadmin (предвидя возражения: "никогда не говори никогда":))

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

PS Если б кто знал, как у меня поначалу чесались руки залезть в движок и покрутить там что-нибудь "отверткой" (привычка – страшная сила). Но когда я вник в суть API WordPress, я понял, сколь убоги движки, не имеющие API.

Юрий, спасибо за информацию! Теперь стало по-прозрачней 🙂

Собственно, плагин получился такой:

<?
/*
Plugin Name: Insert Row into Custom DB table
Description: Insert row into custom table after inserting post
Author: Sergej
Version: 1.0
*/

add_action(‘wp_insert_post’,’wp_insert_post_hook’);

function wp_insert_post_hook($post_ID)
{
if ($post_status == ‘publish’)
{
// Код для добавления записи в БД
}

}

?>

Параметр функции посмотрел, нужно $post_ID передавать.

К вашему пояснению по п.2: "Код, размещенный в активированном плагине, выполняется при инициализации движка. Следовательно, размещенный там add_action пропишет свою подопечную функцию в список обработчиков, и как только выполнение дойдет до нужного хука, будет вызвана указанная функция."

То есть, правильно ли я понял, что для моей задачи – при публикации нового поста сначала сработает системная ф-я wp_insert_post и только потом отработает хук? Именно в такой последовательности?

И еще…я не совсем уверен в том будет ли видна переменная $post_status в моей функции. Может быть стоит сделать ее глобальной?

Я делаю так: нахожу в движке функцию, к которой хотелось бы прицепиться (далеко не всегда с первого раза нахожу, надо признать), и смотрю в ней все do_action и apply_filters. После такой процедуры становится ясно, что когда выполняется и где удобнее перехватить. Посмотрите post.php, найдете еще парочку хуков. В ответственных местах разработчик часто ставит хук "до" и "после".

Я совсем уверен, что $post_status не будет видна. Это значение, судя по всему, придется выколупывать из объекта $post, который в свою очередь или получать через global $post, или из параметров, коих, к слову, у этого хука два. Для доступа ко всем параметрам, а не только к первому, используется полный вызов add_action (см. Кодекс)

Юрий, плагин заработал (после соотвествующей активизации).

Вот основной кусок кода:

add_action(‘wp_insert_post’,’wp_insert_post_hook’);

function wp_insert_post_hook($post_ID)
{
global $post;

if ($post->post_status == ‘publish’)
{
// добавление записи в дополнительную таблицу
$query = "INSERT INTO temp_table (PostID) values (‘".$post_ID."’)";
$result = mysql_query($query);
}
}

Все бы хорошо, вот только вместо того, чтобы вставлять в собственную таблицу строку при post_status == ‘publish’ (то есть 1 раз, как необходимо), сейчас плагин вставляет строку дважды:

а) при post_status == ‘publish’
б) и при post_status == ‘inherit’ (то есть в случае, когда сохраняется ревизия)

При этом, до вставки данных в БД я проверил – переменная $post глобальная, она видна в моей функции. Я затрудняюсь понять почему происходит вставка в БД post_status == ‘inherit’ – ведь в условии четко указана проверка…

Можете подсказать в чём может быть затык/ошибка?

UPD: Попробовал решить задачу с другой стороны, а именно отключить создание ревижинов.

1. в wp-config.php выставил define( ‘AUTOSAVE_INTERVAL’, 60 ); и define(‘WP_POST_REVISIONS’, 0); (т.е. отключил их) – не помогло, ревижины не отключились и продолжают создаваться при публикации нового поста

2. после этого поставил плагин Revision Control (http://dd32.id.au/wordpress-plugins/revision-control/) и через него глобально запретил создание ревижинов дла постов. Тоже не помогло – ревижины не отключились.

В файлы WP я не вносил изменений. Собственно, сталкивался ли кто-нибудь с подобными глюками? Как их лечить?

Может глобальная $post в данном случае отличается от той, что передается вторым параметром? Тогда нельзя использовать global $post, нужно брать параметр. Поставьте в свою функцию print_r($post), посмотрите, что там в объекте.

function wp_insert_post_hook($post_ID)
{
global $post;

echo "<pre>";
print_r($post);
echo "</pre>";
exit;
}

После публикации тестового поста получил следующее содержимое объекта:

stdClass Object
(
[ID] => 120
[post_author] => 1
[post_date] => 2009-03-02 11:05:24
[post_date_gmt] => 2009-03-02 08:05:24
[post_content] => Test post publishing
[post_category] => 0
[post_excerpt] =>
[post_status] => publish
[comment_status] => open
[ping_status] => open
[post_password] =>
[post_name] => test=post-112
[to_ping] =>
[pinged] =>
[post_modified] => 2009-03-02 11:05:24
[post_modified_gmt] => 2009-03-02 08:05:24
[post_content_filtered] =>
[post_parent] => 0
[guid] => http://localhost/test=post-112/
[menu_order] => 0
[post_type] => post
[post_mime_type] =>
[comment_count] => 0
[ancestors] => Array
(
)
)

Насколько я вижу в post_status лежит "publish"

Итак, смотрим post.php:

    do_action('wp_insert_post', $post_id, $post);

Видим два параметра, второй – $post. Судя по всему, он-то нам и нужен.

Смотрим http://codex.wordpress.org/Plugin_API

Hook to WordPress

After your function is defined, the next step is to "hook" or register it with WordPress. To do this, call add_action() in the global execution space of your plugin file:

 add_action ( 'hook_name', 'your_function_name', [priority], [accepted_args] );

== cut ==

accepted_args is an optional integer argument defining how many arguments your function can accept (default 1), useful because some hooks can pass more than one argument to your function. This parameter is new in release 1.5.1.

Пишем так:

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

function wp_insert_post_hook($post_ID, $post)
{
 
print_r($post); return; // DEBUG

  if ($post->post_status == 'publish')

== cut ==

}

и смотрим, что получилось.

У меня в таком написании "print_r($post); return;" не выводится на экран содержимое объекта (на странице создания поста), хотя по идее должен был вывести в области TinyMSI редактора.

При такой записи:

print_r($post);
exit;

вывелось следующее содержимое объекта:

stdClass Object
(
[ID] => 124
[post_author] => 1
[post_date] => 2009-03-02 12:04:00
[post_date_gmt] => 2009-03-02 09:04:00
[post_content] => Test post publishing
[post_title] => Test post title
[post_category] => 0
[post_excerpt] =>
[post_status] => publish
[comment_status] => open
[ping_status] => open
[post_password] =>
[post_name] => test-post-124
[to_ping] =>
[pinged] =>
[post_modified] => 2009-03-02 12:04:00
[post_modified_gmt] => 2009-03-02 09:04:00
[post_content_filtered] =>
[post_parent] => 0
[guid] =>
[menu_order] => 0
[post_type] => post
[post_mime_type] =>
[comment_count] => 0
[ancestors] => Array
(
)
)

Тут же интересно, будут или нет ловиться ревизии, насколько я понимаю.

Юрий, сейчас проверю, отпишусь по результатам!

Все сработало, ревизии ловятся! В кастомную таблицу добавляется запись только при post_status == ‘publish’. Спасибо!

У меня есть еще маленький вопрос по параметам хука и его выполнению:

add_action ( ‘hook_name’, ‘your_function_name’, [priority], [accepted_args] );

в частности по необязательному параметру [priority].

Кодекс гласит:

priority is an optional integer argument that can be used to specify the order in which the functions associated with a particular action are executed (default: 10). Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action.

По-умолчанию параметр принимается равным 10. Меньшее число указывает на более ранее выполнение хука, а в случае если ф-я имеет равный приоритет ее выполнение происходит в том порядке, в котором они были добавлены.

Собственно, в нашем в случае в хуке add_action(‘wp_insert_post’,’wp_insert_post_hook’,10,2); указан приоритет равный 10. Правильно ли я понимаю, что в этом случае сначала отработает do_action(‘wp_insert_post’, $post_id, $post); (указанный в post.php), и сразу после него отработает хук?

Приоритет имеет смысл в том случае, если на хук подвешено несколько обработчиков. Допустим, имеем случай, когда один фильтр-плагин находит в тексте все http… и www… и делает из них ссылки, а другой всем внешним ссылкам добавляет target=_blank. Разумеется, в такой конфигурации порядок выполнения фильтров имеет принципиальное значение. Вот тут нам и поможет параметр приоритета. Кстати, некоторые хуки используются самим движком, так что при помощи этого параметра можно получить выполнение своего кода или "до", или "после", так сказать, системных обработчиков.

do_action – это и есть вызов всех подвешенных на хук обработчиков.

Юрий, по приоритету, когда на хук подвешено несколько обработчиков, понял, спасибо. Все это более чем логично.

Как вы написали, вот вызов всех подвешенных на хук обработчиков:
do_action(‘wp_insert_post’, $post_id, $post);

Правильно ли я понимаю, что в этом случае, сначала сработает системная ф-я wp_insert_post(), после которой сработает хук wp_insert_post_hook (описанный у меня в плагине)?

В функции wp_insert_post() как раз и стоит вызов обработчиков хука ‘wp_insert_post’: do_action(‘wp_insert_post’, $post_id, $post);. Поэтому, естественно, сначала сработает она, точнее, та часть ее кода, которая до do_action, потом по очереди все обработчики, потом выполнение функции продолжится. Такая себе точка прерывания.

Юрий, спасибо большое за помощь! Теперь всё встало на свои места! 🙂

Anonymous
Отправить
Ответ на: