¿Cómo hacer que una publicación en borrador sea accesible para todos?
Tengo varias publicaciones no publicadas en mi sitio Wordpress y estoy intentando hacerlas accesibles para usuarios normales (que no han iniciado sesión) usando los slugs normales de las publicaciones (sitio.com/publicacion-aqui
). Entiendo que puede no ser la mejor práctica, pero para mi propósito especial, esto necesita hacerse.
He intentado agregar el siguiente fragmento de código en mi archivo functions.php
:
function habilitar_ver_borradores() {
$rol = get_role( 'subscriber' );
$rol->add_cap( 'read_private_posts' );
$rol->add_cap( 'edit_posts' );
}
add_action( 'after_setup_theme', 'habilitar_ver_borradores');
También he probado el hook init
en lugar de after_setup_theme
. Sin éxito.
Mi entendimiento es que los cambios en los roles se guardan en la base de datos, por lo que solo necesitan hacerse una vez. Por eso estoy usando el hook after_setup_theme
para llamar a la función.
Pero cuando intento acceder a la página como usuario normal, me muestra una página 404 en lugar del contenido de la publicación. También he intentado cargar la URL de vista previa (sitio.com/?p=212&preview=true
) pero eso tampoco funcionó.
Estas son mis suposiciones:
- el usuario normal no tiene suficientes
capacidades
para leer la publicación en borrador. - probar y ver publicaciones en borrador en el front-end no es posible para ningún usuario (incluidos los administradores).
¿Qué cambios debo hacer para lograr lo que intento hacer? Si no es posible, ¿qué soluciones alternativas sugieres?
Nota: No estoy buscando soluciones basadas en plugins.

No puedes asignar capacidades a usuarios desconocidos. Si deseas hacer una publicación visible para todos, crea una URL separada para estas publicaciones y agrega un elemento de control al editor de publicaciones para habilitar la vista previa solo en publicaciones seleccionadas.
Cuando se llame a dicha URL, verifica si se permite una vista previa para la publicación y si la publicación aún no se ha publicado. También asegúrate de que los motores de búsqueda ignoren esta URL.
Para la URL, usaría un endpoint:
add_rewrite_endpoint( 'post-preview', EP_ROOT );
Ahora puedes crear URLs como …
http://example.com/post-preview/123
… donde 123
es el ID de la publicación.
Luego usa un manejador de callback para inspeccionar el ID de la publicación, verificar si es válido y sobrescribir la consulta principal. Este es probablemente el único caso de uso aceptable para query_posts()
. :)
Digamos que el endpoint es una clase T5_Endpoint
(un modelo), y el manejador de salida es una clase T5_Render_Endpoint
(una vista) que recibe el modelo pasado anteriormente. Entonces probablemente habrá un método render()
llamado en template_redirect
:
public function render()
{
$post_id = $this->endpoint->get_value();
if ( ! $post_id )
return;
if ( 1 !== $this->meta->get_value( $post_id )
or 'publish' === get_post_status( $post_id )
)
{
wp_redirect( get_permalink( $post_id ) );
exit;
}
$query = array (
'suppress_filters' => TRUE,
'p' => $post_id,
'post_type' => 'any'
);
query_posts( $query );
add_action( 'wp_head', 'wp_no_robots' );
}
$this->meta
es otro modelo (clase T5_Post_Meta
) para el valor meta de la publicación que controla si se permite una vista previa. El control se establece en el cuadro de Publicar (acción post_submitbox_misc_actions
), renderizado por otra vista que obtiene la misma clase meta.
Entonces, T5_Post_Meta
sabe dónde y cuándo almacenar el valor meta, las vistas hacen algo con él.
Además, conecta con transition_post_status
para eliminar el campo meta de la publicación cuando esta se publique. No queremos desperdiciar recursos, ¿verdad?
Esto es solo un esquema. Hay muchos detalles por cubrir... He escrito un pequeño plugin que muestra cómo implementar esto: T5 Public Preview.

