META_QUERY作为一种方式如何设置CPT永久链接-这是一件好事吗?

时间:2016-06-05 作者:Petr Cibulka

我正在为一家文学杂志创建一个相当复杂的网站。对于其自定义的post类型Issue和Event,我需要与post不同的permalink结构(这是基本的http://example.com/%postname%).

我的任务并不容易,我已经设法想出了一个解决方案,尽管这是一个非常扭曲的问题。由于我不确定这是否理想,我很想听听WP用户的意见,他们了解内部$wp_query 比我做得好。如果WP Stackexchange不适合进行代码审查,请在其他地方向我咨询。

我需要实现以下目标:

URL反映与CPT相关的日期,例如http://example.com/event/%eventyear%/%eventmonth%/%postname%http://example.com/event/%year%/%issue-num%http://example.com/issue/2016/5 和http://example.com/issue/2015/5http://example.com/issue/2012.

$cpt_args = array(
  \'label\' => \'Issue\',
  \'hierarchical\' => false,
  \'has_archive\' => true,
  \'rewrite\' => array(\'slug\' => \'issue/%issueyear%\'),
);
然后,我注册了我的重写标签:

add_action(\'init\', function() use ($tags) {
    add_rewrite_tag("%issueyear%");
});
然后,我已将我的“%issueyear%”的“重写标记翻译”注册到自定义元值:

$func = function($permalink, $post) {

  if (strpos($permalink, "%issueyear%")) {
    $tags_used[] = $t;
  }

  $issue_start = get_post_meta($post->ID, \'t_issue_start\', true);

  $old = basename($permalink);
  $new = $this->date->get_time(\'Y\', $issue_start);
  $permalink = str_replace($old, $new, $permalink);

  return $permalink;

};

add_action(\'post_link\', $func, 10, 2);
add_action(\'post_type_link\', $func, 10, 2);
然后,我添加了重写规则,将元值传递给URL。

add_action(\'init\', function() {
    add_rewrite_rule(
        "^issue/([0-9]{4})/([0-9]{1,})/?",
        \'index.php?post_type=issue&year=$matches[1]&cibulka_key=cibulka_slug&cibulka_val=$matches[2]\',
        \'top\'
    );
};

add_action(\'query_vars\', function($vars) {
    $vars[] = \'cibulka_key\';
    $vars[] = \'cibulka_val\';
    return $vars;
});
URL地址http://example.com/2016/5 会给我档案。php模板。因此,我包括了单个模板,如果$wp_querycibulka_key 设置include_template_with_var 是我的函数,允许向模板传递参数。

/** Archive.php */

global $wp_query;
if (isset($wp_query->query[\'cibulka_key\'])) {
    $meta_value = $wp_query->query[\'cibulka_val\'] . \'_\' . $wp_query->query[\'year\'];
    $args = array(
        \'post_type\' => $wp_query->query[\'post_type\'],
        \'meta_key\' => $wp_query->query[\'cibulka_key\'],
        \'meta_value\' => $meta_value,
        \'posts_per_page\' => 1
    );
    $posts = get_posts($args);
    if (!empty($posts)) {
        $data = array(
            \'id\' => $posts[0]->ID,
            \'post\' => $posts[0]
        );
    } else {
        $data = array();
    }
    include_template_with_var(\'single.php\', $data);
} else {
    // Do normal archive stuff
}
帖子的单个模板$data[\'id\'] 提供而不是存档。php。

Note: 这不是我的实际代码,为了回答我的问题,我对它进行了很多简化。

这达到了我需要达到的所有4点,但我不确定这是否是正确的方法-从性能角度(将有很多事件)、标准角度等等。因此,在我坚持使用此解决方案之前(因为它将产生相当严重的后果,正如设置URL方案一样),我想听听一些意见。

到目前为止,我发现了这些注意事项:

WP识别上的内容http://example.com/issue/5 作为archive, 即使它应该是single. 所以is_single(), is_single(\'issue\') 回来false 以及body_class() 令人困惑当更多的人出现时,我会将他们添加到这里。

提前多谢了!

编辑1我已从存档中删除了条件。php并将其替换为过滤器。这解决了警告1,并从我的模板中删除了逻辑。耶!

// Change global `wp_query` to retrieving the post by meta query AND mark it as single (not archive)
add_action(\'pre_get_posts\', function() {
    global $wp_query;
    if (!isset($wp_query->query[\'cibulka_key\'])) { return; }

    switch ($wp_query->query[\'post_type\']) {
        case \'issue\':
            $meta_value =  $wp_query->query[\'cibulka_val\'] . \'_\' . $wp_query->query[\'year\'];
        break;
    }

    $wp_query->set(\'meta_key\', $wp_query->query[\'cibulka_key\']);
    $wp_query->set(\'meta_value\', $meta_value);

    $wp_query->is_singular = true;
    $wp_query->is_single = true;
    $wp_query->is_archive = false;

    remove_all_actions ( \'__after_loop\');

});

// Use single.php rather than archive.php, if global `$wp_query` contains my custom properties
add_filter(\'template_include\', function($template) {

    global $wp_query;
    if (!isset($wp_query->query[\'cibulka_key\'])) { return $template; }

    $single_tmplt = locate_template(\'single.php\');
    return $single_tmplt;

});
出于某种原因body_class() 不增加single-issue CSS类,但这没什么。。。

add_filter(\'body_class\', function($body_class) {
    if (is_single() && get_post_type() === \'issue\') {
        $body_class[] = \'single-issue\';
    }
    return $body_class;
}, 11, 1);
。。。无法修复。:)

1 个回复
SO网友:majick

由于这是一个性能问题,您可能可以通过以另一种方式存储/获取该数据,而不必设置单独的元字段来匹配。。。

a、 你可以从出版的$post->post_date... 因此,在执行查询时,只需使用date 参数:

$args = array(
    \'post_type\' => $wp_query->query[\'post_type\'],
    \'date_query\' => array( array(\'year\' => $wp_query->query[\'year\']) ),
    \'posts_per_page\' => -1
);
$posts = get_posts($args);
b.您可以使用页面属性设置问题编号$post->menu_order 领域这将有一个额外的优势,即无需任何额外代码就可以提供自己的帖子撰写屏幕元盒(甚至可以在帖子列表屏幕上进行快速编辑),并且与该字段的用途很好地契合(排序问题就像您对页面的排序一样)只需在注册帖子类型时为其添加支持,也可以执行以下操作:

add_post_type_support(\'issue\',\'page-attributes\');
。。。然后按照上面的代码进行操作:

if (!empty($posts)) {
    foreach ($posts as $post) {
        if ($post->menu_order == $wp_query->query[\'cibulka_val\']) {
            $data[\'id\'] = $post->ID;
        }
    }
}
优点是两者兼而有之post_datemenu_order 都在posts 表(因此$post 对象),因此无需SQL访问postmeta 以这种方式匹配数据。。。虽然这可能是一个相当小的收益,如果乘以数千谁知道。。。那一年你可能仍会收到数百篇帖子,并以这种方式循环发布。

因此,您可以使用menu_orderpost_date 如前所述,但是您是否拥有自定义查询来获取帖子ID?这确实是一种非常高效的方法,这里没有什么比这更快的了。例如:

if (isset($wp_query->query[\'cibulka_key\'])) {
    global $wpdb;
    $query = "SELECT ID FROM ".$wpdb->prefix."posts 
              WHERE YEAR(post_date) = \'".$wp_query->query[\'year\']."\' 
              AND menu_order = \'".$wp_query->query[\'cibulka_val\']."\' 
              AND post_status = \'publish\'";
    $postid = $wpdb->get_var($query);
    if ($postid) {
        $data[\'id\'] = $postid;
        // if this is really needed here?
        $data[\'post\'] = get_post($postid);
    } else {$data = array();}
    include_template_with_var(\'single.php\', $data);
}

相关推荐

Plain permalinks not working!

对于我的wordpress网站,普通永久链接不起作用。帖子url正在更改,但当我们单击帖子时,它不会重定向到帖子页面。它将出现在主页上。例如:http://example.com/?p=14523 如果我将永久链接更改为其他自定义格式,它将正常工作并显示帖子页面。例如:http://example.com/2018/09/01/postname/ 我尝试创建一个新的.htaccess 将永久链接更改为普通后的文件。仍然不工作。