Плагин Wordpress, генерирующий виртуальные страницы и использующий шаблон темы

Мне нужно иметь возможность создавать поддельные/виртуальные/динамические страницы на основе URL-адреса, такого как http://www.mycinema.com/wpcinema/movie/MOVIEID, чтобы иметь возможность отображать фильмы для кинотеатров с информацией о фильме и информацией о прямой трансляции.

Потратив много часов на исследования, похоже, не так много написано о том, как создавать виртуальные страницы в WordPress, поэтому я буду описывать свой опыт после решения этой проблемы!

На данный момент текущий план состоит в том, чтобы использовать два фильтра: template_redirect для установки шаблона в соответствии с текущим шаблоном page.php плагина и the_content для вставки контента. Идея состоит в том, чтобы использовать шаблон темы, чтобы тема страниц хорошо сочеталась с сайтом.

(Я получил этот подход от эту прекрасную страницу 2012 года от Хави Эстеве).

У меня две проблемы:

  1. Каков наилучший, наиболее пуленепробиваемый способ сделать это? Я использую неправильный подход? Я думал, что использование шаблона текущей темы, скорее всего, обеспечит наилучшее соответствие стилю веб-сайта.

  2. Похоже, что TwentyTwelve не вызывает фильтр the_content в том контексте, в котором я его использую. Я подозреваю, что делаю что-то не так, но не могу найти проблему. Это, вероятно, тесно связано с вопросом 1. TwentyTwelve определенно вызывает the_content для обычной страницы, и даже ранний add_filter() не срабатывает в моем коде.

Вчера я обнаружил get_template_part() и задался вопросом, должен ли я использовать это вместо того, чтобы вручную искать в дочерней папке, а затем в родительской и запускать include.

Я бы не спрашивал, но я на грани ума, много гуглил, возможно, в поисках неправильных условий поиска.

Я рассматривал пользовательские типы сообщений, но с этим связаны различные сложности (включая контент, который может меняться каждые несколько минут), что означает, что динамически генерируемые страницы работают намного лучше.

Это отрывок из кода, который я написал для дальнейшего объяснения проблемы:

add_action('parse_request', array(&$this, 'vm_parse_request'));

function vm_parse_request( &$wp )
{
    global $wp;
    if (empty($wp->query_vars['pagename']))
        return; // page isn't permalink

    $p = $wp->query_vars['pagename'];

    if (! preg_match("#wp-cinema/movie/([^/]+)#", $p, $m))
        return;

    // setup hooks and filters to generate virtual movie page
    add_action('template_redirect', array(&$this, 'vm_template_redir'));
    add_filter('the_content', array(&$this, 'vm_the_content'));
}

function vm_template_redir()
{
    // Reset currrently set 404 flag as this is a plugin-generated page
    global $wp_query;
    $wp_query->is_404 = false;

    $template = 'page.php';

    include(STYLESHEETPATH."/page.php"); // child
    // parent case left out for brevity

    exit;
}


function vm_the_content($content)
{
    return "my new content (actually generated dynamically)";
}

Это будет все более распространенным явлением в WordPress — кто-нибудь может предложить предложения или помощь? Все очень ценится.


person Brian C    schedule 31.07.2013    source источник
comment
Привет, Брайан, интересно, могу ли я применить виртуальные страницы к заголовку моего вопроса wordpress.stackexchange.com/questions/110118/ что вы думаете?   -  person Radek    schedule 15.08.2013
comment
Радек - хотя я не проверял, я думаю, вы могли бы, если бы вы могли установить домашнюю страницу как нечто отличное от существующей страницы. Или вы можете использовать мой код, чтобы переопределить его.   -  person Brian C    schedule 20.02.2014


Ответы (1)


(Обновление внизу статьи, включая ссылку на суть улучшенного рабочего кода)

