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

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

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

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

(Я получил этот подход от эту отличную страницу 2012 года от Xavi Esteve).

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

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

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

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

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

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

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

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 - может ли кто-нибудь предлагать предложения или помочь? Все очень ценится.

Ответ 1

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

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

Оказывается, что в 2013 году с WordPress 3.5.2+ (теперь 3,6 по состоянию на неделю назад) решение от Xavi Esteve, упомянутое выше, больше не работает, поскольку WordPress развился, dangit.

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

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

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

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

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

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

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

 $post->ancestors = array();

Это решение используется в плагине WordPress wp-movie (файл 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 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 p >