it-swarm.com.de

Wie kann ich Entwürfe von Posts oder Posts in Reviews über die vollständige URL/Slug zugänglich machen?

Ich betreibe eine Website mit WordPress 4.2 und habe die Art und Weise geändert, in der Entwürfe von Beiträgen oder Beiträge mit Überprüfungsstatus nicht angemeldeten Benutzern angezeigt werden (diese Beiträge sind auch für jeden sichtbar, der die Website besucht).

Ich habe diese hier vorgestellte Lösung implementiert: https://wordpress.org/support/topic/problem-filtering-query-to-allow-displaying-drafts-even-for-not-logged-users

Jetzt kann jeder auf Entwürfe und ausstehende Posts zugreifen, ohne sich anmelden zu müssen. Auf die Posts kann jedoch nur über die post_id zugegriffen werden:

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

Sie sind nicht über ihren Slug/Nice-Permalink erreichbar, was früher so war:

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

Hat jemand eine Idee, wie man Permalinks für Entwürfe/ausstehende Posts "aktiviert"?

Vielen Dank!

UPDATE 20. Februar

Die Antwort von @userabuser wirkt wie ein Zauber !! Da es sich bei allen ausstehenden Beiträgen/Entwürfen um zuvor veröffentlichte Beiträge handelte, musste ich den Trick nicht ausführen, um sie zuerst zu veröffentlichen. Ich hatte gedacht, ich hätte selbst eine funktionierende Lösung gefunden - aber: hier ist der Code, den ich zuvor verwendet habe und der nicht funktioniert hat (und ich verstehe nicht, warum das so ist):

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. Februar

Es gab ein Problem mit privaten Seiten, die Administratoren/angemeldeten Benutzern nicht angezeigt wurden. Ich habe das mit folgendem Code behoben:

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

Jetzt werden ausstehende Posts jedem angezeigt und private Posts sind nur noch für Administratoren sichtbar ;-)

2
Sebastian

Vorsichtsmaßnahme: Die Codebeispiele in dieser Antwort sind sehr einfach und erfordern möglicherweise keine weitere bedingte Logik, um sich an Ihre genauen Anforderungen anzupassen. Diese Logik ist als Beispiel gedacht, um Sie auf den Weg zu bringen.

Es gibt zwei Überlegungen, die Sie berücksichtigen müssen:

Überlegung 1:

Wenn Sie einen neuen Beitrag hinzufügen und ihn mit einem post_status von draft zuerst speichern, enthält der Beitrag die slug nicht im Feld post_name in der Datenbank *_posts, bis Sie publish mindestens einmal .

Überlegung 2:

Wenn Sie einen neuen Beitrag hinzufügen, speichern Sie ihn mit einem post_status von Entwurf oder übergeben Sie einfach die Entwurf -Stufe und gehen Sie direkt zu Veröffentlichen und setzen Sie den Beitrag zurück In einen Entwurf post_status wird der Slug in die Spalte post_name in der Tabelle *_posts eingefügt.

Warum ist das wichtig:

  • In Bezug auf die Überlegung 1 ...

WordPress benötigt mindestens eine identifizierende Markierung, normalerweise die id oder den post_name, die eindeutig ist, um einen Beitrag abzurufen.

Sie werden bemerken, dass WordPress Sie zu einer Vorschau-URL führt, wenn Sie einen Entwurf erstellen und versuchen, eine Vorschau davon anzuzeigen:

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

Dies geschieht, weil der fragliche Beitrag nur anhand der ID identifiziert und in der Vorschau angezeigt werden kann, mit der er in der Datenbank verknüpft ist.

  • In Bezug auf die Überlegung 2 ...

Wenn Sie veröffentlichen den Beitrag mindestens einmal, dann legen Sie ihn wieder in Entwurf , können Sie auf den Beitrag zugreifen, während Sie in Entwurf Status mit der Schnecke ( ziemlich Permalink), weil die Spalte post_name den Slug-Wert enthält.

