Как отключить "Блокировку поста/Блокировку редактирования"?
Я хочу отключить эту функцию только для одного типа записей, так как не важно, если другой пользователь редактирует его (основная область редактирования использует Ajax и не-администраторы видят только это).
Я изучил основные функции, но не нашел точки входа. Из функции wp_set_post_lock
я предполагаю, что нужно перехватить get_post_meta
, но есть ли официальный способ сделать это?
Также есть вторая блокировка, которая, кажется, не подвержена влиянию фильтра wp_check_post_lock_window
(как показал birgire здесь в ответе). Я пробовал remove_filter( 'heartbeat_received', 'wp_refresh_post_lock', 10, 3 );
в различных местах, но она продолжает работать, игнорируя remove_filter
.

В дополнение к ответу @birgire…
Находки
Функция register_post_type()
позволяет зарегистрировать поддержку типов записей, что также можно сделать позже с помощью add_post_type_support()
. А проверить это можно в любое время с помощью мощного post_type_supports( $cpt, $feat )
.
Общий мини-плагин, добавляющий новую функцию
Следующий (mu-)плагин проверяет новый вид поддержки типов записей, который отключает функцию блокировки записей. Он называется disabled_post_lock
.
<?php
defined( 'ABSPATH' );
/** Plugin Name: (#120179) Maybe Disable Post Type Support */
add_action( 'load-edit.php', 'wpse120179MaybeDisablePostLock' );
function wpse120179MaybeDisablePostLock()
{
if ( post_type_supports( get_current_screen()->post_type, 'disabled_post_lock' ) )
add_filter( 'wp_check_post_lock_window', '__return_false' );
}
Один плагин для каждого CPT
Затем мы можем легко добавить мини-плагины для отключения поддержки типов записей для наших или сторонних плагинов (это сэкономит нам трафик и место в таблице пользовательских метаданных):
<?php
defined( 'ABSPATH' );
/** Plugin Name: (#120179) Disable Post Type Support for "Beer" Posts */
add_action( 'init', function()
{
add_post_type_support( 'beer', 'disabled_post_lock' );
} );
Как только второй плагин активирован, наш тип записи beer больше не имеет блокировки записей. Это работает отлично и легко отменяется через экран управления плагинами.
Отключение Heartbeat API
Расширение плагина для отключения Heartbeat API:
<?php
defined( 'ABSPATH' );
/** Plugin Name: (#120179) Maybe Disable Post Type Support */
add_action( 'load-edit.php', 'wpse120179MaybeDisablePostLock' );
function wpse120179MaybeDisablePostLock()
{
if ( post_type_supports( get_current_screen()->post_type, 'disabled_post_lock' ) )
{
add_filter( 'wp_check_post_lock_window', '__return_false' );
add_filter( 'heartbeat_settings', function( $settings )
{
return wp_parse_args( [ 'autostart' => false ], $settings );
} );
}
}

Это действительно элегантное решение, как бы вы обработали часть с admin-ajax.php
(вопрос обновлён и ответ добавлен)?

@brasofilo Я добавил правку для полного отключения Heartbeat API. Не знаю, как вы хотите это обработать, но вы всё ещё можете запускать Heartbeat API в плагинах, используя wp.heartbeat.start();
в вашем JavaScript.

