如何在WordPress中创建虚拟页面

时间:2011-02-20 作者:EAMann

我试图在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端点文件,而不是要求用户在安装和/或破解核心中移动文件。

我的第一个尝试是添加一个自定义重写规则。然而,这有两个问题。

端点始终具有尾部斜杠。它变成了http://mysite.com/my-api.php/wp-content/plugins..., 它将重定向到index.php&wp-content/plugins.... 这会导致WordPress显示页面未找到错误或默认为主页想法?建议?

9 个回复
最合适的回答,由SO网友:Jan Fabry 整理而成

WordPress中有两种类型的重写规则:内部规则(存储在数据库中,由WP::parse_request()), 和外部规则(存储在.htaccess 并由Apache解析)。您可以选择任何一种方式,这取决于您在所调用的文件中需要多少WordPress。

External Rules:

外部规则最容易设置和遵循。它将执行my-api.php 在插件目录中,无需从WordPress加载任何内容。

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

Internal Rules:

内部规则需要做更多的工作:首先,我们添加一个重写规则,添加一个查询变量,然后我们将此查询变量公开,然后我们需要检查此查询变量是否存在,以将控件传递给我们的插件文件。当我们这样做的时候,通常的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;
}

SO网友:mfields

这对我有用。我从来没有接触过重写API,但我总是向新的方向努力。以下内容适用于位于localhost子文件夹中的我的3.0测试服务器。如果WordPress安装在web根目录中,我看不到任何问题。

只需将此代码放入插件中,并将名为“tacokittens.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\' );
祝你一切顺利-迈克

SO网友:Will Anderson

有什么理由不这样做吗?

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

然后将插件挂接到“init”中,并检查get变量。如果它存在,做你的插件需要做的事情,然后消亡()

SO网友:rexposadas

我可能不完全理解你的问题,但一个简单的快捷码能解决你的问题吗?

步骤:

让客户端创建一个页面,即。http://mysite.com/my-api

  • 让客户端在该页面中添加一个短代码,即[我的api短代码]
  • 新页面充当api端点,您的短代码向您的插件代码发送请求http://mysite.com/wp-content/plugins/my-plugin/my-api.php

    (当然,这意味着my-api.php将定义短代码)

    您可能可以通过插件自动执行步骤1和2。

    SO网友:wyrfel

    我还没有处理太多重写问题,所以这可能有点粗糙,但似乎很有效:

    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\\u rewrite\\u rules”中,它就会起作用,但必须有更好的方法,因为您不想重写。每个页面加载时的htaccess<似乎我无法停止编辑自己的帖子。。。它可能更应该进入您激活回调并引用全局$wp\\u rewrite。然后从non\\u wp\\u规则中删除该条目并输出到。htaccess在停用回调时再次出现。

    最后,写信给。htaccess应该更复杂一些,您只想替换其中的wordpress部分。

    SO网友:Ken

    我有一个类似的要求,希望根据指向插件生成的内容的独特段塞创建几个端点。

    请查看我的插件的源代码:https://wordpress.org/extend/plugins/picasa-album-uploader/

    我使用的技术首先是为the_posts 检查传入请求。如果插件应该处理它,则会生成一个伪帖子,并为添加一个操作template_redirect.

    template_redirect 调用操作时,必须输出要显示和退出的页面的全部内容,否则返回时不会生成任何输出。请参见中的代码wp_include/template-loader.php 你就会明白为什么了。

    SO网友:Xavi Esteve

    我正在使用另一种方法,包括forcing the home page to load a custom title, content and page template.

    该解决方案非常简洁,因为它可以在用户关注友好链接时实现,例如http://example.com/?plugin_page=myfakepage

    它很容易实现,应该允许无限的页面。

    此处的代码和说明:Generate a custom/fake/virtual Wordpress page on the fly

    SO网友:Brian C

    我使用的方法与上述哈维·埃斯特夫的方法类似,据我所知,由于WordPress在2013年下半年升级,该方法停止工作。

    这里有非常详细的记录:https://stackoverflow.com/questions/17960649/wordpress-plugin-generating-virtual-pages-and-using-theme-template

    我的方法的关键部分是使用现有模板,使生成的页面看起来像是站点的一部分;我希望它能尽可能兼容所有主题,希望能跨越WordPress发布。时间会证明我是对的!

    SO网友:Mr.Hosseini

    这是一个生产就绪的示例,首先创建虚拟页面类:

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

    结束