it-swarm.com.de

register_post_status - show_in_admin_all_list & show_in_admin_status_list hat keinen Einfluss auf die Abfrage

Im register_post_status habe ich show_in_admin_all_list & show_in_admin_status_list für meinen benutzerdefinierten Status my_hidden_status bereits deaktiviert.

Aus dem Abfrageprotokoll wird der post_status my_hidden_status jedoch immer noch nicht herausgefiltert (beim Laden von edit.php)

z.B.

SELECT post_status, COUNT (*) AS num_posts FROM st_posts WHERE post_type = 'my_cpt' GROUP BY post_status;

Der post_status, den ich filtern wollte, ist tatsächlich über 90% meines CPT, wenn die Abfrage also wie folgt umgeschrieben wird

SELECT post_status, COUNT( * ) AS num_posts FROM st_posts WHERE
post_type = 'my_cpt' AND post_status != 'my_hidden_status' GROUP BY
post_status;

Es kann die Leistung erheblich verbessern.

Es ist ein Fehler?

5
Yoga

TL; DR:Es ist kein Fehler (wie wir es allgemein verstehen), sondern eine Funktion, die nie vollständig implementiert wurde in WordPress.


Status von register_post_status()

Die Funktion register_post_status() wurde in WordPress nie vollständig implementiert. Wenn Sie WordPress Codex-Eintrag für register_post_status () Funktion überprüfen, werden Sie sehen, dass es in einem Hinweis deutlich erwähnt wird:

HINWEIS:

Diese Funktion fügt NICHT den Status des registrierten Beitrags zum Admin-Bereich hinzu. Diese Funktionalität ist bis zur zukünftigen Entwicklung . Bitte beziehen Sie sich auf Trac Ticket # 12706 . Betrachten Sie den Aktions-Hook post_submitbox_misc_actions , um diesen Parameter hinzuzufügen.

Wenn Sie das Ticket Related Ticket besuchen, werden Sie feststellen, dass die Diskussion zur vollständigen Implementierung bereits seit über 8 Jahren (ab März 2010) andauert! Da es sich bei WordPress jedoch um Open-Source-Software handelt und nicht viele Freiwillige bereit waren, an dieser Funktion zu arbeiten, steht die ordnungsgemäße Implementierung noch aus.

Das Trac Ticket # 12706 gibt in der Beschreibung Folgendes an:

Ein Entwickler sollte in der Lage sein, einen benutzerdefinierten Beitragsstatus mit register_post_status () zu registrieren. Die Benutzeroberfläche für Administratoren (einschließlich Post-Submit-Feld und Schnellbearbeitung) sollte diesen neuen benutzerdefinierten Post-Status widerspiegeln . Darüber hinaus gibt es im Kern viele hartcodierte Verweise auf den Status "Entwurf" und "Ausstehend", die die Post-Status-API ordnungsgemäß verwenden sollten.

Alle vorhandenen Argumente für register_post_status () sollten vollständig implementiert sein , sollten auch Argumente für jeden Beitragstyp unterstützen. Wenn die Dinge im Kern implementiert werden, wird es wahrscheinlich einen Bedarf an unterstützenden Funktionen und API-Komponenten geben.

Wenn Sie sich nun den WordPress-Kerncode ansehen, werden Sie feststellen, dass diese Beschreibung immer noch gültig ist. Das bedeutet:

  • Die Admin-Benutzeroberfläche (einschließlich Post-Submit-Feld und Schnellbearbeitung) spiegelt nicht den benutzerdefinierten Post-Status wider . Überprüfen Sie diesen Teil des Codes im Kern:

    <?php _e( 'Status:' ); ?> <span id="post-status-display">
    <?php
        switch ( $post->post_status ) {
            case 'private':
                _e( 'Privately Published' );
                break;
            case 'publish':
                _e( 'Published' );
                break;
            case 'future':
                _e( 'Scheduled' );
                break;
            case 'pending':
                _e( 'Pending Review' );
                break;
            case 'draft':
            case 'auto-draft':
                _e( 'Draft' );
                break;
        }
    ?>
    </span>
    

    Der CODE enthält kein Aktions-/Filter-Hook für einen benutzerdefinierten Post-Status oder für jede Änderung. Derzeit ist es also nur logisch, JavaScript zu verwenden, um die Benutzeroberflächenimplementierung zu ändern, bis diese Funktion in WordPress Core implementiert ist.

  • Alle vorhandenen Argumente zuregister_post_status () sind noch nicht vollständig implementiert & sehen daher möglicherweise fehlerhaft aus.

  • Für die vollständige Implementierung der Post-Status-API ist viel mehr Diskussion und Arbeit erforderlich.

Was tun gegen diesen Mangel an Funktionen oder Fehler?

Nennen wir es einen Mangel an Funktionen oder einen Fehler, bleibt die Tatsache: Es muss noch viel mehr getan werden, um die Post-Status-API zu vervollständigen. Wenn dies für Sie zu wichtig ist, sollten Sie sich an der Diskussion im oben genannten Support-Ticket beteiligen, um den Entwicklungsprozess zu beschleunigen.

