使用 WordPress REST API 创建搜索小部件

已发表: 2016-03-28

WordPress 开发人员会意识到 REST API 已经存在了一段时间,但截至去年年底,它已集成到核心中,这意味着它现在可以在小部件和插件中使用。

在本文中,我们将构建一个不同的简单搜索小部件。 使用 WordPress REST API,此小部件将搜索外部 WordPress 网站并在小部件中显示结果。

这篇文章是我上一篇关于 WordPress REST API 你需要了解的内容的继续

创建知识库 - 简单的方法!

建立可搜索的知识库并帮助您的客户自助。

获取插件

构建小部件插件

与上一篇文章一样,假设了构建插件和小部件的一些基本知识。 如果您不确定,可以在本文末尾为您推荐一些阅读材料。

让我们看一下我们在上一篇文章中创建的现有插件。 您的代码应如下所示:


/**
* Plugin Name: KB - REST API Widget
* Author: Kirsty Burgoine
*/

class REST_API_Widget extends WP_Widget {

/**
* Sets up the widgets name etc
*/
public function __construct() {
    $widget_ops = array(
        'classname' => 'rest-api-widget',
        'description' => 'A REST API widget that pulls posts from a different website'
    );
    parent::__construct( 'rest_api_widget', 'REST API Widget', $widget_ops );
}

/**
* Outputs the content of the widget
*
* @param array $args
* @param array $instance
*/
public function widget( $args, $instance ) {
    // outputs the content of the widget

    $response = wp_remote_get( 'http://website-with-api.com/wp-json/wp/v2 /ht_kb/' );
    if( is_wp_error( $response ) ) {
        return;
    }

    $posts = json_decode( wp_remote_retrieve_body( $response ) );

    if( empty( $posts ) ) {
        return;
    }

    echo $args['before_widget'];
    if( !empty( $instance['title'] ) ) {
        echo $args['before_title'] . apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base ) . $args['after_title'];
    }

    // Main Widget Content Here
    if( !empty( $posts ) ) {
        echo '<ul>';
        foreach( $posts as $post ) {
            echo '<li><a href="' . $post->link. '">' . $post->title->rendered . '</a></li>';
        }
        echo '</ul>';
    }
    echo $args['after_widget'];
}

/**
* Outputs the options form on admin
*
* @param array $instance The widget options
*/
public function form( $instance ) {
    //outputs the options form on admin
    $title = ( !empty( $instance['title'] ) ) ? $instance['title'] : '';
    ?>
         <label for="<?php echo $this->get_field_name( 'title' ); ?>">Title: </label>
         <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" /> 
    <?php
}
}//end class
add_action( 'widgets_init', function(){
register_widget( 'REST_API_Widget' );
});

本质上,我们创建了一个新插件。 在该插件中,我们创建了一个小部件,该小部件显示来自不同网站的 Heroic Knowledge 库的自定义帖子列表。

我们现在要做的是修改它以创建一个搜索功能。

第 1 步:修改基本查询以获得不同的结果

在上一篇文章中,您会记得我们讨论了如何获取帖子列表以及如何更改参数以便我们可以获取知识库自定义帖子类型。

好吧,学习起来可能并不奇怪,这不是我们可以用 GET 方法做的全部。 通过使用过滤参数,我们实际上可以使用调用 WP_Query 时可用的任何参数。 例如,如果我们想更改显示的帖子数量,您可以添加:


/posts?filter[posts_per_page]=5

进行远程调用是这样的:


$response = wp_remote_get( 'http://website-with -api.com.com/wp-json/wp/v2/posts?filter[posts_per_page]=5' );

或者,如果我们只想显示一篇随机帖子,我们可以添加:


/posts?filter[orderby]=rand&filter[posts_per_page]=1

这对于搜索参数也是一样的。 在标准的 WP Query 中,参数如下所示:


's' => 'keyword'

因此,我们的远程调用需要如下所示:


$response = wp_remote_get( 'http://website-with -api.com.com/wp-json/wp/v2/posts?filter[s]=keyword');

一旦您了解将参数从 WP_Query 转换为 API url 字符串,这将非常简单。

有关可用参数的完整详细信息,请参阅 WP_Query 法典指南。

我们实际上并不想搜索标准帖子,我们想搜索知识库自定义帖子类型。 但是,正如我们在上一篇文章中看到的,这很容易做到,因为我们通过添加过滤器使我们的自定义帖子类型公开可用。 因此,我们需要做的就是通过将/posts/与自定义帖子类型的名称交换来查询知识库自定义帖子类型。 在这种情况下/ht_kb/ 。 远程调用现在看起来像这样:


$response = wp_remote_get( 'http://website-with-api.com/wp-json/wp/v2/ht_kb?filter[s]=keyword' );

第 2 步:搜索框和定制结果

