如何创建类别登录页面,然后创建帖子页面?


9

我正在尝试在主题中创建类别模板,如果用户位于存档的第一页上,它将显示静态内容,然后在接下来的页面中显示类别中的帖子。我基本上是想在Wired.com上复制类别行为,其中 http://www.wired.com/category/design是一个登陆页面,而/ category / design / page / 1显示了像您这样的帖子的倒序排列期望在类别存档上。

这里的关键是我不会在首页上显示类别存档中的任何帖子,因此我需要下一页才能从第一篇文章开始。我首先尝试通过使用偏移量和手动分页来执行此操作如果'paged'查询变量为2,则将查询的偏移量设置为0。但是,将偏移量设置为零时会忽略偏移量,因此我能做的最好的就是将偏移量设置为1,然后从类别中的第二个帖子开始。

这是我添加到functions.php中的内容:

add_action('pre_get_posts', 'category_query_offset', 1 );
function category_query_offset(&$query) {
  // Before anything else, make sure this is the right query
  if (!$query->is_category('news')) {
    return;
  }

  // Next, determine how many posts per page
  $ppp = get_option('posts_per_page');

  //Next, detect and handle pagination
  if ($query->is_paged) {
    // Manually determine page query offset
    $page_offset = (($query->query_vars['paged']-1) * $ppp) - $ppp;
    // Apply adjust page offset
    $query->set('offset', $page_offset );
  }
}

更好的方法(以及Wired的效果)是使用默认的分页,以便帖子从第1页开始,但为静态内容插入第0页。假设,如果“ paged”为0,则显示静态内容,如果“ paged”为1,则显示帖子的第一页,这似乎是可能的。问题在于,“ paged”从不为1,因为Wordpress设置了“ paged”当用户请求第一页时,将其设置为零。这意味着/ category / news / page / 1和/ category / news的'paged'均为0。

有没有一种方法可以检查用户是否请求/ category / news / page / 1而不是/ category / news?如果失败,是否有办法显示从第2页开始的类别中的所有帖子?

Answers:


7

这是一个非常有趣的问题(我已经提出了这个问题,特别是针对您的方法和研究)。这里的大曲线球是查询的第一页:

  • 您无法将查询设置为返回0首页上的帖子

  • 通过将每页的页面内容上移一页,您将失去最后一页,因为查询仍然仅具有相同数量的帖子,因此该$max_num_pages属性仍将保持不变

我们将需要以某种方式“欺骗” WP_Query类以完全偏移一页的偏移量返回帖子,并获得正确的页数,以免丢失查询中的最后一页

让我们看一下下面的想法,然后尝试将所有内容放入代码中。但是,在此之前,我想在此提出一些注意事项

重要笔记:

  • 一切都未经测试,因此可能有问题。确保在调试打开的情况下在本地测试

  • 该代码至少需要PHP 5.3,低于5.3的任何版本都将导致致命错误。请注意,如果仍在使用PHP 5.5以下的任何版本,则您应该早已升级

  • 修改并滥用代码,使其适合您的实际需求

灯泡创意:

我们将需要什么

为了使一切正常,我们将需要以下内容:

  • 当前正在查看的页码

  • posts_per_page阅读设置中设置的选项

  • 自订 offset

  • 修改$found_posts查询的$max_num_pages属性以更正该属性

分页是WP_Query非常简单的几行代码

if ( empty($q['nopaging']) && !$this->is_singular ) {
    $page = absint($q['paged']);
    if ( !$page )
        $page = 1;
    // If 'offset' is provided, it takes precedence over 'paged'.
    if ( isset( $q['offset'] ) && is_numeric( $q['offset'] ) ) {
        $q['offset'] = absint( $q['offset'] );
        $pgstrt = $q['offset'] . ', ';
    } else {
        $pgstrt = absint( ( $page - 1 ) * $q['posts_per_page'] ) . ', ';
    }
    $limits = 'LIMIT ' . $pgstrt . $q['posts_per_page'];
}