Obwohl der gesamte Entwicklungsprozess viel ehrenamtliche Arbeit erfordert, können Sie dennoch einen Kommentar zu dem Argument show_in_admin_all_list abgeben, der sich nicht auf die Abfrage auswirkt, sodass zumindest dieser Teil der Anomalie früher als der Rest der Status-API verbessert werden kann.

Was ist zu tun, bis der Core die Funktionen nicht mehr ordnungsgemäß implementiert?

Gegenwärtig wirkt sich das Argument show_in_admin_all_list nur auf den Status-Header-Teil All(*) der Liste "Alle Beiträge" aus. Beispiel:

 All Posts Listing Status Header (All Posts Selected) 
Image-1: Alle Beiträge, die Status-Header anzeigen (Alle Beiträge ausgewählt)

Es wirkt sich jedoch nicht auf die Posts aus, die in der Liste angezeigt werden (obwohl dies der Fall sein sollte).

Um sicherzustellen, dass Posts mit Ihrem benutzerdefinierten Status my_hidden_status nicht auch in der Liste angezeigt werden, müssen Sie das Argument public auf false setzen.

Dadurch sieht der Funktionsaufruf register_post_status() folgendermaßen aus:

register_post_status( 'my_hidden_status', array(
    'label'                     => _x( 'My Hidden Status', 'post' ),
    'public'                    => false,
    'show_in_admin_all_list'    => false, 
    'show_in_admin_status_list' => false,
    'label_count'               => _n_noop( 'My Hidden Status <span class="count">(%s)</span>', 'My Hidden Status <span class="count">(%s)</span>' )
) );

Dies zeigt die korrekte Anzahl in der Statusüberschrift für All(*) an und entfernt auch die Posts mit my_hidden_status aus der Liste All Posts oder All {custom_post_type}.

Natürlich wird dies Posts mit my_hidden_status im WordPress Admin Panel im Wesentlichen unzugänglich machen. Wenn das die Absicht war, dann gut, ansonsten können Sie den show_in_admin_status_list verwenden, um die Posts mit my_hidden_status in einem separaten Listing-Header anzuzeigen:

register_post_status( 'my_hidden_status', array(
    'label'                     => _x( 'My Hidden Status', 'post' ),
    'public'                    => false,
    'show_in_admin_all_list'    => false, 
    'show_in_admin_status_list' => true,
    'label_count'               => _n_noop( 'My Hidden Status <span class="count">(%s)</span>', 'My Hidden Status <span class="count">(%s)</span>' )
) );

Daraufhin werden die Post Lists mit dem Status my_hidden_status in einer separaten Kopfzeile wie der folgenden angezeigt:

 All Posts Listing Status Header (Custom Status Selected) 
Image-2: Alle Posts, die Status-Header anzeigen (Benutzerdefinierter Status ausgewählt)

Problem bei der DB-Abfrageoptimierung:

Die zugehörige DB-Abfrage stammt aus der Funktion wp_count_posts() in der Datei wp-includes/post.php. Wenn Sie sich den bezogenen CODE ansehen, werden Sie feststellen, dass die Argumente der Funktion register_post_status() dort nicht implementiert sind. Es gibt auch keine Möglichkeit, diesen Teil des Kern-CODE zu filtern oder zu erweitern:

$query = "SELECT post_status, COUNT( * ) AS num_posts FROM {$wpdb->posts} WHERE post_type = %s";
if ( 'readable' == $perm && is_user_logged_in() ) {
    $post_type_object = get_post_type_object( $type );
    if ( ! current_user_can( $post_type_object->cap->read_private_posts ) ) {
        $query .= $wpdb->prepare(
            " AND (post_status != 'private' OR ( post_author = %d AND post_status = 'private' ))",
            get_current_user_id()
        );
    }
}
$query .= ' GROUP BY post_status';

Sofern sowohl show_in_admin_all_list als auch show_in_admin_status_list für einen bestimmten Status nicht auf false gesetzt sind, sollten verwandte Posts ohnehin nicht aus der Abfrage entfernt werden. Andernfalls kann WordPress nicht den richtigen status header generieren (wie in Bild-2 gezeigt).

Wenn jedoch sowohl show_in_admin_all_list als auch show_in_admin_status_list auf false gesetzt sind, benötigt WordPress die Zählerinformationen für diesen benutzerdefinierten Status nicht. In diesem Fall haben Sie logischerweise eine kleine Verbesserung der Abfrageleistung mit AND post_status != 'my_hidden_status', wenn Sie eine große Anzahl von Posts (wie z. B. Millionen) haben und die meisten Ihrer Posts (wie Sie sagten, 90%) aus diesem benutzerdefinierten Status stammen.