所以现在我们已经研究了修改查询以按给定的搜索词过滤,下一步是创建一种获取该搜索词的方法。

首先,我们需要在插件中添加一个搜索框。 因为这只是一个简单的搜索表单,我们可以使用 WordPress 已经设置的 get_search_form() 函数,而不是创建单独的搜索表单。

在插件文件中,在您的小部件函数中查找带有注释 // Main Widget Content Here 的行并添加 get_search_form(); 并直接在其下方进行编辑,使其看起来像这样:


// Main Widget Content Here
get_search_form();

if( !empty( $posts ) ) {
    echo '<ul>';
    foreach( $posts as $post ) {
        echo '<li><a href="' . $post->link. '">' . $post->title->rendered . '</a></li>';
    }
    echo '</ul>';
}

现在,当我们在页面上查看小部件时,您将看到标准搜索表单以及其下方知识库中的帖子列表。

标准搜索小部件

我们知道使用get_search_form(); 当我们搜索某些东西时,搜索参数会出现在 url 中,如下所示:


/?s=test

's' 是 $_GET 参数,'test' 是您的搜索词。 因此,剩下的就是从 URL 中获取搜索词并在响应中使用它,如下所示:


if ( isset ( $_GET['s'] ) && !empty( $_GET['s'] ) ) {
    $response = wp_remote_get( 'http://website-with-api.com/wp-json/wp/v2/ht_kb?filter[s]='.$_GET['s'] );
}
else {
    $response = wp_remote_get( 'http://website-with-api.com/wp-json/wp/v2/ht_kb/' );
}

此代码的作用是检查 $_GET['s'] 是否已设置且不为空。 如果有/是,那么您将其包含在您的回复中。 如果没有,则没有执行搜索,您希望正常显示所有知识库帖子。

有关 get_search_form() 函数的更多详细信息,请参见此处。

这就是我们期望这篇文章结束的地方吗? 毕竟,我们已经设置了一个搜索表单,该表单使用 WordPress REST API 查询外部网站上的帖子,然后根据搜索参数返回这些结果。 然而…

步骤 3:修改显示的结果

如果我们测试新的搜索小部件,我们可以看到小部件按预期工作,但是,它也会在主页内容中返回当前网站的结果。

搜索模板结果
显示“测试”结果的搜索小部件以及重定向到搜索结果模板的页面

这是因为 WordPress 模板系统。 WordPress 使用查询字符串来确定要使用的模板或模板集。 因为,当提交搜索表单时,它会在 URL 中添加参数“s”,它告诉 WordPress 执行搜索并重定向到搜索结果页面。 其中,在 TwentySixteen 主题中是 search.php。

有关更多信息,请参阅模板层次结构文档。

如果我们想同时使用 API 在本地网站和外部网站上执行搜索,那就太好了,因为两者的结果都会显示。 但是,在这种情况下,我们不想这样做。 我们只希望使用 API 返回的结果显示在小部件中。 主页应该不受影响。

有很多方法可以做到这一点。 对于这个例子,我们将看看如何修改 get_search_form(); 函数不再使用 's' 作为其搜索参数。 相反,它将更改为“a”以绕过该问题。

第一步是通过创建一个新函数来实际修改表单。


function api_search_form( $form ) {

 $form = '<form role="search" method="get" class="search-form" action="' . home_url( '/' ) . '">
         <label>
             <span class="screen-reader-text">' . _x( 'Search for:', 'label' ) . '</span>
             <input type="search" class="search-field" placeholder="' . esc_attr_x( 'Search …', 'placeholder' ) .'" value="' . get_search_query() . '" name="a" title="' . esc_attr_x( 'Search for:', 'label' ) .'" />
         </label>
         <button type="submit" class="search-submit"><span class="screen-reader-text">Search</span></button>
         </form>';

 return $form;
}

 add_filter( 'get_search_form', 'api_search_form', 100 );

该函数本身非常简单,它基本上是一种新形式,而不是默认形式。 如果我们查看参考 TwentySixteen 主题并检查现有的搜索表单,我们会注意到代码中的唯一区别是搜索输入的名称。 最初是“name=s”,现在是“name=a”。 这会从 URL 中删除“s”参数。

注意:通过这种方法,我们将主搜索表单修改为使用 API 进行搜索,而不是搜索主机网站。 因此,重要的是要考虑,如果我们在网站的其他任何地方使用主搜索表单,它将不再重定向到来自主机网站的搜索结果。 为了进行两种不同的搜索,最简单的解决方案是将这个新表单的代码直接添加到小部件中,而不是修改 get_search_form();

最后一步是添加过滤器。 这告诉 WordPress 用这个替换现有的表单。 我们可以将整个代码块粘贴到小部件类之后的插件文件中。 这可以包含在主题的 functions.php 中,但是通过将其包含在插件中,这意味着只有在激活插件时才会对表单进行更改。