Чтобы убрать всплывающее окно edit-lock, можно попробовать:
add_filter( 'wp_check_post_lock_window', '__return_zero' );
Я не уверен, что это правильный способ, но я проверил исходный код функции wp_check_post_lock()
и там есть такие строки:
...cut...
$time_window = apply_filters( 'wp_check_post_lock_window', 120 );
if ( $time && $time > time() - $time_window && $user != get_current_user_id() )
return $user;
return false;
...cut...
Идея заключается в изменении $time_window
, чтобы условие if
стало false
.
Обновление:
Чтобы применить это на экране edit.php
, например, для пользовательского типа записи beer
:
function wpse_120179()
{
if( 'beer' === get_current_screen()->post_type )
add_filter( 'wp_check_post_lock_window', '__return_zero' );
}
add_action( 'load-edit.php', 'wpse_120179' );
Затем можно добавить:
add_action( 'load-post.php', 'wpse_120179' );
чтобы убрать окно и для экрана post.php
.
Дополнительные исследования...
Функция _admin_notice_post_locked()
определена сразу после функции wp_set_post_lock()
. Она содержит такие строки:
...cut...
if ( ! apply_filters( 'show_post_locked_dialog', true, $post, $user ) )
return;
...cut...
поэтому можно также попробовать фильтр show_post_locked_dialog
:
add_filter( 'show_post_locked_dialog', 'wpse_120179_close_dialog', 99, 3 );
function wpse_120179_close_dialog( $show, $post, $user )
{
if( 'beer' === $post->post_type )
return FALSE;
return $show;
}

Финальная комбинация, которую я использовал:
# Убирает сообщение "Кто-то другой редактирует этот пост"
add_action( 'load-edit.php', function()
{
if( 'beer' === get_current_screen()->post_type )
add_filter( 'wp_check_post_lock_window', '__return_false' );
});
# Убирает сообщение "Пользователь перехватил редактирование" в post.php
add_filter( 'show_post_locked_dialog', function( $bool, $post, $user )
{
if( 'beer' === $post->post_type )
return false;
return $bool;
},
10, 3 );
Но если у кого-то есть другие решения, буду рад услышать, так как я не до конца понимаю всю картину доступных фильтров.
Ранее, используя
load-edit.php
+load-post.php
, мне приходилось удалять фильтрwp_refresh_post_lock
с помощью:add_action( 'admin_init', function() { if( !defined('DOING_AJAX') || !isset( $_POST['screen_id'] ) || 'beer' !== $_POST['screen_id'] ) return; remove_filter( 'heartbeat_received', 'wp_refresh_post_lock', 10 ); });
но загрузка на каждом
admin_init
не кажется хорошей идеей.

Пожалуйста, используйте get_current_screen()->post_type
вместо этого. Вот хороший плагин под названием Current Admin Info, который поможет вам получить такую информацию.

@kaiser, моя цель здесь - отключить heartbeat для Ajax, возможно, мне следует добавить проверку DOING_AJAX
... И, насколько я понимаю, у Ajax нет global $current_screen
(возвращаемого функцией get_current_screen()
).

А, возможно. Не знаю на данный момент. Кстати, есть wp_is_autosave()
- не уверен, относится ли это к каким-либо из этих действий.

Интересно, поможет ли add_filter( 'show_post_locked_dialog', '__return_false' );
из функции _admin_notice_post_locked()
?

@birgire, нет, не сработало. Я думаю, что невозможно остановить wp_ajax_heartbeat()
(wp-admin/includes/ajax-actions.php) с помощью цепочки load-$hook
-> get_current_something()
. . . . . Также в этой функции есть 3 хука, но мне не удается остановить "биение" с их помощью (и у них есть $screen_id
, который соответствует типу записи.

Ощущение, что пытаешься устроить WordPress сердечный приступ... ;-) Но работает ли, если добавить/удалить фильтры напрямую (таким образом для всех CPT?)

@birgire, да, сэр, это именно то, что останавливает биение :) Мы довели старину WP до инфаркта! Фильтр также принимает аргументы $post
и $user
, это был последний гвоздь в крышку. Пожалуйста, добавьте это в ваш Ответ.

Вот окончательное решение, которое сработало у меня:
function my_remove_post_locked() {
$current_post_type = get_current_screen()->post_type;
// Отключаем блокировку для страниц, записей и некоторых пользовательских типов записей
$post_types_arr = array(
'page',
'post',
'custom_post_type'
);
if(in_array($current_post_type, $post_types_arr)) {
add_filter( 'show_post_locked_dialog', '__return_false' );
add_filter( 'wp_check_post_lock_window', '__return_false' );
wp_deregister_script('heartbeat');
}
}
add_action('load-edit.php', 'my_remove_post_locked');
add_action('load-post.php', 'my_remove_post_locked');