Es gibt jedoch zwei Gründe, warum core diesen Teil des CODE möglicherweise nicht aktualisiert, obwohl es in Ihrem speziellen Fall zu einem geringen Leistungsgewinn kommen kann:

  1. WordPress Database verwendet einen Index mit dem Namen type_status_date, der wp-posts-Tabelleneinträge basierend auf post_type-, post_status-, post_date- und ID-Feldern indiziert. Abfragen sind also auch ohne den Teil AND post_status != 'my_hidden_status' schnell genug .

    Ich habe mit über 15.000 Beiträgen getestet und es dauert nur ein paar Millisekunden. Überprüfen Sie dieses MySQL-Dokument , um weitere Informationen zur GROUP BY-Optimierung mit Index zu erhalten. Mit einigen Änderungen am MySQL-Index können Sie sogar bessere Ergebnisse erzielen, ohne WP Core zu ändern. Wenn Sie beispielsweise einen weiteren Index mit den Spalten post_type und post_status hinzufügen, können Sie einige Millisekunden Zeit sparen.

  2. Auch wenn das Hinzufügen von AND post_status != 'my_hidden_status' die Abfrage in Ihrem speziellen Fall beschleunigen kann (nur um Millisekunden), aktualisiert WordPress sie möglicherweise nicht, da WordPress die Möglichkeit in Betracht ziehen muss, dass ein verborgener benutzerdefinierter Status nur wenige Beiträge enthält . In diesen Fällen führt das Hinzufügen von AND post_status != 'my_hidden_status' dazu, dass die Abfrageergebnisse etwas langsamer werden (nur um einige Millisekunden).

Wenn man also alles berücksichtigt, kann WordPress die Abfrage möglicherweise mit AND post_status != 'my_hidden_status' aktualisieren oder nicht, wenn sowohl show_in_admin_all_list als auch show_in_admin_status_list für einen benutzerdefinierten Status auf false gesetzt sind. Meiner Meinung nach wird jedoch die Flexibilität für die Entwickler verbessert, wenn zumindest die zugehörige Abfrage filterbar gemacht wird.

4
Fayaz

Die Abfrage, die Sie filtern möchten, wird tatsächlich von der Funktion wp_count_posts aufgerufen. Die einzige Möglichkeit, diese Abfrage zu filtern, ist die Verwendung des Filters query (innerhalb der Methode wpdb class query zu finden).

Da der Filter query für alle mit der Instanz $wpdb aufgerufenen MySQL-Abfragen verwendet wird, ist es besser, den Filter genau an der Stelle zu registrieren, an der Sie ihn benötigen. Fügen Sie dazu Ihren Filter für die Aktion load-edit.php hinzu.

/* register the filter from edit.php page (works for all post types) */
add_action('load-edit.php', 'wpse_initiate_filter');
function wpse_initiate_filter($query) {
    add_filter('query', 'wpse_filter_posts_count_query');
}

/* modify original query to filter out my_hidden_status */
function wpse_filter_posts_count_query($query) {
    if (strpos($query, 'SELECT post_status') === 0) {
        $query = str_replace(" GROUP BY", " AND post_status != 'my_hidden_status' GROUP BY", $query);
    }
    return $query;
}
1
Shazzad

Ist es ein Bug? Es macht ein wenig mehr Arbeit als nötig, führt jedoch zu keiner unerwarteten Ausgabe und vermeidet potenzielle Probleme mit anderen Site-Setups. Also würde ich (meistens) nein sagen.

Die fragliche Abfrage dient dazu, die Anzahl der gefundenen Beiträge zu zählen, bevor sie auf dem Bearbeitungsbildschirm angezeigt werden. Es zählt alle Beiträge nach Status, sodass es diese Nummern zur Hand hat, wenn die Seite sie später benötigt.

Mein Verdacht ist, dass die Abfrage absichtlich einfach gehalten wurde, um die Möglichkeit zu verhindern, dass mehrere, wenig genutzte Post-Status die Abfrage verstopfen und verlangsamen. Beim Testen auf phpMyAdmin beispielsweise dauerte die Basisabfrage 0,0011 Sekunden mit ungefähr 300 Posts. Durch Hinzufügen von Klauseln zum Herausfiltern von 5 nicht verwendeten oder wenig verwendeten Post-Status wurde die Zeit auf 0,0024 erhöht.

In Ihrer Situation haben Sie Recht, dass das Herausfiltern von 90% der potenziellen Ergebnisse die Abfrage beschleunigen würde. Sie können versuchen, es mit dem Abfragefilter zu filtern.

Als Randnotiz: Als ich dies recherchierte, bemerkte ich, dass "public" => true in register_post_status den show_in_admin_all_list -Wert überschreibt und Posts mit diesem Status auf dem Bearbeitungsbildschirm anzeigt. Ich würde diesen Teil als Fehler bezeichnen, da in anderen register_* -Funktionen die spezifischeren Argumente dazu neigen, das Argument public zu überschreiben.

1
SeventhSteel