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


52

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

例:
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でページが見つからないというエラーが表示されるか、ホームページがデフォルトになります。

アイデア?提案?

回答:


55

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

外部ルール:

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

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;
}

3
パーマリンクページに移動し、WP-Adminで[変更を保存]をクリックすることが重要です。私はパーマリンクを更新する必要があると考える前にこれで1時間遊んでいました...誰かがそれを行うことができる機能を知っていない限り?
エタンピル

外部ルールの場合:Webルートへのパスに空白文字が含まれていたため、これによりApacheが失敗しました。空白は、WordPressインストールへのパスに存在する場合はエスケープする必要があります。
ウィルスター

1
動作しますがget_query_vars()、my-api.phpで渡されたクエリ変数にアクセスできないようです。どの変数がロードされているかを確認しました。そして、設定される唯一の変数はWP objectと呼ばれるaa $wpです。WP_Query渡された変数にアクセスできるように、これをオブジェクトにアクセスまたは変換するにはどうすればよいget_query_vars()ですか?
ジュール

1
@Jules:includeファイルを作成すると、現在のスコープで実行されます。この場合、パラメーターwpse9870_parse_requestのみを持つ関数$wpです。$wp_queryこの時点でグローバルオブジェクトが設定されていない可能性があるため、機能しget_query_var()ません。しかし、あなたは幸運です:必要なメンバーを$wp含むクラスquery_varsです-私は上記のコードで自分でそれを使用します。
ヤンファブリー

1
外部書き換えルールを作成しようとしています。コードのこぶし作品を追加しましたが、私はまだ404を取得していますところで:フラッシュ書き換えルールを
Sisir

12

これは私のために働いた。書き換え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' );

よろしくお願いします、マイク


1
このコードの試行中にアクセス拒否エラーが発生しました。サーバーまたはWPが絶対URLを好まなかったと思われます。この一方で、うまく働いた:add_rewrite_rule( 'taco-kittens', 'wp-content/plugins/taco-kittens.php', 'top' );
ジュール・

taco-kittens.phpに何を入れるべきか教えてください。.htaccessやurl rewriteの知識がありません。
プラフーラクマールサフ

9

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

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

次に、プラグインを「init」にフックして、そのget変数を確認します。存在する場合、プラグインが行う必要のあることを行い、die()


5
それは機能しますが、クエリ変数と実際のエンドポイントを非常に明確に区別しようとしています。将来的には他のクエリ引数が存在する可能性があり、ユーザーが物事を混同することは望ましくありません。
EAMann

書き換えを続けたが、GET変数に書き換えた場合はどうなりますか?また、robots.txtの書き換えがどのように機能するかを確認することもできます。my-api.php /へのリダイレクトを回避する方法を見つけるのに役立つかもしれません
ウィルアンダーソン

API呼び出しのようなロボットを気にしない場合、これは完璧なソリューションです。
ベイタロフスキー

4

あなたの質問を完全に理解していないかもしれませんが、簡単なショートコードで問題を解決できますか?

手順:

  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を自動化できます。


1

私はまだあまり書き換えを扱っていないので、これはおそらく少し荒いかもしれませんが、うまくいくようです:

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を書き換えたくないので、より良い方法が必要です。
私は自分の投稿の編集を止めることができないようです...おそらくコールバックをアクティブにして、代わりにグローバルな$ wp_rewriteを参照する必要があります。次に、コールバックを非アクティブ化するときに、non_wp_rulesからエントリを削除し、.htaccessに再度出力します。

最後に、.htaccessへの書き込みはもう少し洗練されている必要があります。そこのワードプレスセクションのみを置き換えたいと思います。


1

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

プラグインのソースをご覧くださいhttps : //wordpress.org/extend/plugins/picasa-album-uploader/

私が使用した手法はthe_posts、着信要求を調べるためのフィルターを追加することから始まります。プラグインがそれを処理する必要がある場合、ダミーの投稿が生成され、アクションがに追加されtemplate_redirectます。

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


1

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

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

実装は非常に簡単で、無制限のページを許可する必要があります。

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


0

上記のXavi Esteveのようなアプローチを使用していますが、2013年後半にWordPressがアップグレードされたため、機能が停止しました。

ここに詳細が記載されています:https : //stackoverflow.com/questions/17960649/wordpress-plugin-generated-virtual-pages-and-using-theme-template

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


0

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


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;


                }


            } );
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.