WP管理面板:在链接搜索结果中包含自定义文章类型归档

4
我一直在网上和WP文档中搜索此类示例,以寻找合适的钩子,但我找不到一个合适的钩子,所以很抱歉发帖提问时没有好的示例可以说明我要做什么!当您在编辑器中将链接添加到文本或按钮时,您可以搜索要链接到的页面/文章。您无法搜索的是文章类型存档链接。我想能够在搜索框中输入文章类型名称(如下图所示),并在搜索结果中包括文章类型存档链接。在此示例中,我有一个名为“成员”的文章类型,我想链接到它。

enter image description here

我经常需要这样做,但最终只是在框中键入/post-type-link,我认为这不是一个优雅的解决方案,对用户来说也很笨重。
我尝试编写了一些代码,但我不认为我有正确的钩子:
function include_cpt_search( $query ) {

    if ( is_admin() && is_single() ) {
        $query->set( 'post_type', array( 'services' ) );
    }

    return $query;

}
add_filter( 'pre_get_posts', 'include_cpt_search' ); 

有人以前做过这个吗?知道我可以使用的筛选器或钩子吗?任何东西都好!
1个回答

3
在RichText工具栏中,链接格式使用位于“/wp/v2/search”(参见/wp/v2/search)的搜索REST API端点。因此,尽管该端点没有提供专门用于过滤响应的挂钩,但是您可以使用rest_post_dispatch添加自定义链接到通过/wp/v2/search返回的搜索结果。
因此,在下面的示例中,我检查路由是否为/wp/v2/search,如果是,则添加(自定义)文章类型的归档链接。还请注意,您应该提供包含此处所述项(LinkControl组件使用的内容)的数组。
基本示例
仅包括一个帖子类型,其中其名称与搜索关键字完全匹配。
add_filter( 'rest_post_dispatch', 'so_62472641', 10, 3 );
function so_62472641( $response, $server, $request ) {
    // Don't modify the data if the REST API route is not /wp/v2/search
    if ( 'post' !== $request->get_param( 'type' ) ||
        '/wp/v2/search' !== $request->get_route() ) {
        return $response;
    }

    // Let's see if there's a post type that matched the search keyword.
    $search = $request->get_param( 'search' );
    if ( ! $post_type = get_post_type_object( $search ) ) {
        return $response;
    }

    // Now add the post type archive URL, if any, to the response data.
    if ( $url = get_post_type_archive_link( $search ) ) {
        $data = (array) $response->get_data();

        $data[] = [
            'id'    => 'post_type-' . $search,
            'type'  => 'Post Type Archive',
            'title' => $post_type->label,
            'url'   => $url,
        ];

        $response->set_data( $data );
    }

    return $response;
}

扩展示例

包括所有帖子类型,其中名称/标签与搜索关键字匹配。

add_filter( 'rest_post_dispatch', 'so_62472641', 10, 3 );
function so_62472641( $response, $server, $request ) {
    // Don't modify the data if the REST API route is not /wp/v2/search
    if ( 'post' !== $request->get_param( 'type' ) ||
        '/wp/v2/search' !== $request->get_route() ) {
        return $response;
    }

    $search = $request->get_param( 'search' );
    $post_types = get_post_types( [], 'objects' );
    $extra_data = [];

    // Let's see if there's a post type that matched the search keyword.
    foreach ( $post_types as $obj ) {
        if ( $search === $obj->name ||
            // look for the search keyword in the post type name/slug and labels (plural & singular)
            false !== stripos( "{$obj->name} {$obj->label} {$obj->labels->singular_name}", $search )
        ) {
            if ( $url = get_post_type_archive_link( $obj->name ) ) {
                $extra_data[] = [
                    'id'    => 'post_type-' . $obj->name,
                    'type'  => 'Post Type Archive',
                    'title' => $obj->label,
                    'url'   => $url,
                ];
            }
        }
    }

    // Now add the post type archive links, if any, to the response data.
    if ( ! empty( $extra_data ) ) {
        $response->set_data( array_merge( (array) $response->get_data(), $extra_data ) );
    }

    return $response;
}

第二个示例的样本输出

第二个示例的样本输出

注意:以上是真实响应的屏幕截图,但我故意(通过 PHP)将域名更改为example.com(即实际域名不同)。

并且这两个示例都经过尝试和测试,在 WordPress 5.5.1(撰写时的最新版本)上运行正常。如果你想的话,还可以排除默认的post文章类型。

附加说明

  1. It should be noted that the examples do not take into account the pagination, which means, if there were 10 post types that matched the search keyword, then they would always be included in the response (on page 1, 2, 3, etc.). So you might want to just use the first example because at least it always includes at most 1 post type only. However, with the second example, you can actually limit the $extra_data to, say, 5 items (per page - but it's up to you on how to distribute the items per page).

  2. You can also use a custom search handler class, e.g. one that extends the default class (WP_REST_Post_Search_Handler) and use the wp_rest_search_handlers hook to add your class to the list. Here's a very basic example...

    In your-class.php:

    class My_WP_REST_Post_Search_Handler extends WP_REST_Post_Search_Handler {
        // ... you'll need to actually write the code on your own..
    }
    
    return new My_WP_REST_Post_Search_Handler;
    

    In the theme's functions.php file or somewhere in your plugin:

    add_filter( 'wp_rest_search_handlers', 'my_wp_rest_search_handlers' );
    function my_wp_rest_search_handlers( $search_handlers ) {
        $search_handlers[] = include_once '/path/to/the/your-class.php';
    
        return $search_handlers;
    }
    

非常有趣!谢谢。我明天/星期五会测试一下,如果符合预期,就接受这个答案。 - lukeseager

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接