web-dev-qa-db-fra.com

register_post_status - show_in_admin_all_list & show_in_admin_status_list n'affecte pas la requête

Dans le register_post_status, j'ai déjà désactivé show_in_admin_all_list & show_in_admin_status_list pour mon statut personnalisé my_hidden_status

Toutefois, dans le journal de requête, le post_status my_hidden_status n'est toujours pas filtré (lors du chargement de edit.php)

par exemple.

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

Le post_status que je voulais filtrer représente en réalité plus de 90% de mon CPT, donc si la requête est réécrite en tant que

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;

Cela peut grandement améliorer les performances.

C'est un bug?

5
Yoga

TL; DR: _ Ce n'est pas un bug (comme nous l'entendons généralement), c'est plutôt une fonctionnalité qui était jamais entièrement implémentée in WordPress.


Statut de register_post_status()

La fonction register_post_status() n’a jamais été entièrement implémentée dans WordPress. Si vous vérifiez l'entrée WordPress Codex pour la fonction register_post_status () , vous verrez qu'il est clairement mentionné dans un avis:

AVIS:

Cette fonction n'ajoute pas le statut de la poste enregistrée au panneau d'administration. Cette fonctionnalité est en attente de développement futur . Veuillez vous référer à Trac Ticket # 12706 . Considérez le hook d’action post_submitbox_misc_actions pour ajouter ce paramètre.

De plus, si vous visitez le Ticket Related , vous verrez que la discussion pour le mettre pleinement en œuvre dure maintenant depuis plus de 8 ans (à partir de mars 2010)! Cependant, étant donné que WordPress est un logiciel Open Source piloté par la communauté et que peu de volontaires étaient disposés à travailler sur cette fonctionnalité, elle n’a toujours pas été mise en œuvre correctement.

Le Trac Ticket # 12706 indique ce qui suit dans la description:

Un développeur doit pouvoir enregistrer un statut de publication personnalisé à l’aide de register_post_status () . L'interface utilisateur d'administration (y compris la boîte d'envoi et la modification rapide) doit refléter ce nouveau statut d'article personnalisé . En outre, il existe de nombreuses références codées en dur aux statuts "brouillon" et "en attente" dans le noyau qui devraient utiliser correctement l'API post-statut.

Tous les arguments existants de register_post_status () devraient être entièrement implémentés , devrait également prendre en charge les arguments de type post-post. Au fur et à mesure que les choses seront mises en œuvre de manière centralisée, il faudra probablement des capacités de support et des éléments d’API.

Maintenant, si vous regardez le code principal de WordPress, vous verrez que cette description est toujours valide. Cela signifie:

  • L'interface utilisateur de l'administrateur (y compris la boîte d'envoi et la modification rapide) ne reflète pas le statut de l'article personnalisé . Vérifiez cette partie du code dans le noyau:

    <?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>
    

    Le code ne contient aucune action/filtre de filtrage pour tout statut de publication personnalisé ou pour quelque modification que ce soit. La seule solution logique pour le moment consiste donc à utiliser du JavaScript pour modifier la mise en œuvre de l'interface utilisateur jusqu'à ce que cette fonctionnalité soit implémentée dans le noyau WordPress.

  • Tous les arguments existants deregister_post_status ()} _n'est pas encore complètement implémenté & peut donc paraître bogué.

  • Et beaucoup plus de discussions et de travail sont nécessaires pour la mise en œuvre complète de l'API Post Status.

Que faire à propos de ce manque de fonctionnalité ou de bogue?

Appelez cela un manque de fonctionnalités ou appelez-le un bogue, le fait demeure: il reste encore beaucoup de travail à faire pour compléter l'API Post Status. Donc, si cela est trop important pour vous, il est préférable de participer à la discussion dans le ticket de support mentionné ci-dessus pour accélérer le processus de développement.

Bien que l'ensemble du processus de développement nécessite beaucoup de travail volontaire, vous pouvez toujours commenter l'argument show_in_admin_all_list n'affectant pas la requête, afin qu'au moins cette partie de l'anomalie puisse être améliorée plus tôt que le reste de l'API Status.

Que faire jusqu'à ce que Core n'implémente pas correctement les fonctionnalités?

À l'heure actuelle, l'argument show_in_admin_all_list n'affecte que l'en-tête d'état All(*) de la liste de tous les messages, par exemple:

All Posts Listing Status Header (All Posts Selected)
Image-1: Tous les messages Statut En-tête (Tous les messages sélectionnés)

Cependant, cela n’affecte pas les messages qui apparaissent dans la liste (bien que ce soit le cas).

Pour vous assurer que les publications avec votre statut personnalisé my_hidden_status n'apparaissent pas également dans la liste, vous devez définir l'argument public sur false.

L’appel de la fonction register_post_status() se présentera ainsi:

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

Cela affichera le nombre correct dans l'en-tête d'état All(*) et supprimera également les publications avec my_hidden_status de la liste All Posts ou All {custom_post_type}.

Bien sûr, cela rendra essentiellement les publications avec my_hidden_status inaccessibles à partir du Panneau d’administration de WordPress. Si telle était l'intention, alors très bien, sinon, vous pouvez utiliser le show_in_admin_status_list pour afficher les publications avec my_hidden_status dans un en-tête de liste séparé:

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

Cela affichera les listes de publication avec le statut my_hidden_status dans un en-tête séparé, comme suit:

All Posts Listing Status Header (Custom Status Selected)
Image-2: Tous les messages En-tête de statut de la liste (Statut personnalisé sélectionné)

Problème d'optimisation de requête de base de données:

La requête de base de données associée provient de la fonction wp_count_posts() dans le fichier wp-includes/post.php. Si vous examinez le code relatif à [ , vous verrez que les arguments de la fonction register_post_status() ne sont pas implémentés ici. En outre, il n’existe aucun moyen de filtrer ou d’étendre cette partie du CODE principal:

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

Sauf si show_in_admin_all_list et show_in_admin_status_list sont définis sur false pour un statut particulier, les publications associées ne doivent de toute façon pas être supprimées de la requête. Sinon, WordPress ne pourra pas générer le status header approprié (comme indiqué dans l'image-2).

Toutefois, dans le cas où show_in_admin_all_list et show_in_admin_status_list sont définis sur false, WordPress n'a pas besoin des informations de nombre pour ce statut personnalisé. Donc, logiquement, dans ce cas, vous aurez une petite amélioration des performances de la requête avec la partie AND post_status != 'my_hidden_status', si vous avez un grand nombre de publications (comme Millions) et si la plupart de vos publications (comme vous l'avez dit à 90%) proviennent de ce statut personnalisé.

Il existe néanmoins deux raisons pour lesquelles Core ne met peut-être pas à jour cette partie du code même s'il peut y avoir un léger gain de performances dans votre cas particulier:

  1. La base de données WordPress utilise un index nommé type_status_datequi indexe les entrées de la table wp-posts en fonction des champs post_type, post_status, post_date et ID. Les requêtes sont donc assez rapides même sans la partie AND post_status != 'my_hidden_status'.

    J'ai testé avec 15K + messages et cela ne prend que quelques millisecondes. Consultez this Document MySQL pour plus d’informations sur l’optimisation GROUP BY avec index. Avec quelques ajustements de l'index MySQL, vous pouvez même obtenir de meilleurs résultats sans même changer WP Core. Par exemple, l'ajout d'un autre index avec les colonnes post_type et post_status peut vous faire gagner quelques millisecondes.

  2. Même si l'ajout de AND post_status != 'my_hidden_status' peut accélérer la requête (de l'ordre de quelques millisecondes) dans votre cas particulier, WordPress risque de ne pas la mettre à jour, car WordPress devra envisager la possibilité qu'un statut personnalisé masqué ne comporte que quelques publications . Dans ces cas, l'ajout de AND post_status != 'my_hidden_status' ralentira un peu les résultats de la requête (de quelques millisecondes seulement).

Donc, compte tenu de tout, WordPress peut ou non mettre à jour la requête avec AND post_status != 'my_hidden_status' lorsque show_in_admin_all_list et show_in_admin_status_list sont définis sur false pour un statut personnalisé. Cependant, à mon avis, rendre au moins la requête associée pouvant être filtrée améliorera la flexibilité des développeurs.

4
Fayaz

La requête que vous souhaitez filtrer est en réalité appelée par la fonction wp_count_posts. Le seul moyen de filtrer cette requête consiste à utiliser le filtre query (situé dans la méthode wpdb class query).

Comme le filtre query est utilisé pour toutes les requêtes mysql appelées avec l’instance $wpdb, il serait préférable d’enregistrer votre filtre à l’endroit exact où vous en avez besoin. Pour cela, ajoutez votre filtre sur l'action load-edit.php.

/* 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

Est-ce un bug? Cela demande un peu plus de travail que nécessaire, mais cela n'entraîne aucune sortie inattendue et évite les problèmes potentiels liés à la configuration d'autres sites. Donc je dirais non (principalement).

La requête en question sert à compter le nombre de publications trouvées avant de les afficher sur l'écran d'édition. Il compte tous les messages par statut afin de disposer de ces numéros si la page en a besoin ultérieurement.

Mon intuition est que la requête a été délibérément simplifiée pour éviter la possibilité d'encrassement et de ralentissement de plusieurs statuts de publication peu utilisés. Par exemple, lors des tests sur phpMyAdmin, la requête de base prenait 0,0011 seconde avec environ 300 publications. L'ajout de clauses pour filtrer 5 statuts de publication inutilisés ou peu utilisés a porté le temps à 0,0024.

Dans votre cas, vous avez raison de dire que le filtrage de 90% des résultats potentiels accélérerait la requête. Vous pouvez essayer de le filtrer avec le filtre query filter .

Remarque: lors de mes recherches, j’ai remarqué que si "public" => true dans register_post_status, il remplace la valeur show_in_admin_all_list et affiche les publications ayant ce statut sur l’écran de modification. Je qualifierais cette partie de bogue, car dans d'autres fonctions register_*, les arguments plus spécifiques ont tendance à remplacer le paramètre public arg.

1
SeventhSteel