使用 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)創建一個小部件插件