Я хотел опубликовать ответ на это, так как кажется, что НИ ОДИН из вопросов о виртуальных страницах WordPress здесь не имел ответов! И было потрачено много крови, чтобы получить ответ на этот вопрос, протестировать его и убедиться, что он работает хорошо. Надеюсь, это спасет некоторых других от боли, через которую я прошел...

Оказывается, в 2013 году с WordPress 3.5.2+ (теперь 3.6 по состоянию на неделю назад) решение от Хави Эстеве, упомянутое выше, больше не работает, поскольку WordPress эволюционировал, черт возьми.

При использовании метода template_redirect, описанного выше, проблема заключается в том, что для WordPress отсутствует контент страницы/публикации, и поэтому многие темы не будут вызывать the_content(), поэтому мой код в фильтре the_content никогда не вызывается.

Лучшим решением в настоящее время кажется подключение к фильтру 'the_posts' и возврат псевдостраницы, однако сама по себе она не имеет прикрепленной к ней темы.

Решение проблемы отсутствия темы состояло в том, чтобы смешать это с частью подхода Хави Эстеве, чтобы позволить мне изменить шаблон, используемый для создания страницы.

Этот подход должен работать сразу для большинства, если не для всех тем WordPress, что было моей целью, и он работает очень хорошо с темами, которые я тестировал до сих пор.

Я использовал подход, задокументированный Дейвом Джешем на этой странице (есть и другие версии этого, но Дэйв — единственный, кто подробно объяснил его, спасибо, Дэйв!): http://davejesch.com/wordpress/wordpress-tech/creating-virtual-pages-in-wordpress/

Я также прошел через много боли здесь с разделом комментариев Wordpress, появляющимся внизу страницы в некоторых темах. Решение для этого появится в файле, указанном выше, и, вероятно, выходит за рамки этого конкретного решения.

Кроме того, чтобы предотвратить предупреждение с WordPress 3.5.2+, мне также пришлось добавить участника записи:

 $post->ancestors = array();

Это решение используется в плагине wp-cinema для WordPress (файл views.php). если вы хотите получить какой-то рабочий код, его следует проверить в ближайшие несколько недель). Если возникнут проблемы с подходом, я буду поддерживать этот файл в актуальном состоянии, поскольку он является частью более крупного проекта.

Полное рабочее решение ниже. Это выдержка из гораздо более длинного фрагмента кода, который также предотвращает появление комментариев и т. д. (см. ссылку, приведенную выше). Код:

add_action('parse_request', 'vm_parse_request');


// Check page requests for Virtual movie pages
// If we have one, generate 'movie details' Virtual page.
// ...
//
function vm_parse_request(&$wp)
{
    if (empty($wp->query_vars['pagename']))
       return; // page isn't permalink

    $p = $wp->query_vars['pagename'];

    if (! preg_match("#wp-cinema/movie/([^/]+)#", $p, $m))
       return;

    // setup hooks and filters to generate virtual movie page
    add_action('template_redirect', 'vm_template_redir');

    $this->vm_body = "page body text";

    add_filter('the_posts', 'vm_createdummypost');

    // now that we know it's my page,
    // prevent shortcode content from having spurious <p> and <br> added
    remove_filter('the_content', 'wpautop');
}


