Bagaimana Anda membuat halaman "virtual" di WordPress

52

Saya mencoba membuat titik akhir API khusus di WordPress, dan saya perlu mengarahkan permintaan ke halaman virtual di root WordPress ke halaman aktual yang dikirimkan bersama dengan plug-in saya. Jadi pada dasarnya, semua permintaan ke satu halaman sebenarnya dialihkan ke yang lain.

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

Maksudnya adalah untuk membuat url untuk titik akhir API sesingkat mungkin (mirip dengan http://mysite.com/xmlrpc.phptetapi untuk mengirim file endpoint API yang sebenarnya dengan plug-in daripada mengharuskan pengguna untuk memindahkan file di sekitar dalam instalasi dan / atau inti hack mereka .

Tusukan pertama saya adalah menambahkan aturan penulisan ulang kustom. Namun, ini punya dua masalah.

  1. Titik akhir selalu memiliki garis miring. Itu menjadihttp://mysite.com/my-api.php/
  2. Aturan penulisan ulang saya hanya diterapkan sebagian. Itu tidak akan mengarahkan ke wp-content/plugins..., itu akan mengarahkan ke index.php&wp-content/plugins.... Ini menyebabkan WordPress menampilkan halaman yang tidak ditemukan kesalahan atau hanya default ke beranda.

Ide ide? Saran?

EAMann
sumber

Jawaban:

55

Ada dua jenis aturan penulisan ulang di WordPress: aturan internal (disimpan dalam database dan diuraikan oleh WP :: parse_request () ), dan aturan eksternal (disimpan di .htaccessdan diuraikan oleh Apache). Anda dapat memilih salah satu cara, tergantung pada seberapa banyak WordPress yang Anda butuhkan di file yang Anda panggil.

Aturan Eksternal:

Aturan eksternal adalah yang termudah untuk diatur dan diikuti. Ini akan dieksekusi my-api.phpdi direktori plugin Anda, tanpa memuat apa pun dari 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 );
}

Aturan Internal:

Aturan internal memerlukan beberapa pekerjaan lagi: pertama kita menambahkan aturan penulisan ulang yang menambahkan kueri vars, lalu kita buat kueri ini publik, dan kemudian kita perlu memeriksa keberadaan kueri var ini untuk meneruskan kontrol ke file plugin kami. Pada saat kita melakukan ini, inisialisasi WordPress yang biasa akan terjadi (kita memisahkan diri sebelum permintaan posting reguler).

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
sumber
3
Saya hanya ingin menambahkan bahwa penting untuk masuk ke halaman Permalinks dan klik "Simpan Perubahan" di WP-Admin. Saya bermain dengan ini selama satu jam sebelum berpikir bahwa saya perlu menyegarkan permalink ... Kecuali ada yang tahu fungsi yang bisa melakukan itu?
ethanpil
Untuk aturan eksternal: Karena jalur ke root web saya memiliki karakter spasi, ini menyebabkan apache jatuh. Ruang putih harus diloloskan jika ada di jalur instalasi wordpress Anda.
Willster
1
Berhasil, tapi sepertinya saya tidak dapat mengakses variabel kueri yang dilewati dengan get_query_vars()di-api.php saya. Saya memeriksa variabel apa yang dimuat. Dan satu-satunya var yang diatur adalah aa WP objectdipanggil $wp. Bagaimana cara mengakses atau mengubah bentuk ini menjadi WP_Queryobjek sehingga saya dapat mengakses variabel yang diteruskan get_query_vars()?
Jules
1
@ Jules: Ketika Anda includefile, itu dieksekusi dalam lingkup saat ini Dalam hal ini, itu adalah wpse9870_parse_requestfungsi, yang hanya memiliki $wpparameter. Mungkin saja $wp_queryobjek global belum ditetapkan saat ini, jadi get_query_var()tidak akan berfungsi. Namun, Anda beruntung: $wpadalah kelas yang berisi query_varsanggota yang Anda butuhkan - saya menggunakannya sendiri dalam kode di atas.
Jan Fabry
1
mencoba membuat aturan penulisan ulang eksternal. menambahkan kepalan kode Anda tetapi saya masih mendapatkan 404. btw: flushed rewrite rules
Sisir
12

Ini berhasil untuk saya. Saya tidak pernah menyentuh API penulisan ulang, tetapi saya selalu mendorong diri saya ke arah baru. Berikut ini berfungsi pada server pengujian saya untuk 3.0 yang terletak di sub folder localhost. Saya tidak melihat masalah jika WordPress diinstal di root web.

Cukup masukkan kode ini dalam plugin dan unggah file bernama "taco-kittens.php" secara langsung di folder plugin. Anda perlu menulis hard flush untuk permalink Anda. Saya pikir mereka mengatakan waktu terbaik untuk melakukan ini adalah pada aktivasi plugin.

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

Salam hangat, -Mike