基本上会发生什么,一旦明确设置了偏移量,该paged参数就会被忽略。将LIMIT根据偏移量重新计算SQL 子句的第一个参数,该参数将是生成的SQL查询中要跳过的帖子数。

从你的问题,显然当设置offset0,偏移查询失败,这是奇怪的,如下面的检查应返回true

if ( isset( $q['offset'] ) && is_numeric( $q['offset'] ) )

0是有效数字,应返回true。如果您的安装上没有安装此软件,则应调试该问题

回到当前的问题,我们将使用相同的逻辑来计算和设置偏移量,以获取第2页上的第1个帖子,然后从中对查询进行分页。对于第一页,我们将不会进行任何更改,因此假定位于第1页的帖子仍将照常显示在页面上,我们只需要稍后“隐藏”它们,以免在页面上显示它们。 1个

add_action( 'pre_get_posts', function ( $q )
{
    if (    !is_admin() // Only target the front end, VERY VERY IMPORTANT
         && $q->is_main_query() // Only target the main query, VERY VERY IMPORTANT
         && $q->is_cateory( 'news' ) // Only target the news category
    ) {
        $current_page = $q->get( 'paged' ); // Get the current page number
        // We will only need to run this from page 2 onwards
        if ( $current_page != 0 ) { // You can also use if ( is_paged() ) {
            // Get the amount of posts per page
            $posts_per_page = get_option( 'posts_per_page' );
            // Recalculate our offset
            $offset = ( ( $current_page - 1) * $posts_per_page ) - $posts_per_page; // This should work on page 2 where it returns 0

            // Set our offset
            $q->set( 'offset', $offset );
        }
    }
});

您应该在第2页的第1页上看到相同的帖子。如前所述,如果没有发生,is_numeric( 0 )则返回false(不应返回),或者您还有另一个pre_get_posts尝试设置偏移量的操作,或者正在使用posts_*子句过滤器(更具体地说是post_limitsfilter)。这将是您需要自己调试的东西。

下一个问题是纠正分页,因为正如我之前所说,您将缺页。为此,我们需要将的值添加get_option( 'posts_per_page' )到查询中找到的帖子数量中,因为我们会将查询偏移该数量。通过这样做,我们有效地添加1了该$max_num_pages属性。

add_action( 'found_posts', function ( $found_posts, $q )
{
    if (    !is_admin() // Only target the front end, VERY VERY IMPORTANT
         && $q->is_main_query() // Only target the main query, VERY VERY IMPORTANT
         && $q->is_cateory( 'news' ) // Only target the news category
    ) {
        $found_posts = $found_posts + get_option( 'posts_per_page');
    }
}, 10, 2 );

除第一页外,这应该对所有内容进行排序。

现在所有(特别是@ialocin- 黄色潜水艇

这都应该进入 functions.php

add_action( 'pre_get_posts', function ( $q )
{
    if (    !is_admin() // Only target the front end, VERY VERY IMPORTANT
         && $q->is_main_query() // Only target the main query, VERY VERY IMPORTANT
         && $q->is_cateory( 'news' ) // Only target the news category
    ) {
        $current_page = $q->get( 'paged' ); // Get the current page number
        // We will only need to run this from page 2 onwards
        if ( $current_page != 0 ) { // You can also use if ( is_paged() ) {
            // Get the amount of posts per page
            $posts_per_page = get_option( 'posts_per_page' );
            // Recalculate our offset
            $offset = ( ( $current_page - 1) * $posts_per_page ) - $posts_per_page; // This should work on page 2 where it returns 0

            // Set our offset
            $q->set( 'offset', $offset );
        }
    }
});

add_filter( 'found_posts', function ( $found_posts, $q )
{
    if (    !is_admin() // Only target the front end, VERY VERY IMPORTANT
         && $q->is_main_query() // Only target the main query, VERY VERY IMPORTANT
         && $q->is_cateory( 'news' ) // Only target the news category
    ) {
        $found_posts = $found_posts + get_option( 'posts_per_page');
    }
    return $found_posts;
}, 10, 2 );

第一页选项

这里有一些选择:

选项1

我很可能会选择这个选项。您要在此处创建一个category-news.php如果尚未执行此操作)。这是将在news查看类别时使用的模板。这个模板将非常简单

