自定义重写以获取提要数据

时间:2019-08-02 作者:Cyclonecode

当用户转到特定url时,我试图从提要中获取和显示数据,如/items/32 其中32 应获取并显示的源项的实际id。请注意,我没有为此使用任何自定义帖子类型。我只是根据提供的id从外部资源获取数据:

class FeedPlugin
{
  public function __construct()
  {
    add_action(\'init\', array($this, \'addRewriteRules\'));
    add_filter(\'query_vars\', array($this, \'addQueryVars\'));
    add_action(\'template_redirect\', array($this, \'addTemplate\'));
  }

  /**
   * Add query argument item_id
  **/
  public function addQueryVars(array $query_vars)
  {
    $query_vars[] = \'item_id\';
    return $query_vars;
  }

  /**
   * Add a custom rewrite in the form ^/items/123/$
  **/
  public function addRewriteRules()
  {
    add_rewrite_rule(
      \'items/([0-9]+)/?$\',
      \'index.php?pagename=items&item_id=$matches[1]\',
      \'top\'
    );
    // This is just for testing purposes at this point.
    flush_rewrite_rules(true);
  }

  /**
   * Here we actually are fetching the data based on the id
  **/
  public function addTemplate()
  {
    global $item;
    if (get_query_var(\'pagename\') == \'items\' && 
        get_query_var(\'item_id\')) {
        $feedUrl = \'https://example.com/api/v1/feed?id=\' . get_query_var(\'item_id\');
        $response = wp_remote_request($feedUrl);

        // For now we just assume that this works.
        $body = wp_remote_retrieve_body($response);
        $item = json_decode($body);

        // Include our custom template that renders the content from the $body variable
        // I also manage to do this by using the `template_include` filter
        include plugin_dir_path(__FILE__) . \'/custom-item.php\';
      }
    }
}
上面这类作品,但由于我在访问这条路线时没有使用真正的帖子,因此页面标题设置为BlogName | Not found 访问此路由时返回的http状态码设置为404. 我通过使用add_filter(\'pre_get_document_title\', array($this, \'setTitle\'));:

public function setTitle($title)
{
    global $item;
    if (get_query_var(\'pagename\') == \'items\') {
        return get_bloginfo(\'name\') . \' | \' . $item->Title;
    }
    return $title;
}
为了摆脱404 我使用的状态代码:

global $wp_query;
$wp_query->is_404 = false;
status_header(200);
addTemplate() 方法

尽管这看起来很有效,但感觉很混乱,我想知道是否有更顺畅的方法?也许是通过创造一些虚假的帖子或类似的东西?

1 个回复
SO网友:Sally CJ

Seems like a good candidate for add_rewrite_endpoint().

add_rewrite_endpoint( \'items\', EP_ROOT, \'item_id\' );

That will register the endpoint /items/<item ID> and also registers the query var item_id, and eliminates the 404 status header/title as well. But the page title would be the site name and you\'d probably still want to hook to pre_get_document_title to customize the title.

And your class would be simpler:

class FeedPlugin {
    public function __construct() {
        add_action( \'init\', [ $this, \'add_rewrite_endpoint\' ] );
        add_action( \'template_redirect\', [ $this, \'addTemplate\' ] );
    }

    public function add_rewrite_endpoint() {
        add_rewrite_endpoint( \'items\', EP_ROOT, \'item_id\' );
    }

    public function addTemplate() {
        if ( $item_id = get_query_var( \'item_id\' ) ) {
            /* your code here:
            echo \'Yay, it works! Item ID: \' . $item_id;
            exit;
            */
        }
    }
}

Don\'t forget to flush the rewrite rules — just visit the permalink settings page.

UPDATE

how can I specify what is valid for release_id e.g [0-9A-Z]+

So I believe you meant item_id when you said release_id?

And (at the moment) there\'s no "standard"/easy way to specify the preferred RegEx pattern for an endpoint added using add_rewrite_endpoint(), so if you need a custom RegEx pattern, it\'s actually better to use add_rewrite_rule(). :)

And here\'s how you can prevent the 404 error with your original code.

I believe you know it happens because you\'re querying a post/Page that doesn\'t exist (pagename=items) and I also believe you added that in the rewrite rule as an identifier for the custom feed request.

And I\'m not sure if you intentionally didn\'t do this, but it\'s a very easy way to prevent the 404 error: create a Page and set its slug to items.

That may sound silly, but it actually works. (Although you\'d still need to tweak the page title.) And you could just create a custom Page template (which loads/generates/renders the feed) and assign the template to that items Page, without having to hook to template_redirect.

Alternate solution without creating a Page

  1. In the addRewriteRules(), just omit the pagename=items&:

    public function addRewriteRules()
    {
      add_rewrite_rule(
        \'items/([0-9]+)/?$\',
        \'index.php?item_id=$matches[1]\',
        \'top\'
      );
    }
    
  2. In the addTemplate(), check if the matched rewrite rule is the one you added via add_rewrite_rule() above:

    public function addTemplate()
    {
      global $item, $wp;
      if ( \'items/([0-9]+)/?$\' === $wp->matched_rule &&
        ( $item_id = get_query_var(\'item_id\') ) ) {
        // your code here
      }
    }
    

But once again, you\'d still need to tweak the page title which defaults to the site name.

相关推荐

使用fetch_feed();完全在WordPress之外?

我用过fetch_feed() 多次使用WordPress项目。现在我在非WP网站工作。那么有没有办法使用fetch_feed() 完全在WordPress之外?什么WordPress Core files 我应该复制到我的工作场所吗?