ladang
sumber
1
Saya mendapat kesalahan akses ditolak saat mencoba kode ini. Saya menduga server atau WP saya tidak suka URL absolut. Ini, di sisi lain, bekerja dengan baik:add_rewrite_rule( 'taco-kittens', 'wp-content/plugins/taco-kittens.php', 'top' );
Jules
Bisakah Anda memberi tahu saya, apa yang harus saya masukkan ke taco-kittens.php, saya tidak memiliki pengetahuan tentang .htaccess atau menulis ulang url.
Prafulla Kumar Sahu
9

Adakah alasan untuk tidak melakukan hal seperti ini?

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

Kemudian cukup kaitkan plugin Anda ke 'init' dan periksa variabel get. Jika ada, lakukan apa yang perlu dilakukan plugin Anda dan mati ()

Will Anderson
sumber
5
Itu akan berhasil, tapi saya mencoba untuk memberikan perbedaan yang sangat jelas antara variabel kueri dan titik akhir yang sebenarnya. Mungkin ada argumen permintaan lain di masa depan, dan saya tidak ingin pengguna mencampuradukkannya.
EAMann
Bagaimana jika Anda menyimpan penulisan ulang, tetapi menulis ulang ke GET var? Anda mungkin juga melihat bagaimana penulisan ulang untuk robots.txt bekerja. Mungkin membantu Anda mengetahui cara menghindari pengalihan ke my-api.php /
Will Anderson
Ini adalah solusi sempurna jika Anda tidak peduli dengan robot seperti panggilan API.
beytarovski
4

Saya mungkin tidak sepenuhnya memahami pertanyaan Anda, tetapi apakah kode pendek sederhana akan menyelesaikan masalah Anda?

Langkah:

  1. Mintalah klien membuat halaman yaitu http://mysite.com/my-api
  2. Mintalah klien menambahkan kode pendek di halaman itu yaitu [kode-my-api-short]

Halaman baru bertindak sebagai titik akhir API dan kode pendek Anda mengirim permintaan ke kode plugin Anda di http://mysite.com/wp-content/plugins/my-plugin/my-api.php

(tentu saja ini berarti my-api.php akan menetapkan kode pendek)

Anda mungkin dapat mengotomatiskan langkah 1 dan 2 melalui plugin.

rexposadas
sumber
1

Saya belum pernah berurusan dengan menulis ulang sebanyak itu, jadi ini mungkin agak kasar, tetapi sepertinya berhasil:

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

Ini berfungsi jika Anda menghubungkan ini ke 'menghasilkan_rewrite_rules', tetapi harus ada cara yang lebih baik, karena Anda tidak ingin menulis ulang .htaccess pada setiap memuat halaman.
Sepertinya saya tidak bisa berhenti mengedit posting saya sendiri ... mungkin sebaiknya Anda mengaktifkan callback dan referensi global $ wp_rewrite sebagai gantinya. Dan kemudian hapus entri dari non_wp_rules dan output ke .htaccess lagi di Anda menonaktifkan panggilan balik.

Dan akhirnya, penulisan untuk .htaccess harus sedikit lebih canggih, Anda hanya ingin mengganti bagian wordpress di sana.

wyrfel
sumber
1

Saya memiliki persyaratan yang sama dan ingin membuat beberapa titik akhir berdasarkan siput unik yang menunjuk ke konten yang dihasilkan oleh plugin.

Lihat sumber untuk plugin saya: https://wordpress.org/extend/plugins/picasa-album-uploader/

Teknik yang saya gunakan dimulai dengan menambahkan filter untuk the_postsmemeriksa permintaan yang masuk. Jika plugin harus menanganinya, posting dummy dihasilkan dan tindakan ditambahkan untuk template_redirect.

Ketika template_redirecttindakan dipanggil, itu harus menghasilkan keluaran seluruh isi halaman yang akan ditampilkan dan keluar atau harus kembali tanpa output yang dihasilkan. Lihat kodenya wp_include/template-loader.phpdan Anda akan tahu sebabnya.

Ken
sumber
0

Saya menggunakan pendekatan yang mirip dengan Xavi Esteve di atas, yang berhenti berfungsi karena peningkatan WordPress sejauh yang saya tahu pada paruh kedua 2013.

Ini didokumentasikan dengan sangat rinci di sini: https://stackoverflow.com/questions/17960649/wordpress-plugin-generating-virtual-pages-and-using-theme-template

Bagian penting dari pendekatan saya adalah menggunakan template yang ada sehingga halaman yang dihasilkan terlihat seperti itu adalah bagian dari situs; Saya ingin agar kompatibel dengan semua tema, semoga di seluruh rilis WordPress. Waktu akan memberi tahu jika saya benar!

Brian C
sumber
0

ini adalah contoh produksi, pertama buat kelas halaman virtual:


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

Pada langkah selanjutnya kaitkan template_redirecttindakan dan tangani halaman virtual Anda seperti di bawah ini

    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
sumber