web-dev-qa-db-ja.com

register_post_status - show_in_admin_all_list&show_in_admin_status_listはクエリに影響しません

register_post_statusでは、私のカスタムステータスshow_in_admin_all_listに対してshow_in_admin_status_listmy_hidden_statusを無効にしました

しかし、クエリログからpost_status my_hidden_statusはまだ除外されていません(edit.phpをロードするとき)

例えば.

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

私が実際にフィルタリングしたいpost_statusは私のCPTの90%以上なので、クエリが以下のように書き直されるなら

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;

それはパフォーマンスを大幅に向上させることができます。

それはバグですか?

5
Yoga

TL; DR:これはバグではなく(一般に理解されているように)、むしろ機能でした- 完全に実装されていない WordPress。


register_post_status()のステータス

register_post_status()関数がWordPressに完全に実装されることはありませんでした。 WordPress register_post_status()関数のCodexエントリ をチェックすると、通知で明確に言及されていることがわかります。

注意:

この関数は、登録済みの投稿ステータスを管理パネルに追加しません。この機能は保留中の将来の開発です。 Trac Ticket#12706 を参照してください。このパラメーターを追加するには、アクションフック post_submitbox_misc_actions を検討してください。

また、 関連チケット にアクセスすると、それを完全に実装するための議論が8年以上にわたって行われていることがわかります(2010年3月から)。ただし、WordPressはオープンソースコミュニティ主導のソフトウェアであり、この機能に取り組むボランティアはあまりいないため、適切な実装はまだ保留されています。

Trac Ticket#12706 は、説明で次のことを示しています。

開発者はregister_post_status()を使用してカスタム投稿ステータスを登録できる必要があります。管理UI(投稿送信ボックスとクイック編集を含む)この新しいカスタム投稿ステータスを反映する必要があります。さらに、ポストステータスAPIを適切に使用する必要があるコアの「ドラフト」および「保留」ステータスへのハードコーディングされた参照が多数あります。

register_post_status()のすべての既存の引数は完全に実装する必要があります。投稿タイプごとの引数もサポートする必要があります。コア全体に物事が実装されると、おそらくAPIの機能とビットをサポートする必要があります。

WordPressコアコードを見ると、この説明がまだ有効であることがわかります。つまり:

  • 管理UI(投稿送信ボックスとクイック編集を含む)カスタム投稿ステータスを反映しません。コアの CODEのこの部分 を確認します。

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

    CODEにはカスタム投稿ステータスのアクション/フィルターフックなしまたは変更が含まれます。したがって、現時点で唯一の論理的な方法は、この機能がWordPressコアに実装されるまで、JavaScriptを使用してUI実装を変更することです。

  • register_post_status()へのすべての既存の引数はまだ完全には実装されていません&したがって、バグがあるように見える場合があります。

  • Post Status APIを完全に実装するには、さらに多くの議論と作業が必要です。

この機能不足またはバグについてどうすればよいですか?

機能の欠如、またはバグと呼んでも、事実は変わりません。PostStatus APIを完了するには、さらに多くの作業が必要です。したがって、これがあなたにとってあまりにも重要な場合は、上記のサポートチケットのディスカッションに参加して、開発プロセスを促進することをお勧めします。

開発プロセス全体では多くの自主的な作業が必要になりますが、クエリに影響を与えない引数show_in_admin_all_listについてコメントすることができます。これにより、少なくとも異常のこの部分を残りのStatus APIよりも早く改善できます。

コアが機能を適切に実装しないまでどうすればよいですか?

現在のように、show_in_admin_all_list引数は、すべての投稿リストのAll(*)ステータスヘッダー部分にのみ影響します。たとえば、

All Posts Listing Status Header (All Posts Selected)
Image-1:すべての投稿リストステータスヘッダー(すべての投稿が選択されている)

ただし、リストに表示される投稿には影響しません(ただし、そうする必要があります)。

カスタムステータスmy_hidden_statusの投稿がリストにも表示されないようにするには、public引数をfalseに設定する必要があります。

これにより、register_post_status()関数呼び出しが次のようになります。

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

これにより、All(*)ステータスヘッダーに正しいカウントが表示され、my_hidden_statusまたはAll PostsリストからAll {custom_post_type}の投稿も削除されます。

もちろん、これにより、基本的にWordPress管理パネルからmy_hidden_statusの投稿にアクセスできなくなります。それが意図である場合は、それ以外の場合は問題ありません。別のリストヘッダーにshow_in_admin_status_listを使用して、my_hidden_statusの投稿を表示できます。

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

