Jak utworzyć „wirtualną” stronę w WordPress


52

Próbuję utworzyć niestandardowy punkt końcowy interfejsu API w WordPress i muszę przekierować żądania do wirtualnej strony w katalogu głównym WordPress na rzeczywistą stronę, która jest dostarczana z moją wtyczką. Zasadniczo wszystkie żądania na jednej stronie są w rzeczywistości przekierowywane na drugą.

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

Chodzi o to, aby adres URL punktu końcowego interfejsu API był jak najkrótszy (podobnie jak w http://mysite.com/xmlrpc.phpcelu dostarczenia rzeczywistego pliku punktu końcowego interfejsu API z wtyczką, zamiast wymagać od użytkownika przenoszenia plików podczas instalacji i / lub rąbania rdzenia .

Moim pierwszym pchnięciem było dodanie niestandardowej reguły przepisywania. Miało to jednak dwa problemy.

  1. Punkt końcowy zawsze miał końcowy ukośnik. Stało sięhttp://mysite.com/my-api.php/
  2. Moja reguła przepisywania została zastosowana tylko częściowo. Nie przekierowuje do wp-content/plugins..., przekierowuje do index.php&wp-content/plugins.... Doprowadziło to do wyświetlenia przez WordPress błędu nie znalezienia strony lub domyślnego ustawienia strony głównej.

Pomysły? Propozycje?

Odpowiedzi:


55

Istnieją dwa typy reguł przepisywania w WordPress: reguły wewnętrzne (przechowywane w bazie danych i analizowane przez WP :: parse_request () ) oraz reguły zewnętrzne (przechowywane .htaccessi analizowane przez Apache). Możesz wybrać dowolny sposób, w zależności od tego, ile WordPress potrzebujesz w wywołanym pliku.

Zasady zewnętrzne:

Reguła zewnętrzna jest najłatwiejsza do skonfigurowania i przestrzegania. Uruchomi się on my-api.phpw twoim katalogu wtyczek, bez ładowania czegokolwiek z 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 );
}

Zasady wewnętrzne:

Reguła wewnętrzna wymaga nieco więcej pracy: najpierw dodajemy regułę przepisywania, która dodaje zmienne zapytania, następnie upubliczniamy to zapytanie var, a następnie musimy sprawdzić, czy istnieje zapytanie var, aby przekazać kontrolę do naszego pliku wtyczki. Do czasu, gdy to zrobimy, nastąpi zwykła inicjalizacja WordPress (odrywamy się przed zwykłym zapytaniem po).

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
Chcę tylko dodać, że ważne jest, aby przejść do strony Permalinks i kliknąć „Zapisz zmiany” w Administratorze WP. Bawiłem się tym przez godzinę, zanim pomyślałem, że muszę odświeżyć permalinki ... Chyba że ktoś zna funkcję, która może to zrobić?
— ethanpil

W przypadku reguły zewnętrznej: ponieważ ścieżka do mojego katalogu głównego miała znak spacji, spowodowało to przewrócenie Apache. Białe znaki należy usunąć, jeśli istnieją na ścieżce do instalacji Wordpress.
— Willster,

1
Działa, ale wydaje się, że nie mogę uzyskać dostępu do żadnych zmiennych zapytań get_query_vars()w my-api.php. Sprawdziłem, które zmienne są ładowane. A jedynym ustawionym var jest aa o WP objectnazwie $wp. Jak uzyskać dostęp do WP_Queryobiektu lub przekształcić go w obiekt, aby uzyskać dostęp do przekazywanych zmiennych za pomocą get_query_vars()?
— Jules

1
@Jules: Gdy includeplik jest wykonywany w bieżącym zakresie. W tym przypadku jest to wpse9870_parse_requestfunkcja, która ma tylko $wpparametr. Możliwe, że $wp_queryobiekt globalny nie został ustawiony w tej chwili, więc get_query_var()nie będzie działać. Jednak masz szczęście: $wpjest to klasa, która zawiera element query_varsczłonkowski, którego potrzebujesz - używam go sam w powyższym kodzie.
— Jan Fabry,

1
próba utworzenia zewnętrznych reguł przepisywania. dodałem twój kawałek kodu pięści, ale wciąż otrzymuję 404. btw: przepłukane przepisy przepisywania
— Sisir

12

To zadziałało dla mnie. Nigdy nie dotykam przepisanego API, ale zawsze jestem gotów popchnąć się w nowych kierunkach. Poniższe działało na moim serwerze testowym dla wersji 3.0 zlokalizowanym w podfolderze localhost. Nie widzę żadnego problemu, jeśli WordPress jest zainstalowany w katalogu głównym.

Po prostu upuść ten kod we wtyczce i prześlij plik o nazwie „taco-kittens.php” bezpośrednio do folderu wtyczki. Będziesz musiał napisać twardy kolor dla swoich permalinków. Myślę, że mówią, że najlepszym czasem na to jest aktywacja wtyczki.

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

Najlepsze życzenia, -Mike


1
Wystąpił błąd odmowy dostępu podczas próbowania tego kodu. Podejrzewam, że mój serwer lub WP nie lubił bezwzględnego adresu URL. To z kolei działało dobrze:add_rewrite_rule( 'taco-kittens', 'wp-content/plugins/taco-kittens.php', 'top' );
— Jules

