WordPress 缺省模板重载

howto override wordpress default template

我们知道 WordPress 有一套自己的内容显示流程以及相关显示模板的加载方式,但在有些应用场景可能需要对缺省的流程和显示方式做客户化定制,比如从其它 URL 获取的内容,显示在文章的某个区域,本篇文章就介绍具体的实现方法。

这里主要通过 WordPress 的三个钩链来实现,包括 template_includewp_headthe_content

首先就是重载缺省的显示模板,也就是在加载预定义模板(主题)之前加载自定义内容及显示方式,这是通过钩链 template_include 来处理的。

...
//下面的代码可以放到插件的主程序中
add_filter(
    'template_include',
    function( $template ) {
      //当前显示的内容是页面 “site_map” 时用自定义模板
      if (is_page('site_map'))
        return plugin_dir_path( __FILE__ ) . '/template.php';
      return $template;
    },
    20
);
...

上面的代码中使用了过滤条件 is_page(),就是当前访问页面 “site_map” 时使用自定义模板,否则使用缺省模板。另外,过滤条件可以组合使用,比如 is_front_page()is_single() 等。这里列出了各种条件函数的说明,可以参考一下。

在自定义模板中,使用 wp_remote_get 从其它 URL 地址处获取网页内容,并保持原来的显示样式,这需要分离获取页面 <head> 标签部分,与现有主题 <head> 中的内容合并,然后通过钩链 wp_head 来完成。

template.php

...
$url = 'http://localhost:8080';
$args = array(
	'httpversion' => '1.1',
	'headers' => array(
		'referer' => home_url()
	)
);
$response = wp_remote_get( $url, $args );
if ( is_wp_error( $response ) ) {
  status_header( 500 );
  require_once plugin_dir_path( __FILE__ ) . 'error.php';
} else {
  $isStatic = preg_match(
    '/\.(js|png|jpe?g|gif|svg|woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/i',
    $_SERVER['REQUEST_URI']
  );
  header( 'content-type: ' . $response['headers']['content-type'] );
  status_header( $response['response']['code'] );

  //非静态资源处理
  if (!$isStatic) {
    //分离标签<head>和<body>中的内容
    list($head, $rest) = preg_split('/(?=<\/head>)/', wp_remote_retrieve_body( $response ) );
    list($body, $end) = preg_split('/(?=<\/body>)/', $rest);

    //这里如果使用获取页面的<head>,就用echo $head,下面的代码做<head>内容合并
    $head_data = preg_replace('/<\s+head\s+>/', '', $head, 1);
    $body_data = preg_replace('/<\s+body\s+>/', '', $body, 1);

    //使用钩链wp_head,当主题header.php中调用wp_head()时合并获取页面<head>内容
    add_action('wp_head', function () {
            global $head_data;
            echo $head_data;
        });
    get_header();  //调用主题header.php,合并其<head>中的定义,同时渲染其内容

    //这里如果直接显示获取页面<body>中的内容就调用 echo $body,使用the_content钩链是为了把内容显示在文章的显示区域
    add_filter( 'the_content', function() {
            global $body_data;
            return $body_data;
        }, -1 );
    the_content();
    //调用主题footer.php
    get_footer();
    //如果不做原主题相关内容的合并处理就调用 echo $end
  } else {
    //静态资源不做处理,原样输出
    echo wp_remote_retrieve_body( $response );
  }
}
...

通过上面的代码,可以把获取网页的内容显示在当前主题定义的文章显示区域,同时显示主题 header.php 和 footer.php 中的内容(显示侧边栏就调用 get_sidebar),如果仅需要显示获取网页的内容,就按照上面代码中的提示,不做合并处理即可。

发表评论

邮箱地址不会被公开。 必填项已用*标注