web-dev-qa-db-fra.com

Comment rendre les brouillons ou les posts en revue accessibles via une URL/un slug complète?

J'utilise un site Web avec WordPress 4.2 et j'ai changé la façon dont les articles brouillon ou en cours de révision sont affichés pour les utilisateurs non connectés (ces articles sont également visibles par quiconque visite le site Web).

J'ai implémenté cette solution présentée ici: https://wordpress.org/support/topic/problem-filtering-query-to-allow-displaying-drafts-even-for-not-logged-users

Maintenant, alors que n'importe qui peut maintenant accéder aux brouillons/sans avoir à se connecter, les posts ne sont accessibles que via post_id, comme ceci:

http://my-domain.com/?p=1234

Ils ne sont pas accessibles via leur lien permanent/permalien Nice, qui était comme ça:

http://my-domain.com/2015/12/07/post-with-Nice-slug/

Quelqu'un a-t-il une idée sur la manière de "activer" les liens permanents pour les brouillons/les messages en attente?

Je vous remercie!

UPDATE 20 février

La réponse donnée par @userabuser fonctionne à merveille !! Étant donné que tous mes projets en attente/brouillon étaient des publications antérieures, je n'avais pas besoin de faire le tour pour publier en premier. J'avais pensé que j'avais moi-même trouvé une solution de travail - mais: voici le code que j'ai utilisé auparavant, qui ne fonctionnait pas (et je ne vois pas pourquoi):

function guest_enable_hidden_single_post($query) {
    if(is_user_logged_in()) return $query;
    //user is not logged

    if(!is_single()) return $query;
    //this is a single post

    if(!$query->is_main_query())return $query;
    //this is the main query    

    $query->set('post_status',array('publish', 'pending'));
    //allowed post statuses for guest

    return $query;
}

function guest_reload_hidden_single_post($posts) {
    global $wp_query, $wpdb;

    if(is_user_logged_in()) return $posts;
    //user is not logged

    if(!is_single()) return $posts;
    //this is a single post

    if(!$wp_query->is_main_query()) return $posts;
    //this is the main query

    if($wp_query->post_count) return $posts;
    //no posts were found

    $posts = $wpdb->get_results($wp_query->request);

    return $posts;
}

//allow guests to view single posts even if they have not post_status="publish"
add_filter('pre_get_posts', 'guest_enable_hidden_single_post');

//reload hidden posts
add_filter('the_posts', 'guest_reload_hidden_single_post');

UPDATE 22 février

Il y avait un problème avec les pages privées non affichées aux administrateurs/utilisateurs connectés. J'ai corrigé cela avec le code suivant:

function preview_draft_posts($query) {
    if(is_user_logged_in()) return $query;
    // user is not logged

    if(is_admin()) return $query;
    // user is not admin

    if(is_attachment()) return $query;
    // is not an attachment

    if(get_query_var('suppress_filters')) return $query;
    // no suppressed filters

    if(!is_single()) return $query;
    // query for a single post

    if(!$query->is_main_query()) return $query;
    // this is the main query

    $query->set('post_status', array('publish', 'pending'));

    return $query;
}
add_filter('pre_get_posts', 'preview_draft_posts');

Désormais, les publications en attente sont affichées à tout le monde et les publications privées ne sont encore visibles que par les administrateurs ;-)

2
Sebastian

Avertissement: les exemples de code dans cette réponse sont très basiques et peuvent nécessiter ou non une logique conditionnelle supplémentaire pour s'adapter à vos besoins précis. Cette logique est conçue à titre d'exemple pour vous permettre de progresser.

Vous devez prendre en compte deux considérations:

Considération 1:

Si vous ajoutez une nouvelle publication et l'enregistrez avec un post_status de draft first, la publication n'aura pas la variable slug dans le champ post_name de la table *_posts de la base de données jusqu'à ce que vous publiez au moins une fois .

Considération 2:

Si vous ajoutez un nouveau post, enregistrez-le avec un post_status de draft , ou passez simplement le draft stage et passez directement à publish puis remettez le post dans un brouillon post_status, alors le billet aura le slug inséré dans la colonne post_name de la table *_posts.

Pourquoi c'est important:

  • En ce qui concerne la contrepartie 1 ...

