Як створити "віртуальну" сторінку в WordPress


52

Я намагаюся створити власну кінцеву точку API в WordPress, і мені потрібно перенаправляти запити на віртуальну сторінку в корені WordPress на фактичну сторінку, яка постачається разом із моїм плагіном. Отже, всі запити на одну сторінку фактично перенаправлені на іншу.

Приклад:
http://mysite.com/my-api.php=>http://mysite.com/wp-content/plugins/my-plugin/my-api.php

Сенс цього полягає в тому, щоб зробити URL-адресу для кінцевої точки API якомога коротшим (подібним до, http://mysite.com/xmlrpc.phpале щоб передати фактичний файл кінцевої точки API за допомогою плагіну, а не вимагати від користувача переміщення файлів навколо їх встановлення та / або злому ядра .

Першим моїм завданням було додати спеціальне правило перезапису. Однак це мало дві проблеми.

  1. Кінцева точка завжди мала косу рису. Це сталоhttp://mysite.com/my-api.php/
  2. Моє правило перезапису застосовувалося лише частково. Він не перенаправляв би wp-content/plugins..., він перенаправляв би на index.php&wp-content/plugins.... Це призводить до того, що WordPress відображає помилку на сторінці, яку не знайдено, або просто за замовчуванням на домашній сторінці.

Ідеї? Пропозиції?

Відповіді:


55

Існує два типи правил перезапису в WordPress: внутрішні правила (зберігаються в базі даних та аналізуються WP :: parse_request () ) та зовнішні правила (зберігаються в .htaccessApache та аналізуються ними). Ви можете вибрати будь-який спосіб, залежно від того, скільки WordPress вам потрібно у вашому викликаному файлі.

Зовнішні правила:

Зовнішнє правило найпростіше встановити та дотримуватись. Він буде виконуватися 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 );
}

Внутрішні правила:

Внутрішнє правило вимагає ще трохи роботи: спочатку ми додаємо правило перезапису, яке додає vars vars, потім робимо цей var запиту загальнодоступним, а потім нам потрібно перевірити наявність цього var запиту, щоб передати управління до нашого файла плагінів. До того часу, як ми це зробимо, відбудеться звичайна ініціалізація WordPress (ми відриваємося перед звичайним запитом після публікації).

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-адміністраторі. Я грав з цим протягом години, перш ніж подумав, що мені потрібно оновити постійні посилання ... Якщо хтось не знає функції, яка може це зробити?
етанпіль

Для зовнішнього правила: Оскільки шлях до мого веб-корінця мав пробільний характер, це спричинило перекидання апача. Білі простори потрібно уникати, якщо вони існують на шляху до вашої установки WordPress.
Уіллстер

1
Працює, але я не можу отримати доступ до жодних змінних запитів, що передаються, get_query_vars()в моєму-api.php. Я перевірив, які змінні завантажуються. І тільки вар , який встановлений аа WP objectназивається $wp. Як отримати доступ до цього або перетворити його на WP_Queryоб'єкт, щоб я міг отримати доступ до переданих змінних get_query_vars()?
Жуль

1
@Jules: Коли ви includeстворюєте файл, він виконується в поточному масштабі. У цьому випадку це wpse9870_parse_requestфункція, яка має лише $wpпараметр. Можливо, глобальний $wp_queryоб’єкт наразі не встановлений, тому get_query_var()він не працюватиме. Однак вам пощастило: $wpце клас, який містить query_varsпотрібного вам члена - я сам його використовую у наведеному вище коді.
Ян Фабрі

1
намагаючись створити правила зовнішнього перезапису. додав кулак коду, але я все одно отримую 404. btw:
flushed

12

Це працювало для мене. Я ніколи не торкаюся API перезапису, але завжди намагаюся просунути себе в нових напрямках. Наступне працювало на моєму тестовому сервері для 3.0, що знаходиться в підпапці localhost. Я не бачу жодних проблем, якщо WordPress встановлений у веб-корінці.

Просто киньте цей код у плагін і завантажте файл із назвою "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.
Прафула Кумар Саху

9

Будь-яка причина замість цього не зробити щось подібне?

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

Тоді просто підключіть ваш плагін до 'init' і перевірте, чи не отримати змінну. Якщо він існує, зробіть те, що ваш плагін повинен зробити, і вмирайте ()


5
Це би спрацювало, але я намагаюся надати чітке розрізнення між змінними запиту та фактичною кінцевою точкою. В майбутньому можуть з’явитися інші аргументи запитів, і я не хочу, щоб користувачі переплутали речі.
EAMann

Що робити, якщо ви зберегли перезапис, але переписали його на GET var? Ви також можете подивитися, як працює перезапис для 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

(звичайно це означає, що мій-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() );
}

Це працює, якщо ви підключите це до 'create_rewrite_rules', але повинен бути кращий спосіб, оскільки ви не хочете переписувати .htaccess при кожному завантаженні сторінки.
Здається, я не можу припинити редагування своїх власних публікацій ... це, мабуть, скоріше, щоб увійти до вас, активувати зворотний виклик та посилатись на глобальний $ wp_rewrite. А потім видаліть запис з non_wp_rules і знову виведіть на .htaccess, щоб ви відключили зворотний виклик.

І нарешті, запис у .htaccess має бути дещо складнішим, ви хочете лише замінити там розділ wordpress.


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, який припинив роботу через оновлення WordPress, наскільки я міг сказати у другій половині 2013 року.

Це детально задокументовано тут: https://stackoverflow.com/questions/17960649/wordpress-plugin-generating-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;


                }


            } );
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.