现在我们已经将输入的名称更改为“a”,我们还必须更改实际的搜索参数。 该参数现在将在 url 中显示为:/?a=test,而不是 /?s=test,因此删除了告诉 WordPress 这应该重定向到搜索结果模板的查询字符串部分。

为了使您可以使用新参数进行搜索,请更新之前为远程调用编写的代码以使用“a”参数而不是“s”。

它现在应该是这样的:


if ( isset ( $_GET['a'] ) && !empty( $_GET['a'] ) ) {
    $response = wp_remote_get( 'http://website-with-api.com/wp-json/wp/v2/ht_kb?filter[s]='.$_GET['a'] );
} else {
    $response = wp_remote_get( 'http://website-with-api.com/wp-json/wp/v2/ht_kb/' );
}

请注意,尽管 $_GET 中的搜索参数已更改,但这不会更改实际查询中的过滤器。 这是因为用于搜索的标准 WP Query 仍然是“s”。

现在,当我们测试小部件时,我们应该能够在您的外部网站上搜索知识库文章并返回结果,而无需重定向到搜索结果页面。

搜索小部件显示“测试”结果而不重定向页面
搜索小部件显示“测试”结果而不重定向页面

小部件的完整代码如下所示:


/**
 * Plugin Name: KB - REST API Widget
 * Author: Kirsty Burgoine
*/

class REST_API_Widget extends WP_Widget {

 /**
 * Sets up the widgets name etc
 */
 public function __construct() {
     $widget_ops = array( 
     'classname' => 'rest-api-widget',
     'description' => 'A REST API widget that pulls posts from a different website');

     parent::__construct( 'rest_api_widget', 'REST API Widget', $widget_ops );
 }



 /**
 * Outputs the content of the widget
 *
 * @param array $args
 * @param array $instance
 */
 public function widget( $args, $instance ) {
     // outputs the content of the widget
     if ( isset ( $_GET['a'] ) && !empty( $_GET['a'] ) ) {
         $response = wp_remote_get( 'http://website-with-api.com/wp-json/wp/v2/ht_kb?filter[s]='.$_GET['a'] );
     } else {
         $response = wp_remote_get( 'http://website-with-api.com/wp-json/wp/v2/ht_kb/' );
     }

     if( is_wp_error( $response ) ) {
         return;
     }

     $posts = json_decode( wp_remote_retrieve_body( $response ) );

     if( empty( $posts ) ) {
         return;
     }

     echo $args['before_widget'];
     if( !empty( $instance['title'] ) ) {
         echo $args['before_title'] . apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base ) . $args['after_title'];
     }
 
     // Main Widget Content Here
     get_search_form();

     if( !empty( $posts ) ) { 
         echo '<ul>';
         foreach( $posts as $post ) {
             echo '<li><a href="' . $post->link. '">' . $post->title->rendered . '</a></li>';
         }
         echo '</ul>'; 
     }
     echo $args['after_widget'];
 }

 /**
 * Outputs the options form on admin
 *
 * @param array $instance The widget options
 */
 public function form( $instance ) {
     // outputs the options form on admin

     $title = ( !empty( $instance['title'] ) ) ? $instance['title'] : '';
     ?>
         <label for="<?php echo $this->get_field_name( 'title' ); ?>">Title: </label>
         <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" 
      name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
     <?php
     }
}

function api_search_form( $form ) {

 $form = '<form role="search" method="get" class="search-form" action="' . home_url( '/' ) . '">
         <label>
             <span class="screen-reader-text">' . _x( 'Search for:', 'label' ) . '</span>
             <input type="search" class="search-field" placeholder="' . esc_attr_x( 'Search …', 'placeholder' ) .'" value="' . get_search_query() . '" name="a" title="' . esc_attr_x( 'Search                 for:', 'label' ) .'" />
         </label>
         <button type="submit" class="search-submit"><span class="screen-reader-text">Search</span></button>
         </form>';

 return $form;
}
add_filter( 'get_search_form', 'api_search_form', 100 );


add_action( 'widgets_init', function(){
 register_widget( 'REST_API_Widget' );
});

这是一个使用 REST API 的自定义搜索小部件的非常简单的实现。 如前所述,我们可以向查询添加额外的过滤器来限制搜索结果的数量或它们的显示顺序。您可以选择在小部件中显示额外的信息,例如搜索词和结果的数量,或者,如果您了解 jQuery / Javascript,您可以更进一步,并添加一个不错的 AJAX 效果,以便在无需刷新页面的情况下返回结果。

延伸阅读:

  • 小部件 API (WordPress Codex)
  • 创建您的第一个 WordPress 小部件 (Tutsplus) 简介
  • 如何创建自定义 WordPress 小部件(WP 初学者)
  • 如何为 WordPress(WP Explorer)创建一个小部件插件