web-dev-qa-db-ja.com

WordPressで「仮想」ページを作成する方法

私はWordPressでカスタムAPIエンドポイントを作成しようとしていますが、WordPressのルートにある仮想ページへのリクエストを自分のプラグインに同梱されている実際のページにリダイレクトする必要があります。そのため、基本的には、あるページに対するすべての要求は実際には別のページにルーティングされます。

例:
http://mysite.com/my-api.php => http://mysite.com/wp-content/plugins/my-plugin/my-api.php

ここで重要なのは、APIエンドポイントのURLをできるだけ短くすることです(http://mysite.com/xmlrpc.phpに似ていますが、実際のAPIエンドポイントファイルをプラグインと一緒に出荷するのではなく、インストールやハックの際にファイルを移動する必要はありません)。コア。

私の最初のスタブはカスタム書き換えルールを追加することでした。しかし、これには2つの問題がありました。

  1. エンドポイントには常に末尾のスラッシュがあります。 http://mysite.com/my-api.php/になりました
  2. 私の書き換え規則は部分的にしか適用されませんでした。 wp-content/plugins...にリダイレクトせず、index.php&wp-content/plugins...にリダイレクトします。これはWordPressがエラーを見つけられなかったページを表示するか、単にホームページにデフォルト設定することにつながります。

アイデア?提案?

50
EAMann

WordPressには2種類の書き換え規則があります:内部規則(データベースに格納され WP :: parse_request() によって解析される)と外部規則(.htaccessに格納されApacheによって解析される)呼び出したファイルに必要なWordPressの量に応じて、どちらの方法を選ぶこともできます。

外部ルール:

外部ルールが最も簡単に設定して従うことができます。 WordPressから何も読み込まずに、プラグインディレクトリでmy-api.phpを実行します。

add_action( 'init', 'wpse9870_init_external' );
function wpse9870_init_external()
{
    global $wp_rewrite;
    $plugin_url = plugins_url( 'my-api.php', __FILE__ );
    $plugin_url = substr( $plugin_url, strlen( home_url() ) + 1 );
    // The pattern is prefixed with '^'
    // The substitution is prefixed with the "home root", at least a '/'
    // This is equivalent to appending it to `non_wp_rules`
    $wp_rewrite->add_external_rule( 'my-api.php$', $plugin_url );
}

内部ルール:

内部ルールにはもう少し作業が必要です。最初にクエリ変数を追加する書き換えルールを追加し、次にこのクエリ変数をパブリックにしてから、このクエリ変数の存在をチェックしてプラグインファイルにコントロールを渡す必要があります。これを行う頃には、通常のWordPressの初期化が行われているでしょう(通常のpostクエリの直前に抜け出します)。

add_action( 'init', 'wpse9870_init_internal' );
function wpse9870_init_internal()
{
    add_rewrite_rule( 'my-api.php$', 'index.php?wpse9870_api=1', 'top' );
}

add_filter( 'query_vars', 'wpse9870_query_vars' );
function wpse9870_query_vars( $query_vars )
{
    $query_vars[] = 'wpse9870_api';
    return $query_vars;
}

add_action( 'parse_request', 'wpse9870_parse_request' );
function wpse9870_parse_request( &$wp )
{
    if ( array_key_exists( 'wpse9870_api', $wp->query_vars ) ) {
        include 'my-api.php';
        exit();
    }
    return;
}
54
Jan Fabry

これは私のために働きました。私はこれまで書き換えAPIに触れることはありませんでしたが、常に新しい方向に進むことは自分次第です。以下は、localhostのサブフォルダーにある3.0用の私のテストサーバーで動作しました。 WordPressがWebルートにインストールされている場合は問題ありません。

このコードをプラグインにドロップして、 "taco-kittens.php"という名前のファイルをプラグインフォルダに直接アップロードするだけです。あなたのパーマリンクのためにハードフラッシュを書く必要があるでしょう。私は彼らがこれをする最もよい時期がプラグインアクティベーションにあると言うと思います。

function taco_kitten_rewrite() {
    $url = str_replace( trailingslashit( site_url() ), '', plugins_url( '/taco-kittens.php', __FILE__ ) );
    add_rewrite_rule( 'taco-kittens\\.php$', $url, 'top' );
}
add_action( 'wp_loaded', 'taco_kitten_rewrite' );

よろしく、 - マイク

11
mfields

代わりにこのようなことをしない理由は何ですか?

http://mysite.com/?my-api=1

それからプラグインを 'init'にフックして、そのget変数をチェックしてください。それが存在する場合、あなたのプラグインがする必要があることをしてdie()

8
Will Anderson

私はあなたの質問を完全に理解しているのではないかもしれませんが、簡単な短いコードであなたの問題を解決できるでしょうか?

ステップ:

  1. クライアントにページを作成させます。すなわち、 http://mysite.com/my-api
  2. クライアントにそのページにショートコードを追加してもらいます、すなわち[my-api-shortcode]

新しいページはAPIエンドポイントとして機能し、ショートコードは http://mysite.com/wp-content/plugins/my-plugin/my-api.php にあるプラグインコードにリクエストを送信します。

(もちろん、これはmy-api.phpにショートコードが定義されることを意味します)

あなたはおそらくプラグインを介してステップ1と2を自動化することができます。

3
rexposadas

私はホームページにカスタムのタイトル、コンテンツ、およびページテンプレートを強制的に読み込ませるで構成される別の方法を使用しています。

ユーザーが http://example.com/?plugin_page = myfakepageのようなわかりやすいリンクをたどったときに実装できるため、このソリューションは非常に優れています。

実装は非常に簡単で、ページ数は無制限にできます。

ここにコードと手順: その場でカスタムの/偽の/仮想Wordpressのページを生成する

1
Xavi Esteve

私はそれほど書き直すことを扱っていません、それで、これはおそらく少し大まかです、しかしそれはうまくいくようです:

function api_rewrite($wp_rewrite) {
    $wp_rewrite->non_wp_rules['my-api\.php'] = 'wp-content/plugins/my-plugin/my-api.php';
    file_put_contents(ABSPATH.'.htaccess', $wp_rewrite->mod_rewrite_rules() );
}

これを 'generate_rewrite_rules'にフックすればうまくいきますが、ページをロードするたびに.htaccessを書き換えたくないので、もっと良い方法があるはずです。
自分の投稿の編集をやめることはできないようです…おそらくコールバックを有効にして代わりにglobal $ wp_rewriteを参照してください。その後、non_wp_rulesからエントリを削除し、コールバックを無効にして再度.htaccessに出力します。

そして最後に、.htaccessへの書き込みはもう少し洗練されているはずです、あなたはそこのwordpressセクションだけを置き換えたいと思います。

1
wyrfel

私は同様の要件があり、プラグインによって生成されたコンテンツを指し示す独自のスラグに基づいていくつかのエンドポイントを作成したいと思いました。

私のプラグインのソースを見てみましょう: https://wordpress.org/extend/plugins/picasa-album-uploader/

私が使ったテクニックは、入ってくるリクエストを調べるためにthe_postsのためのフィルタを追加することから始まります。プラグインがそれを処理する必要がある場合は、ダミーの投稿が生成され、template_redirectに対するアクションが追加されます。

template_redirectアクションが呼び出されると、表示されるページの内容全体を出力して終了するか、または出力を生成せずに戻る必要があります。 wp_include/template-loader.phpのコードを見れば、その理由がわかります。

1
Ken

私は上記のXavi Esteveと似たアプローチを使用していますが、2013年後半にはWordPressのアップグレードが原因で機能しなくなりました。

それはここに非常に詳細に文書化されています: https://stackoverflow.com/questions/17960649/wordpress-plugin-generating-virtual-pages-and-using-theme-template

私のアプローチの重要な部分は既存のテンプレートを使用することであるので、結果のページはそれがサイトの一部であるように見えます。私はそれがすべてのテーマと可能な限り互換性があることを望んだ、うまくいけばWordPressのリリース間で。私が正しかったかどうか時がたてばわかるでしょう!

0
Brian C

本番環境のサンプルです。最初に仮想ページクラスを作成します。


class VirtualPage
{

    private $query;
    private $title;
    private $content;
    private $template;
    private $wp_post;

    function __construct($query = '/index2', $template = 'page', $title = 'Untitled')
    {
        $this->query = filter_var($query, FILTER_SANITIZE_URL);
        $this->setTemplate($template);
        $this->setTitle($title);
    }

    function getQuery()
    {
        return $this->query;
    }

    function getTemplate()
    {
        return $this->template;
    }

    function getTitle()
    {
        return $this->title;
    }

    function setTitle($title)
    {
        $this->title = filter_var($title, FILTER_SANITIZE_STRING);

        return $this;
    }

    function setContent($content)
    {
        $this->content = $content;

        return $this;
    }

    function setTemplate($template)
    {
        $this->template = $template;

        return $this;
    }

    public function updateWpQuery()
    {

        global $wp, $wp_query;

        // Update the main query
        $wp_query->current_post = $this->wp_post->ID;
        $wp_query->found_posts = 1;
        $wp_query->is_page = true;//important part
        $wp_query->is_singular = true;//important part
        $wp_query->is_single = false;
        $wp_query->is_attachment = false;
        $wp_query->is_archive = false;
        $wp_query->is_category = false;
        $wp_query->is_tag = false;
        $wp_query->is_tax = false;
        $wp_query->is_author = false;
        $wp_query->is_date = false;
        $wp_query->is_year = false;
        $wp_query->is_month = false;
        $wp_query->is_day = false;
        $wp_query->is_time = false;
        $wp_query->is_search = false;
        $wp_query->is_feed = false;
        $wp_query->is_comment_feed = false;
        $wp_query->is_trackback = false;
        $wp_query->is_home = false;
        $wp_query->is_embed = false;
        $wp_query->is_404 = false;
        $wp_query->is_paged = false;
        $wp_query->is_admin = false;
        $wp_query->is_preview = false;
        $wp_query->is_robots = false;
        $wp_query->is_posts_page = false;
        $wp_query->is_post_type_archive = false;
        $wp_query->max_num_pages = 1;
        $wp_query->post = $this->wp_post;
        $wp_query->posts = array($this->wp_post);
        $wp_query->post_count = 1;
        $wp_query->queried_object = $this->wp_post;
        $wp_query->queried_object_id = $this->wp_post->ID;
        $wp_query->query_vars['error'] = '';
        unset($wp_query->query['error']);

        $GLOBALS['wp_query'] = $wp_query;

        $wp->query = array();
        $wp->register_globals();

    }

    public function createPage()
    {
        if (is_null($this->wp_post)) {
            $post = new stdClass();
            $post->ID = -99;
            $post->ancestors = array(); // 3.6
            $post->comment_status = 'closed';
            $post->comment_count = 0;
            $post->filter = 'raw';
            $post->guid = home_url($this->query);
            $post->is_virtual = true;
            $post->menu_order = 0;
            $post->pinged = '';
            $post->ping_status = 'closed';
            $post->post_title = $this->title;
            $post->post_name = sanitize_title($this->template); // append random number to avoid clash
            $post->post_content = $this->content ?: '';
            $post->post_excerpt = '';
            $post->post_parent = 0;
            $post->post_type = 'page';
            $post->post_status = 'publish';
            $post->post_date = current_time('mysql');
            $post->post_date_gmt = current_time('mysql', 1);
            $post->modified = $post->post_date;
            $post->modified_gmt = $post->post_date_gmt;
            $post->post_password = '';
            $post->post_content_filtered = '';
            $post->post_author = is_user_logged_in() ? get_current_user_id() : 0;
            $post->post_content = '';
            $post->post_mime_type = '';
            $post->to_ping = '';

            $this->wp_post = new WP_Post($post);
            $this->updateWpQuery();

            @status_header(200);
            wp_cache_add(-99, $this->wp_post, 'posts');

        }


        return $this->wp_post;
    }
}

次のステップでtemplate_redirectアクションをフックし、以下のように仮想ページを処理します

    add_action( 'template_redirect', function () {


                    switch ( get_query_var( 'name' ,'') ) {

                        case 'contact':
                            // http://yoursite/contact  ==> loads page-contact.php
                            $page = new VirtualPage( "/contact", 'contact',__('Contact Me') );
                            $page->createPage();
                            break;

                        case 'archive':
                            // http://yoursite/archive  ==> loads page-archive.php
                            $page = new VirtualPage( "/archive", 'archive' ,__('Archives'));
                            $page->createPage();
                            break;

                        case 'blog':
                            // http://yoursite/blog  ==> loads page-blog.php
                            $page = new VirtualPage( "/blog", 'blog' ,__('Blog'));
                            $page->createPage();
                            break;


                }


            } );
0
Mr.Hosseini