// Setup a dummy post/page 
// From the WP view, a post == a page
//
function vm_createdummypost($posts)
{
    // have to create a dummy post as otherwise many templates
    // don't call the_content filter
    global $wp, $wp_query;

    //create a fake post intance
    $p = new stdClass;
    // fill $p with everything a page in the database would have
    $p->ID = -1;
    $p->post_author = 1;
    $p->post_date = current_time('mysql');
    $p->post_date_gmt =  current_time('mysql', $gmt = 1);
    $p->post_content = $this->vm_body;
    $p->post_title = $this->vm_title;
    $p->post_excerpt = '';
    $p->post_status = 'publish';
    $p->ping_status = 'closed';
    $p->post_password = '';
    $p->post_name = 'movie_details'; // slug
    $p->to_ping = '';
    $p->pinged = '';
    $p->modified = $p->post_date;
    $p->modified_gmt = $p->post_date_gmt;
    $p->post_content_filtered = '';
    $p->post_parent = 0;
    $p->guid = get_home_url('/' . $p->post_name); // use url instead?
    $p->menu_order = 0;
    $p->post_type = 'page';
    $p->post_mime_type = '';
    $p->comment_status = 'closed';
    $p->comment_count = 0;
    $p->filter = 'raw';
    $p->ancestors = array(); // 3.6

    // reset wp_query properties to simulate a found page
    $wp_query->is_page = TRUE;
    $wp_query->is_singular = TRUE;
    $wp_query->is_home = FALSE;
    $wp_query->is_archive = FALSE;
    $wp_query->is_category = FALSE;
    unset($wp_query->query['error']);
    $wp->query = array();
    $wp_query->query_vars['error'] = '';
    $wp_query->is_404 = FALSE;

    $wp_query->current_post = $p->ID;
    $wp_query->found_posts = 1;
    $wp_query->post_count = 1;
    $wp_query->comment_count = 0;
    // -1 for current_comment displays comment if not logged in!
    $wp_query->current_comment = null;
    $wp_query->is_singular = 1;

    $wp_query->post = $p;
    $wp_query->posts = array($p);
    $wp_query->queried_object = $p;
    $wp_query->queried_object_id = $p->ID;
    $wp_query->current_post = $p->ID;
    $wp_query->post_count = 1;

    return array($p);
}


// Virtual Movie page - tell wordpress we are using the page.php
// template if it exists (it normally will).
//
// We use the theme page.php if we possibly can; if not, we do our best.
// The get_template_part() call will use child theme template if it exists.
// This gets called before any output to browser
//
function vm_template_redir()
{
    // Display movie template using WordPress' internal precedence
    //  ie: child > parent; page-movie.php > page.php
    //  this call includes the template which outputs the content
    get_template_part('page', 'movie');

    exit;
}

Кстати, важно сказать, что я чувствую, что это в значительной степени хак, и хотел бы знать, как это можно было бы сделать лучше. Кроме того, я бы хотел, чтобы WordPress шагнул вперед и предоставил API для создания поддельных страниц. (Я подозреваю, что у них есть идеологические причины, по которым они этого не сделают, но было бы неплохо увидеть их решения, пусть даже альтернативные, с подробным объяснением); Я лично чувствую, что есть случаи, когда я не хочу вмешиваться в сайт пользователя только для создания страниц.

ОБНОВЛЕНИЕ, февраль 2014 г. Я абстрагировал это в класс, который должен обеспечивать достаточную гибкость для большинства приложений: https://gist.github.com/brianoz/9105004

person Brian C    schedule 11.08.2013
comment
С тех пор я превратил его в класс для управления несколькими виртуальными страницами. Класс вызывает предоставленную функцию содержимого при совпадении регулярного выражения. Когда я буду уверен в этом, я заменю приведенную выше ссылку ссылкой на файл класса (который включает пример). Подтолкните меня, если вам это нужно, и я забыл! :) - person Brian C; 13.08.2013
comment
Это интересный метод. Я пытался сделать что-то подобное некоторое время для умеренного успеха. У вас есть ссылка на файл класса, который вы сделали доступным? - person The Salt; 11.01.2014
comment
Извините, да; Я забыл, что уже сделал это. Суть здесь (также обновленная статья): gist.github.com/brianoz/9105004 Это должно быть достаточно гибким, чтобы работать с большинством приложений, приветствуется обратная связь. - person Brian C; 20.02.2014
comment
Класс, связанный с Gist, отлично работал для моего варианта использования (создание виртуальных страниц на основе первой части URL-адреса). Стоит прочитать комментарии на странице Gist — там три строки кода, которые вам нужно изменить, чтобы сделать его функциональным. - person Andrew Sauder; 22.08.2015