Wie erstelle ich eine "virtuelle" Seite in WordPress?


52

Ich versuche, einen benutzerdefinierten API-Endpunkt in WordPress zu erstellen, und ich muss Anforderungen an eine virtuelle Seite im Stammverzeichnis von WordPress auf eine aktuelle Seite umleiten, die mit meinem Plug-in geliefert wird. Grundsätzlich werden also alle Anforderungen an die eine Seite an die andere weitergeleitet.

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

Das Ziel ist es, die URL für den API-Endpunkt so kurz wie möglich zu halten (ähnlich wie http://mysite.com/xmlrpc.phpbei der Auslieferung der eigentlichen API-Endpunktdatei mit dem Plug-in, anstatt dass der Benutzer Dateien in seiner Installation und / oder seinem Hack-Core verschieben muss) .

Mein erster Versuch war das Hinzufügen einer benutzerdefinierten Regel zum Umschreiben. Dies hatte jedoch zwei Probleme.

  1. Der Endpunkt hatte immer einen abschließenden Schrägstrich. Es wurdehttp://mysite.com/my-api.php/
  2. Meine Umschreiberegel wurde immer nur teilweise angewendet. Es würde nicht umleiten wp-content/plugins..., es würde umleiten index.php&wp-content/plugins.... Dies führte dazu, dass WordPress entweder einen Fehler bei der Anzeige einer nicht gefundenen Seite oder nur die Startseite als Standard anzeigt.

Ideen? Vorschläge?

Antworten:


55

Es gibt zwei Arten von Umschreiberegeln in WordPress: interne Regeln (in der Datenbank gespeichert und von WP :: parse_request () analysiert ) und externe Regeln (in .htaccessApache gespeichert und von Apache analysiert). Sie können eine der beiden Möglichkeiten wählen, je nachdem, wie viel WordPress Sie in Ihrer aufgerufenen Datei benötigen.

Externe Regeln:

Die externe Regel ist am einfachsten einzurichten und zu befolgen. Es wird my-api.phpin Ihrem Plugin-Verzeichnis ausgeführt, ohne etwas von WordPress zu laden.

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

Interne Regeln:

Die interne Regel erfordert etwas mehr Arbeit: Zuerst fügen wir eine Umschreiberegel hinzu, die eine Abfragevariable hinzufügt, dann machen wir diese Abfragevariable öffentlich und müssen dann prüfen, ob diese Abfragevariable vorhanden ist, um das Steuerelement an unsere Plug-in-Datei zu übergeben. Wenn wir dies tun, ist die übliche WordPress-Initialisierung abgeschlossen (wir brechen direkt vor der regulären Post-Abfrage ab).

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
Ich möchte nur hinzufügen, dass es wichtig ist, auf die Permalinks-Seite zu gehen und im WP-Admin auf "Save Changes" zu klicken. Ich habe eine Stunde damit gespielt, bevor ich dachte, ich müsste die Permalinks auffrischen ... Wenn jemand eine Funktion kennt, die das kann?
Ethanpil

Für die externe Regel: Da der Pfad zu meinem Webstamm ein Leerzeichen hatte, fiel der Apache um. Leerzeichen müssen maskiert werden, wenn sie im Pfad zu Ihrer WordPress-Installation vorhanden sind.
Willster

1
Funktioniert, aber ich kann anscheinend mit get_query_vars()my-api.php nicht auf übergebene Abfragevariablen zugreifen. Ich habe überprüft, welche Variablen geladen sind. Und die einzige Variable, die gesetzt wird, ist aa WP objectcalled $wp. Wie kann ich darauf zugreifen oder es in ein WP_QueryObjekt umwandeln, damit ich mit auf die übergebenen Variablen zugreifen kann get_query_vars()?
Jules

1
@Jules: Wenn Sie includeeine Datei erstellen, wird sie im aktuellen Bereich ausgeführt. In diesem Fall ist es die wpse9870_parse_requestFunktion, die nur den $wpParameter hat. Es ist möglich, dass das globale $wp_queryObjekt zu diesem Zeitpunkt noch nicht festgelegt wurde und daher get_query_var()nicht funktioniert. Sie haben jedoch Glück: Ist $wpdie Klasse, die das query_varsMitglied enthält, das Sie benötigen - ich benutze es selbst im obigen Code.
Jan Fabry

1
versuchen, eine externe Umschreiberegeln zu erstellen. fügte Ihr erstes
Sisir

12

Das hat bei mir funktioniert. Ich habe die Rewrite-API nie angerührt, bin aber immer bereit, neue Wege einzuschlagen. Folgendes funktionierte auf meinem Testserver für 3.0 in einem Unterordner von localhost. Ich sehe kein Problem, wenn WordPress im Webroot installiert ist.

Legen Sie diesen Code einfach in einem Plugin ab und laden Sie die Datei "taco-kittens.php" direkt in den Plugin-Ordner hoch. Sie müssen einen Hard Flush für Ihre Permalinks schreiben. Ich denke, sie sagen, dass die beste Zeit dafür die Aktivierung des Plugins ist.

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

Beste Grüße, -Mike


1
Ich habe beim Versuch, diesen Code zu verwenden, einen Fehler mit verweigertem Zugriff erhalten. Ich vermute, dass meinem Server oder WP die absolute URL nicht gefallen hat. Dies funktionierte jedoch einwandfrei:add_rewrite_rule( 'taco-kittens', 'wp-content/plugins/taco-kittens.php', 'top' );
Jules

Kannst du mir bitte mitteilen, was ich in taco-kittens.php eintragen soll, ich habe keine Kenntnis von .htaccess oder url rewrite.
Prafulla Kumar Sahu

9

Gibt es einen Grund dafür, nicht stattdessen so etwas zu tun?

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

Dann binde dein Plugin einfach in 'init' ein und überprüfe, ob die Variable 'get' ist. Wenn es existiert, tue was dein Plugin tun muss und sterbe ()


5
Das würde funktionieren, aber ich versuche, eine sehr klare Unterscheidung zwischen den Abfragevariablen und dem tatsächlichen Endpunkt zu treffen. Möglicherweise wird es in Zukunft andere Abfrageargs geben, und ich möchte nicht, dass Benutzer die Dinge durcheinander bringen.
EAMann,

Was ist, wenn Sie das Umschreiben beibehalten, es aber in die GET-Variable umgeschrieben haben? Sie können sich auch ansehen, wie das Umschreiben für robots.txt funktioniert. Es könnte Ihnen helfen, herauszufinden, wie Sie die Weiterleitung zu my-api.php /
Will Anderson

Es ist die perfekte Lösung, wenn Sie Roboter wie API-Aufrufe nicht interessieren.
Beytarovski

4

Ich verstehe Ihre Fragen möglicherweise nicht vollständig, aber würde ein einfacher Shortcode Ihr Problem lösen?

Schritte:

  1. Lassen Sie den Kunden eine Seite erstellen, z. B. http://meinesite.com/mein-api
  2. Lassen Sie den Client einen Shortcode auf dieser Seite hinzufügen, z. B. [my-api-shortcode].

Die neue Seite fungiert als API-Endpunkt und Ihr Shortcode sendet Anfragen an Ihren Plugin-Code unter http://mysite.com/wp-content/plugins/my-plugin/my-api.php

(Das bedeutet natürlich, dass in my-api.php der Shortcode definiert ist.)

Sie können wahrscheinlich die Schritte 1 und 2 über das Plugin automatisieren.


1

Ich habe noch nicht so viel mit dem Umschreiben zu tun gehabt, daher ist dies wahrscheinlich etwas rau, aber es scheint zu funktionieren:

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

Es funktioniert, wenn Sie dies in 'generate_rewrite_rules' einbinden, aber es muss einen besseren Weg geben, da Sie nicht bei jedem Laden der Seite .htaccess neu schreiben möchten.
Scheint so, als ob ich nicht aufhören kann, meine eigenen Beiträge zu bearbeiten ... es sollte wahrscheinlich eher darum gehen, den Rückruf zu aktivieren und stattdessen auf globales $ wp_rewrite zu verweisen. Entfernen Sie dann den Eintrag aus non_wp_rules und geben Sie ihn erneut in .htaccess aus, indem Sie den Rückruf deaktivieren.

Und schließlich sollte das Schreiben in .htaccess etwas raffinierter sein. Sie möchten nur den WordPress-Abschnitt dort ersetzen.


1

Ich hatte eine ähnliche Anforderung und wollte mehrere Endpunkte basierend auf einzigartigen Slugs erstellen, die auf den vom Plugin generierten Inhalt verweisen.

Schauen Sie sich die Quelle für mein Plugin an: https://wordpress.org/extend/plugins/picasa-album-uploader/

Die Technik, die ich verwendet habe, beginnt mit dem Hinzufügen eines Filters the_posts, um die eingehende Anforderung zu untersuchen. Wenn das Plugin damit umgehen soll, wird ein Dummy-Post generiert und eine Aktion für hinzugefügt template_redirect.

Wenn die template_redirectAktion aufgerufen wird, muss der gesamte Inhalt der anzuzeigenden Seite ausgegeben und beendet werden. Andernfalls wird keine Ausgabe generiert. Lesen Sie den Code in wp_include/template-loader.phpund Sie werden sehen warum.


1

Ich benutze einen anderen Ansatz, der darin besteht , die Homepage zum Laden eines benutzerdefinierten Titels, Inhalts und einer Seitenvorlage zu zwingen .

Die Lösung ist sehr ordentlich, da sie implementiert werden kann, wenn ein Benutzer einem benutzerfreundlichen Link folgt, z. B. http://example.com/ ? Plugin_page = myfakepage

Es ist sehr einfach zu implementieren und sollte unbegrenzte Seiten ermöglichen.

Code und Anweisungen hier: Erstellen Sie eine benutzerdefinierte / gefälschte / virtuelle Wordpress-Seite im Handumdrehen


0

Ich benutze einen ähnlichen Ansatz wie Xavi Esteve oben, der aufgrund eines WordPress-Upgrades nicht mehr funktionierte, soweit ich in der zweiten Jahreshälfte 2013 feststellen konnte.

Es ist hier ausführlich dokumentiert: https://stackoverflow.com/questions/17960649/wordpress-plugin-generating-virtual-pages-and-using-theme-template

Der wichtigste Teil meines Ansatzes ist die Verwendung der vorhandenen Vorlage, sodass die resultierende Seite aussieht, als wäre sie Teil der Website. Ich wollte, dass es mit allen Themen so kompatibel wie möglich ist, hoffentlich über alle WordPress-Versionen hinweg. Die Zeit wird zeigen, ob ich Recht hatte!


0

Es ist ein Beispiel für eine readey-Produktion. Erstellen Sie zunächst eine virtuelle Seitenklasse:


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

Setzen Sie im nächsten Schritt einen Haken template_redirectund bearbeiten Sie Ihre virtuelle Seite wie folgt

    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;


                }


            } );
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.