WordPress s'appuie sur au moins un marqueur d'identification, généralement le id ou le post_name, qui est unique pour pouvoir récupérer un message.

Vous remarquerez que lorsque vous créez un brouillon et tentez de le prévisualiser, WordPress vous conduit à une URL de prévisualisation similaire à:

http://example.com/?p=123&preview=true

C'est parce que le seul moyen d'identifier et de prévisualiser le message en question consiste à le faire à l'aide de l'ID auquel il est associé dans la base de données.

  • Par rapport à la considération 2 ...

Si vous publiez la publication au moins une fois, puis remettez-la dans draft , vous pourrez accéder à la publication tant que draft status sera utilisée avec le slug ( très permalien) car la colonne post_name contient la valeur slug.

Quelques exemples de code:

Le code suivant vous permettra de renvoyer des publications dans un draft ou en attente status en utilisant le slug tant que la publication a été publiée au moins une fois auparavant (voir considération 2).

function preview_draft_posts($query) {

  if ( is_admin() || get_query_var('suppress_filters') )
    return $query;


  $query->set('post_status', array('publish', 'pending', 'draft'));


  return $query;

}

add_filter('pre_get_posts', 'preview_draft_posts');

Ce qui précède fonctionnera pour les utilisateurs connectés et déconnectés.

Que se passe-t-il si vous êtes déconnecté et souhaitez prévisualiser un brouillon?

Ok, donc si le draf n’a pas été publié au moins une fois auparavant, le seul moyen de prévisualiser le message consiste à utiliser le format suivant:

http://example.com/?p=123

WordPress dépend de ce format pour trouver un article où il n’a pas de slug.

Si vous êtes déconnecté, vous ne pourrez pas voir ce message malgré la logique pre_get_posts utilisée dans l'exemple ci-dessus.

Au lieu de cela, vous devez vous connecter au filtre the_posts et rajouter la publication aux résultats à afficher, car WP_Query exclura draft posts de l'ensemble de résultats pour les utilisateurs déconnectés, car les utilisateurs déconnectés ne disposent pas du des capacités d'utilisateur appropriées.

Si, par contre, vous essayez (en étant déconnecté) d'accéder à un message similaire à celui de la considération 1 par son URL de prévisualisation par défaut, comme indiqué ci-dessus dans l'exemple http://example.com/?p=123&preview=true (avec ou sans le preview=true), un message d'erreur s'affiche. Avis de page non trouvée.

L'exemple de code suivant corrige cela:

function the_posts_preview_draft_posts($posts, $wp_query) {

    //abort if $posts is not empty, this query ain't for us...
    if ( count($posts) ) {
        return $posts;
    }

    $p = get_query_var('p');

    //get our post instead and return it as the result...
    if ( !empty($p) ) {
        return array(get_post($p));
    }
}

add_filter('the_posts', 'the_posts_preview_draft_posts', 10, 2);

Génial ... mais accrochez-vous, ça craint toujours, en quelque sorte, car vous devez utiliser un format d'URL tel que http://example.com/?p=123 pour accéder à la publication.

Revenons au problème principal décrit dans Considération 1 , les seules solutions auxquelles je puisse penser sont les suivantes:

Solution n ° 1

  • enregistrer le brouillon de message et trouver le message par son titre en convertissant le slug en titre.

Exemple...

function the_posts_preview_draft_posts($posts, $wp_query) {

    //abort if $posts is not empty, this query ain't for us...
    if ( count($posts) ) {
        return $posts;
    }

    $id    = get_query_var('p');
    $name = get_query_var('name');

    //this is a bit of a bad idea...
    if ( empty($id) && !empty($name) ) {

        $name = preg_replace('/\W/', ' ', $name);

        global $wpdb;
        $id = $wpdb->get_var( 
            "
            SELECT ID 
            FROM $wpdb->posts 
            WHERE UPPER(post_title) LIKE UPPER('".$name."')
            LIMIT 1" 
        );

    }


    //get our post instead and return it as the result...
    if ( !empty($id) ) {
        return array(get_post($id));
    }

}

add_filter('the_posts', 'the_posts_preview_draft_posts', 10, 2);

