Cómo desactivar el "Bloqueo de publicación/Bloqueo de edición"

26 oct 2013, 17:22:05
Vistas: 18.2K
Votos: 16

Quiero desactivar esto solo para un Tipo de Publicación específico, ya que no importa realmente si otro usuario lo está editando (el área principal de edición de contenido usa Ajax y los no-administradores solo pueden ver eso).

Imagen mostrando el bloqueo de edición en WordPress

Revisé las funciones principales pero no encontré un punto de entrada. Por la función wp_set_post_lock supongo que tendría que interceptar el get_post_meta, pero ¿existe una forma oficial de hacerlo?

Además hay un segundo bloqueo que no parece verse afectado por el filtro wp_check_post_lock_window (como mostró birgire, aquí en una Respuesta). Intenté usar remove_filter( 'heartbeat_received', 'wp_refresh_post_lock', 10, 3 ); en varios puntos pero sigue funcionando sin respetar el remove_filter.

Segundo sistema de bloqueo en WordPress

1
Comentarios

He añadido una aclaración sobre los motivos, y me hace pensar en una solución: mostrar este contenido a usuarios no administradores en otra pantalla. Pero igualmente sería bueno conocer un hook adecuado para post_lock.

brasofilo brasofilo
26 oct 2013 18:32:24
Todas las respuestas a la pregunta 4
3
11

Como complemento a la respuesta de @birgire

Hallazgos

register_post_type() permite registrar soporte para un tipo de post, lo cual también puede hacerse después usando add_post_type_support(). Y esto puede verificarse más tarde usando el todopoderoso post_type_supports( $cpt, $feat ).

Un mini plugin general que añade una nueva característica

El siguiente (mu-)plugin verifica un nuevo tipo de soporte para tipos de post que deshabilita la característica de bloqueo de posts. Se llama 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' );
}

Un plugin por CPT

Luego podemos fácilmente añadir mini plugins para deshabilitar el soporte de tipos de post para nuestros propios plugins o de terceros (ahorrando ancho de banda y tamaño en la tabla de metadatos de usuario):

<?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' );
} );

Tan pronto como se active el segundo plugin, nuestro tipo de post beer ya no tendrá bloqueo de posts. Esto debería funcionar bien y es fácilmente reversible desde la pantalla de administración de plugins.

Deshabilitar la API Heartbeat

Extendiendo el plugin para también deshabilitar la API Heartbeat:

<?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 oct 2013 06:16:07
Comentarios

Esta es una solución realmente elegante, ¿cómo manejarías la parte de admin-ajax.php (Pregunta actualizada y Respuesta añadida)?

brasofilo brasofilo
27 oct 2013 09:39:27

@brasofilo Añadí una edición para deshabilitar completamente la API Heartbeat. No estoy seguro de cómo quieres manejar eso, pero aún puedes ejecutar la API heartbeat en plugins usando wp.heartbeat.start(); en tu JavaScript.

kaiser kaiser
27 oct 2013 12:34:11

Es una gran idea usar post_type_supports para manejar esto en cada tipo de contenido personalizado, ojalá pudiera darte más votos positivos ;-)

birgire birgire
27 oct 2013 13:12:18
2

Para eliminar la ventana emergente de edit-lock, podrías intentar:

add_filter( 'wp_check_post_lock_window', '__return_zero' );

No estoy seguro si es la mejor manera, pero revisé el código fuente de wp_check_post_lock() y encontramos estas líneas:

...cortado...

$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;

...cortado...

así que la idea es cambiar $time_window para que la condición if sea false.

Actualización:

Para aplicar esto en la pantalla de edit.php, con el tipo de post personalizado beer por ejemplo:

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' );

Y luego podemos añadir:

add_action( 'load-post.php', 'wpse_120179' );

para eliminarlo también en la pantalla de post.php.

Profundizando más...

La función _admin_notice_post_locked() está definida justo debajo de la función wp_set_post_lock(). Contiene estas líneas:

...cortado...
if ( ! apply_filters( 'show_post_locked_dialog', true, $post, $user ) )
    return;
...cortado...

así que también se puede probar el filtro 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 oct 2013 19:34:51
Comentarios

¿No sería más fácil simplemente usar __return_false() en lugar de la primera verificación para $time que básicamente se resume como un bool TRUE?

kaiser kaiser
27 oct 2013 06:03:49

OK, tal vez, pero no estoy seguro de cómo establecer $time como false así que opté por $time_window en su lugar...

birgire birgire
27 oct 2013 14:34:47
8

La combinación final que terminé usando es

# Se encarga del mensaje "Alguien más está editando esto"
add_action( 'load-edit.php', function()
{
    if( 'beer' === get_current_screen()->post_type )
        add_filter( 'wp_check_post_lock_window', '__return_false' );
});

# Se encarga de post.php y el mensaje "El usuario ha tomado el control"
add_filter( 'show_post_locked_dialog', function( $bool, $post, $user )
{
    if( 'beer' === $post->post_type )
        return false;
    return $bool;
}, 
10, 3 );

pero si alguien tiene otra perspectiva, me encantaría escucharla, ya que no termino de entender completamente el panorama completo de filtros disponibles.

Anteriormente, usando load-edit.php + load-post.php, tuve que eliminar el filtro wp_refresh_post_lock con:

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 );
});

pero cargarlo en cada admin_init no parece una buena idea.

27 oct 2013 09:36:50
Comentarios

Por favor usa get_current_screen()->post_type en su lugar. Aquí hay un buen plugin llamado Current Admin Info para ayudarte a obtener esta información.

kaiser kaiser
27 oct 2013 12:36:13

@kaiser, mi intención aquí es bloquear el heartbeat para Ajax, tal vez debería agregar alguna verificación DOING_AJAX... Y según lo entiendo, Ajax no tiene global $current_screen (devuelto por get_current_screen()).

brasofilo brasofilo
27 oct 2013 12:46:36

Ah, tal vez. No lo sé en este momento. Por cierto, existe wp_is_autosave() - no estoy seguro si eso aplica a alguna de esas acciones.

kaiser kaiser
27 oct 2013 13:11:41

Me pregunto si add_filter( 'show_post_locked_dialog', '__return_false' );, de la función _admin_notice_post_locked(), podría ser de ayuda.

birgire birgire
27 oct 2013 14:37:59

@birgire, no, no funcionó. Estoy pensando que no es posible detener wp_ajax_heartbeat() (wp-admin/includes/ajax-actions.php) usando la cadena load-$hook -> get_current_something(). . . . . Además, hay 3 hooks en esa función, pero no he logrado detener el latido usándolos (y tienen $screen_id, que coincide con el tipo de publicación.

brasofilo brasofilo
27 oct 2013 14:59:55

Se siente como intentar darle un ataque al corazón a WordPress... ;-) Pero ¿funciona si agregas/eliminas los filtros directamente (así que para todos los CPT?)

birgire birgire
27 oct 2013 15:11:55

@birgire, sí señor, ese es el que detiene el ritmo :) ¡Le dimos un infarto al viejo WP! El filtro también toma $post y $user como argumentos, fue el clavo final. Por favor, agrégalo a tu Respuesta.

brasofilo brasofilo
27 oct 2013 15:26:17

ok genial, pobre WP viejo ;-)

birgire birgire
27 oct 2013 16:07:10
Mostrar los 3 comentarios restantes
0

Aquí está la solución final que funciona para mí:

function my_remove_post_locked() {
    $current_post_type = get_current_screen()->post_type;   

    // Deshabilitar bloqueo para página, entrada y algún tipo de contenido personalizado
    $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 abr 2015 18:23:01