Resolví este problema de una manera que consideré más simple que la respuesta de @toscho mencionada anteriormente.
Mi caso de uso es que estoy utilizando la misma base de datos para un sitio de staging interno de intranet y un sitio público, y el flujo de trabajo es que los autores escriben borradores y los comparten con otros usuarios que ven esos borradores en el sitio de intranet, antes de publicarlos. Específicamente no quería requerir que los revisores iniciaran sesión para ver borradores, así que solo dependo de una constante, ENV_PRODUCTION
que se establece en el archivo wp-config según el nombre del host en $_SERVER['SERVER_NAME']
. Eso es lo que hacen las verificaciones de ENV_PRODUCTION
aquí; simplemente anulan todos estos filtros si se está viendo el sitio de producción.
Esto es un poco extraño, porque hay que engancharse después de que WP_Query elimina todas las publicaciones del array $wp_query->posts, pero me parece estable y seguro.
/*
* En la página de inicio y archivos del sitio de staging, los borradores deben ser visibles.
*/
function show_drafts_in_staging_archives( $query ) {
if ( ENV_PRODUCTION )
return;
if ( is_admin() || is_feed() )
return;
$query->set( 'post_status', array( 'publish', 'draft' ) );
}
add_action( 'pre_get_posts', 'show_drafts_in_staging_archives' );
/*
* Hacer que los borradores sean visibles en las vistas individuales del sitio de staging.
*
* (Porque en vistas individuales, WP_Query aplica lógica para asegurarse de que el
* usuario actual pueda editar la publicación antes de mostrar un borrador.)
*/
function show_single_drafts_on_staging( $posts, $wp_query ) {
if ( ENV_PRODUCTION )
return $posts;
//asegurándose de que la publicación es una vista previa para evitar mostrar publicaciones privadas publicadas
if ( ! is_preview() )
return $posts;
if ( count( $posts ) )
return $posts;
if ( !empty( $wp_query->query['p'] ) ) {
return array ( get_post( $wp_query->query['p'] ) );
}
}
add_filter( 'the_posts', 'show_single_drafts_on_staging', 10, 2 );
Hay dos partes separadas en los filtros.
- Un filtro en el hook "pre_get_posts" establece el post_status predeterminado como 'publish,draft' en el sitio de staging. Esto devolverá los borradores en los listados de archivo.
- Se necesita un filtro separado para las vistas individuales, porque hay una lógica complicada en la clase WP_Query para eliminar borradores de los resultados de la consulta a menos que el usuario actual pueda editarlos. Lo solucioné filtrando 'the_posts' y agregando la publicación que quería de vuelta a los resultados.

Esto es increíble, muchas gracias por compartirlo. Absolutamente perfecto y exactamente lo que necesitaba.

@Joelio ¿Puedes ser específico sobre el problema que estás resolviendo? Como enfoque simple, simplemente agregué este código a mi functions.php, y añadí una definición simple a mi wp-config.php que establece la constante ENV_PRODUCTION como verdadera o falsa dependiendo del dominio de la solicitud.

@goldenapples He añadido este fragmento de código a mi function.php, ¿qué debería añadir a wp-config? Gracias por tu ayuda

@MatthiasGrahamSlick - Solo necesitas algo que establezca la constante ENV_PRODUCTION
si estás en producción. Yo estaba usando domain.com para producción y staging.domain.com para staging, así que mi línea era define( 'ENV_PRODUCTION', false === stripos( $_SERVER['HTTP_HOST'], 'staging' ) );
¿Te ayuda eso?

@goldenapples ¿Dónde en tu función show_single_drafts_on_staging
controlas para mostrar solo entradas con post_status=draft
? Según lo que he probado de tu código, mostrará cualquier entrada (incluso las eliminadas) en las páginas individuales. ¿O estoy haciendo algo mal?

Creo que el plugin "User Role Editor" disponible en el sitio web de WordPress.org podría ser lo que estás buscando. Por cierto, ¿por qué quieres dar acceso a tus borradores a todos? Personalmente, no se me ocurre una situación en la que esto sería necesario.

No, como se mencionó en la pregunta, no estoy buscando soluciones basadas en plugins. El caso de uso es un poco complicado, pero estoy seguro de que esta es la mejor solución para esta tarea específica que estoy tratando de lograr. :-)

También estoy perplejo por la razón. Si quieres que todos vean la publicación, ¿por qué no simplemente publicarla? Podrías usar campos personalizados en la publicación para rastrear cualquier estado especial que desees definir.

Creo que el comentario de G.M. es el mejor aquí. Supongo que estás intentando hacer lo siguiente:
- Escribir una entrada
- Guardar como borrador
- Permitir que un usuario externo (no registrado) vea el borrador para su aprobación
- Publicar
¿Es eso correcto?
Desafortunadamente, no se me ocurre ninguna forma sencilla de hacer esto. Podrías publicarlo como una entrada privada para que necesiten ingresar una contraseña para verla, pero necesitarías estar registrado para esto. También podrías protegerla con contraseña, pero aún así aparecerá en tu feed y lista de entradas recientes, etc. ¿No podrías crear una cuenta de usuario invitado y darles el nombre de usuario/contraseña cuando les des la URL?
Lee aquí para más información: http://codex.wordpress.org/Content_Visibility
Alternativamente, hay un plugin que podría adaptarse a tus necesidades: http://wordpress.org/extend/plugins/shareadraft/ Eché un vistazo rápido al código y parece que el desarrollador está modificando el valor devuelto por get_post_status, así que podrías jugar con eso:
http://codex.wordpress.org/Function_Reference/get_post_status
Espero que esto ayude

Esta no es una solución viable para una página ya publicada. Puedes hacer ediciones en una página actualmente en vivo y guardarlas como borrador. Si siguieras este enfoque en una página en vivo, eliminaría la página en vivo de los resultados de búsqueda con el tiempo y potencialmente causaría otros problemas.
