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?

EAMann
źródło

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;
}
Jan Fabry
źródło
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

pola
źródło
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ń ()

Will Anderson
źródło
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.

rexposadas
źródło
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.

wyrfel
źródło
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.

Rozpoznać
źródło
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

Xavi Esteve
źródło
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ę!

Brian C.
źródło
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;


                }


            } );
Mr.Hosseini
źródło