これにより、次のような別のヘッダーにステータスmy_hidden_statusの投稿リストが表示されます。

All Posts Listing Status Header (Custom Status Selected)
Image-2:すべての投稿リストステータスヘッダー(カスタムステータスが選択されている)

DBクエリ最適化の問題:

関連するDBクエリは、wp-includes/post.phpファイルのwp_count_posts()関数から取得されます。 関連CODE を見ると、register_post_status()関数からの引数がそこに実装されていないことがわかります。また、コアCODEのこの部分をフィルタリングまたは拡張する方法もありません。

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

特定のステータスでshow_in_admin_all_listshow_in_admin_status_listの両方がfalseに設定されていない限り、関連する投稿をクエリから削除しないでください。そうしないと、WordPressは適切なstatus headerを生成できません(画像2を参照)。

ただし、show_in_admin_all_listshow_in_admin_status_listの両方がfalseに設定されている場合、WordPressはそのカスタムステータスのカウント情報を必要としません。論理的には、このケースでは、AND post_status != 'my_hidden_status'部分でクエリパフォーマンスが少し向上します。多数の投稿(数百万など)があり、ほとんどの投稿(90%を言った)がそのカスタムステータスからのものである場合。

それでも、特定のケースではパフォーマンスが少し向上する可能性があるにもかかわらず、コアがCODEのこの部分を更新しない場合がある2つの理由があります。

  1. WordPressデータベースは、type_status_datewp-postspost_typeIDフィールドに基づいてpost_statusテーブルエントリにインデックスを付けるpost_dateという名前のインデックスを使用します。 つまり、クエリはAND post_status != 'my_hidden_status'部分がなくても十分に高速です

    15K以上の投稿でテストしましたが、数ミリ秒しかかかりません。インデックス付きGROUP BY最適化の詳細については、 このMySQLドキュメント を確認してください。 MySQLインデックスの調整により、WP Coreを変更しなくても、より良い結果が得られる場合があります。たとえば、post_type列とpost_status列で別のインデックスを追加すると、数ミリ秒のゲインが得られる場合があります。

  2. 特定のケースでAND post_status != 'my_hidden_status'を追加するとクエリが(ミリ秒単位で)速くなる場合がありますが、WordPressが非表示のカスタムの可能性を考慮する必要があるため、WordPressステータスには数個の投稿しかありません。これらの場合、AND post_status != 'my_hidden_status'を追加すると、実際にはクエリ結果が少し遅くなります(数ミリ秒だけ)。

したがって、すべてを考慮すると、WordPressは、カスタムステータスのAND post_status != 'my_hidden_status'show_in_admin_all_listの両方がfalseに設定されている場合、show_in_admin_status_listでクエリを更新する場合としない場合があります。ただし、少なくとも、関連するクエリをフィルター可能にすると、開発者の柔軟性が向上します。

4
Fayaz

フィルタリングしようとしているクエリは、実際にはwp_count_posts関数によって呼び出されます。このクエリをフィルタ処理する唯一の方法は、queryフィルタを使用することです(wpdbクラスqueryメソッド内にあります)。

フィルタqueryは、$wpdbインスタンスで呼び出されるすべてのmysqlクエリに使用されるので、必要な場所からフィルタを登録することをお勧めします。そのためには、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

それはバグですか?それはそれがしなければならないよりももう少し多くの仕事をしています、しかしそれは少しの予期しない出力ももたらさず、そしてそれは他のサイト設定に関する潜在的な問題を避けます。だから私は(ほとんど)ノーと言うでしょう。

問題のクエリは、編集画面に表示する前に見つかった投稿の数を数えるのに役立ちます。それはページが後でそれらを必要とするならそれがこれらの数が便利であるようにステータスによってすべての投稿を数えます。

私の考えは、あまり使われていない投稿ステータスが詰まってクエリが遅くなる可能性を防ぐために、クエリを意図的に単純にしたことです。たとえば、phpMyAdminのテストでは、ベースクエリは0.0011秒かかり、約300件の投稿がありました。 5つの未使用またはほとんど使用されていない投稿ステータスを除外するための句を追加すると、時間が0.0024に増えました。

あなたの状況では、潜在的な結果の90%を除外することがクエリをスピードアップすることは正しいと思います。 query filter でそれをフィルタリングしてみることができます。

補足として:これを調べているときに、"public" => trueregister_post_statusshow_in_admin_all_listの値をオーバーライドして、編集画面にそのステータスの投稿を表示することに気付きました。他のregister_*関数では、より特定的な引数がpublic引数をオーバーライドする傾向があるので、私はその部分をバグと呼びます。

1
SeventhSteel