Czy możesz dać mi znać, co powinienem umieścić w taco-kittens.php, nie mam wiedzy na temat .htaccess ani przepisywania adresów URL.
— Prafulla Kumar Sahu

9

Czy jest jakiś powód, aby nie robić czegoś takiego?

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

Następnie po prostu podłącz swoją wtyczkę do 'init' i sprawdź, czy zmienna jest dostępna. Jeśli istnieje, zrób to, co musi zrobić wtyczka, i zgiń ()


5
To by działało, ale staram się wprowadzić bardzo wyraźne rozróżnienie między zmiennymi zapytania a rzeczywistym punktem końcowym. W przyszłości mogą pojawić się inne argumenty zapytań i nie chcę, aby użytkownicy się pomylili.
— EAMann

Co zrobić, jeśli zachowałeś przepisywanie, ale przepisałeś je do GET var? Możesz także sprawdzić, jak działa przepisywanie pliku robots.txt. Może ci pomóc dowiedzieć się, jak uniknąć przekierowania do my-api.php /
— Will Anderson

Jest to idealne rozwiązanie, jeśli nie obchodzą Cię roboty, takie jak wywołania API.
— beytarovski,

4

Być może nie rozumiem w pełni twoich pytań, ale czy zwykły krótki kod rozwiązałby twój problem?

Kroki:

  1. Poproś klienta o utworzenie strony, tj. Http://mysite.com/my-api
  2. Poproś klienta o dodanie krótkiego kodu na tej stronie, tj. [My-api-shortcode]

Nowa strona działa jako punkt końcowy interfejsu API, a Twój shortcode wysyła żądania do kodu wtyczki w http://mysite.com/wp-content/plugins/my-plugin/my-api.php

(oczywiście oznacza to, że my-api.php miałby zdefiniowany krótki kod)

Prawdopodobnie możesz zautomatyzować kroki 1 i 2 za pomocą wtyczki.


1

Nie zajmowałem się jeszcze zbyt często przepisywaniem, więc jest to prawdopodobnie trochę trudne, ale wydaje się, że działa:

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

Działa, jeśli podłączysz to do „generate_rewrite_rules”, ale musi istnieć lepszy sposób, ponieważ nie chcesz przepisywać pliku .htaccess przy każdym ładowaniu strony.
Wygląda na to, że nie mogę przestać edytować własnych postów ... raczej powinno raczej wejść w ciebie, aktywować oddzwanianie i odwołać się do globalnego $ wp_rewrite. A następnie usuń wpis z non_wp_rules i wyślij ponownie do .htaccess, jeśli dezaktywujesz oddzwanianie.

I na koniec, pisanie na .htaccess powinno być nieco bardziej wyrafinowane, chcesz tylko tam zastąpić sekcję wordpress.


1

Miałem podobne wymagania i chciałem stworzyć kilka punktów końcowych w oparciu o unikalne ślimaki, które wskazywałyby na zawartość generowaną przez wtyczkę.

Zobacz źródło mojej wtyczki: https://wordpress.org/extend/plugins/picasa-album-uploader/

Technika, której użyłem, zaczyna się od dodania filtra the_postsdo badania przychodzącego żądania. Jeśli wtyczka powinna to obsłużyć, generowany jest fałszywy post i dodawane jest działanie template_redirect.

Wywołanie template_redirectakcji musi skutkować wyświetleniem całej zawartości strony, która ma zostać wyświetlona, ​​i wyjściem, w przeciwnym razie powinna powrócić bez generowania danych wyjściowych. Zobacz kod w, wp_include/template-loader.phpa zobaczysz dlaczego.


1

Używam innego podejścia, które polega na zmuszeniu strony głównej do załadowania niestandardowego tytułu, treści i szablonu strony .

Rozwiązanie jest bardzo fajne, ponieważ można je wdrożyć, gdy użytkownik podąża za przyjaznym linkiem, takim jak http://example.com/ ? Plugin_page = moja strona

Jest bardzo łatwy do wdrożenia i powinien pozwalać na nieograniczoną liczbę stron.

Kod i instrukcje tutaj: Generuj na bieżąco niestandardową / fałszywą / wirtualną stronę Wordpress


0

Używam podejścia podobnego do powyższego Xavi Esteve, który przestał działać z powodu aktualizacji WordPress, o ile mogłem powiedzieć w drugiej połowie 2013 roku.

Jest to szczegółowo opisane tutaj: https://stackoverflow.com/questions/17960649/wordpress-plugin-generating-virtual-pages-and-using-theme-template

Kluczową częścią mojego podejścia jest użycie istniejącego szablonu, aby powstała strona wyglądała tak, jakby była częścią witryny; Chciałem, aby był jak najbardziej kompatybilny ze wszystkimi motywami, mam nadzieję, że we wszystkich wersjach WordPress. Czas pokaże, czy miałem rację!


0

jest to gotowy przykład produkcji, najpierw stwórz wirtualną klasę strony:


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

W następnym kroku podpinaj template_redirecti obsługuj swoją wirtualną stronę jak poniżej

    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;


                }


            } );
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.