Einige Beispielcodes:

Mit dem folgenden Code können Sie Posts in einem Draft oder Pending -Status zurückgeben, indem Sie den Slug verwenden, solange der Post mindestens einmal zuvor veröffentlicht wurde (siehe Überlegung 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');

Das Obige funktioniert für angemeldete und abgemeldete Benutzer.

Was passiert, wenn Sie abgemeldet sind und eine Vorschau eines Entwurfs anzeigen möchten?

Ok, wenn draf noch nicht mindestens einmal veröffentlicht wurde, können Sie den Beitrag nur in folgendem Format in der Vorschau anzeigen:

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

WordPress hängt von diesem Format ab, um einen Beitrag ohne Slug zu finden.

Wenn Sie jedoch abgemeldet sind, können Sie diesen Beitrag trotz der im obigen Beispiel verwendeten pre_get_posts-Logik nicht sehen.

Stattdessen müssen Sie den Filter the_posts aktivieren und den Beitrag wieder zu den Ergebnissen hinzufügen, die Sie anzeigen möchten, da WP_Query draft Beiträge aus der Ergebnismenge für abgemeldete Benutzer ausschließt, da abgemeldete Benutzer nicht über die verfügen ordnungsgemäße Benutzerfähigkeiten.

Wenn Sie andererseits versuchen (während Sie abgemeldet sind), auf einen Beitrag zuzugreifen, der dem in Betracht gezogenen 1 ähnelt, und zwar über die Standard-Vorschau-URL, wie oben im Beispiel http://example.com/?p=123&preview=true angegeben (mit oder ohne preview=true), erhalten Sie einen 404 Hinweis "Seite nicht gefunden".

Der folgende Beispielcode behebt Folgendes:

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

Großartig ... aber Moment mal, das nervt immer noch, weil du ein URL-Format wie http://example.com/?p=123 verwenden musst, um auf den Beitrag zuzugreifen.

Zurück zum Hauptproblem in Überlegung 1 , die einzigen Lösungen, die ich mir vorstellen kann, sind die folgenden:

Lösung Nr. 1

  • speichern Sie den Entwurf eines Beitrags und finden Sie den Beitrag anhand seines Titels, indem Sie den Slug in einen Titel umwandeln.

Beispiel...

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

Das oben Gesagte ... ↑ ... ist eine schlechte Idee, aber nur ein Beispiel für die Länge, die Sie benötigen. Warum dies eine schlechte Idee ist, ist einfach. Sie müssen sicherstellen, dass Sie keine doppelten Beitragstitel in der Datenbank haben, und Sie müssen sicherstellen, dass Sie den Slug nicht so ändern, dass er sich vom Titel unterscheidet, wenn Sie ihn als Entwurf speichern .

Ich bin voller Probleme, wie Sie sehen können.

Lösung Nr. 2

Wahrscheinlich ist es eine bessere Möglichkeit, den post_status des Posts auf publish zu setzen, damit die Spalte post_name den Slug-Wert erhält, und den Post dann sofort wieder in einen draft -Status zu versetzen .

Wenn Sie das manuell machen, ist das ein Kinderspiel. Hier ist ein 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);

Der erste an die Aktion post_submitbox_misc_actions angehängte Rückruf fügt dem Bearbeitungsbildschirm "Öffentliche Vorschau zulassen" ein Kontrollkästchen hinzu ...

 enter image description here 

... Wenn Sie dieses Kontrollkästchen markieren, wird dies durch den zweiten Rückruf bei der Aktion save_post erkannt.

In der Aktion save_post prüfen wir, ob unser Kontrollkästchen in $_POST superglobal vorhanden ist. Wenn es vorhanden ist, setzen wir den Post-Status auf publish und setzen ihn dann sofort wieder auf draft .

Jetzt können Sie über ihre Slugs/Pretty Permalinks auf Entwurfspostings zugreifen, die angemeldet oder abgemeldet sind.

Jetzt alle zusammen:

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