<?php
get_header()

if ( !is_paged() ) { // This is the first page
    get_template_part( 'news', 'special' );
} else { // This is not the first page
    get_template_part( 'news', 'loop' );
}

get_sidebar();
get_footer();

如您所见,我包括了两个模板部分,news-special.phpnews-loop.php。现在,这两个自定义模板的基础是:

  • news-special.php->此模板部分将是您要在首页上显示的任何内容。在此处添加所有自定义静态信息。注意不要在此模板中调用循环,因为这会显示第一页的帖子。

  • news-loop.php->这是我们将调用循环的模板。本节如下所示:

    global $wp_query;
    while ( have_posts() ) {
    the_post();
    
        // Your template tags and markup
    
    }

选项2

category_template当您查看news类别的第一页时,使用您的静态内容创建一个单独的模板,只需使用过滤器即可使用此模板。另外,请确保不要在此模板中调用默认循环。另外,请确保此处的命名约定不会与模板层次结构中的模板名称冲突

我希望这是有用的。随意发表有疑虑的评论

编辑

多亏了OP,该WP_Query班级中确实存在一个错误,请检查追踪票#34060。我发布的代码来自Wordpress v4.4,该错误已在此版本中修复。

我回到了bug所在的v4.3的源代码,并且可以确定将0其设置为value时忽略offset了该代码,因为代码只需检查offset参数是否为empty0在PHP中被视为空。我不确定是否仅在v4.3或所有以前的版本中找到此行为(错误)(根据票证,此错误在v4.3中),但是有此错误的补丁程序可以检查在火车票上。就像我说的那样,此错误在v4.4中已得到修复


2
感谢您的详细回答。实际上,这实际上是我第一次尝试时实现的。问题在于将“偏移”设置为0无效。事实证明,这实际上是WordPress Core core.trac.wordpress.org/ticket/34060中的错误。修补它使一切正常。您的代码唯一缺少的是return $found_posts;在found_posts操作中的if语句之后。谢谢!
willcwelch

感谢您的积极反馈。我回到中的4.3版源代码query.php,是的,0因为此处的检查为空,并且0被视为空,所以将被忽略。我的答案中的代码是v4.4附带的更新代码,因此我可以确认该错误已在4.4中修复。我将相应地更新我的答案。在found_posts问题上,好的捕获实际上是一个筛选器,应该返回。享受
Pieter Goosen 2015年

哈哈,谢谢:),所有这些都想知道为什么……一,二,三,四,我还能再多一点吗……这首歌的实际链接现在都在一起了
Nicolai

@ialocin哈哈哈,我会记得这个;-)
Pieter Goosen

1
它很吸引人:)但也就不足为奇了,因为它写得很像儿童歌曲
Nicolai

0

更新:

add_action('pre_get_posts', 'category_query_offset', 1 );
function category_query_offset($query) {
 // Before anything else, make sure this is the right query
 if (!$query->is_category('news')) {
    return;
 }

 // Next, determine paged
 $ppp = get_option('paged');
}
// Next, handle paged
if($ppp > 1){
    $query->set('paged', $ppp-1);
}

尝试一些类似的事情

$paged = ( get_query_var('paged') ) ? get_query_var('paged')-1 : 1;
$args = array (
    'paged' => $paged,
);

我已经更正了有关“分页”变量如何工作的解释。看来您要执行的操作是将每个页码降低1,因此对第2页的请求使您获得第1页。问题是,当查询第1页时,“ paged”设置为0。而且,get_query_var ()应该代替“ paged”的get_option。使用该修复程序,在运行该修复程序时,每次更改查询都会再次循环,直到任何页面请求的“ paged”为0。
willcwelch 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.