Как отключить "Блокировку поста/Блокировку редактирования"?

26 окт. 2013 г., 17:22:05
Просмотры: 18.2K
Голосов: 16

Я хочу отключить эту функцию только для одного типа записей, так как не важно, если другой пользователь редактирует его (основная область редактирования использует 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.

Изображение второй блокировки

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

Я добавил пояснение о мотивах, и это наводит на мысль о решении: показывать этот контент не-администраторам на другом экране. Но всё равно было бы полезно знать правильный хук для post_lock.

brasofilo brasofilo
26 окт. 2013 г. 18:32:24
Все ответы на вопрос 4
3
11

В дополнение к ответу @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 );
        } );
    }
}
27 окт. 2013 г. 06:16:07
Комментарии

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

brasofilo brasofilo
27 окт. 2013 г. 09:39:27

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

kaiser kaiser
27 окт. 2013 г. 12:34:11

Отличная идея использовать post_type_supports для обработки этого для каждого пользовательского типа записи, хотел бы я поставить вам больше плюсов ;-)

birgire birgire
27 окт. 2013 г. 13:12:18
2

Чтобы убрать всплывающее окно 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;
}
26 окт. 2013 г. 19:34:51
Комментарии

Не проще ли просто использовать __return_false() вместо первой проверки для $time, которая в итоге сводится к bool TRUE?

kaiser kaiser
27 окт. 2013 г. 06:03:49

Возможно, но я не уверен, как установить $time в false, поэтому я выбрал вариант с $time_window...

birgire birgire
27 окт. 2013 г. 14:34:47
8

Финальная комбинация, которую я использовал:

# Убирает сообщение "Кто-то другой редактирует этот пост"
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 не кажется хорошей идеей.

27 окт. 2013 г. 09:36:50
Комментарии

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

kaiser kaiser
27 окт. 2013 г. 12:36:13

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

brasofilo brasofilo
27 окт. 2013 г. 12:46:36

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

kaiser kaiser
27 окт. 2013 г. 13:11:41

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

birgire birgire
27 окт. 2013 г. 14:37:59

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

brasofilo brasofilo
27 окт. 2013 г. 14:59:55

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

birgire birgire
27 окт. 2013 г. 15:11:55

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

brasofilo brasofilo
27 окт. 2013 г. 15:26:17

ок, отлично, бедный старый WP ;-)

birgire birgire
27 окт. 2013 г. 16:07:10
Показать остальные 3 комментариев
0

Вот окончательное решение, которое сработало у меня:

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');
26 апр. 2015 г. 18:23:01