Ce qui précède ... ↑ ... est une mauvaise idée, mais juste un exemple des longueurs auxquelles vous devez aller. Pourquoi ceci est une mauvaise idée est simple, vous devez vous assurer que vous n'avez aucun titre d'article en double dans la base de données et vous ne devez pas modifier le slug afin qu'il soit différent du titre lorsque vous l'enregistrez en tant que brouillon .

Beaucoup de problèmes, comme vous pouvez le voir.

Solution n ° 2

Une meilleure solution consiste probablement à définir le post_status de la publication sur publish afin que la colonne post_name obtienne la valeur slug, puis à replacer immédiatement la publication dans un draft status .

Faire cela manuellement serait nul alors voici du code:

function allow_draft_public_preview( ) {

        global $post;

        if ( !empty($post->post_name) )
            return;

        $html =<<<DOC
        <div class="misc-pub-section">
            <label>
                <input type="checkbox" id="_allow_public_preview" name="_allow_public_preview" value="1" />
                Allow public preview
            </label>
        </div>
DOC;

echo $html;

}

add_action('post_submitbox_misc_actions', 'allow_draft_public_preview');

function update_post_status( $post_id, $post, $update ) {

    if ( !empty($_POST['_allow_public_preview']) ) {

        //un-hook to prevent infinite loop
        remove_action( 'save_post', 'update_post_status', 13, 2 );

        //set the post to publish so it gets the slug is saved to post_name
        wp_update_post( array( 'ID' => $post_id, 'post_status' => 'publish' ) );

        //immediately put it back to draft status
        wp_update_post( array( 'ID' => $post_id, 'post_status' => 'draft' ) );

        //re-hool
        add_action( 'save_post', 'update_post_status', 13, 2 );
    }

}

add_action('save_post', 'update_post_status', 13, 2);

Le premier rappel attaché à l'action post_submitbox_misc_actions ajoute une case à cocher à l'écran d'édition postérieure "Autoriser l'aperçu public" ...

 enter image description here 

... lorsque vous cochez cette case, elle sera reconnue par le deuxième rappel déclenché sur l'action save_post.

Dans l'action save_post, nous vérifions l'existence de notre case à cocher dans le $_POST superglobal et si elle est présente, nous affectons le statut de publication à publish puis nous le remettons immédiatement à draft .

Vous pouvez maintenant accéder aux brouillons, connectés ou déconnectés, par leurs liens permanents/jolis permaliens.

Tous ensemble maintenant:

function preview_draft_posts($query) {

  if ( is_admin() || get_query_var('suppress_filters') )
    return $query;


  $query->set('post_status', array('publish', 'pending', 'draft'));


  return $query;

}

add_filter('pre_get_posts', 'preview_draft_posts');

function the_posts_preview_draft_posts($posts, $wp_query) {

    //abort if $posts is not empty, this query ain't for us...
    if ( count($posts) ) {
        return $posts;
    }

    $p = get_query_var('p');

    //get our post instead and return it as the result...
    if ( !empty($p) ) {
        return array(get_post($p));
    }
}

add_filter('the_posts', 'the_posts_preview_draft_posts', 10, 2);

function allow_draft_public_preview( ) {

        global $post;

        if ( !empty($post->post_name) )
            return;

        $html =<<<DOC
        <div class="misc-pub-section">
            <label>
                <input type="checkbox" id="_allow_public_preview" name="_allow_public_preview" value="1" />
                Allow public preview
            </label>
        </div>
DOC;

echo $html;

}

add_action('post_submitbox_misc_actions', 'allow_draft_public_preview');

function update_post_status( $post_id, $post, $update ) {

    if ( !empty($_POST['_allow_public_preview']) ) {

        //un-hook to prevent infinite loop
        remove_action( 'save_post', 'update_post_status', 13, 2 );

        //set the post to publish so it gets the slug is saved to post_name
        wp_update_post( array( 'ID' => $post_id, 'post_status' => 'publish' ) );

        //immediately put it back to draft status
        wp_update_post( array( 'ID' => $post_id, 'post_status' => 'draft' ) );

        //re-hool
        add_action( 'save_post', 'update_post_status', 13, 2 );
    }

}

add_action('save_post', 'update_post_status', 13, 2);
3
userabuser