사용자 정의 루프의 페이지 매김을 수정하는 방법은 무엇입니까?


122

템플릿 파일 / 사용자 정의 페이지 템플릿에 사용자 정의 / 보조 쿼리를 추가했습니다. 기본 쿼리 루프의 페이지 매김을 사용하는 대신 WordPress에서 페이지 매김에 사용자 정의 쿼리를 사용하도록하려면 어떻게해야합니까?

추가

를 통해 기본 루프 쿼리를 수정했습니다 query_posts(). 페이지 매김이 작동하지 않는 이유는 무엇이며 어떻게 수정합니까?

답변:


215

문제

주어진 상황에서 WordPress는 기본 쿼리를 사용하여 페이지 매김을 결정합니다. 기본 쿼리 개체는 $wp_query전역에 저장되며 기본 쿼리 루프를 출력하는 데에도 사용됩니다.

if ( have_posts() ) : while ( have_posts() ) : the_post();

이 때 사용자 지정 쿼리를 사용하여 , 당신은 완전히 별도의 쿼리 객체를 생성 :

$custom_query = new WP_Query( $custom_query_args );

그리고 해당 쿼리는 완전히 별도의 루프를 통해 출력됩니다.

if ( $custom_query->have_posts() ) : 
    while ( $custom_query->have_posts() ) : 
        $custom_query->the_post();

그러나 포함 매김 템플릿 태그는, previous_posts_link(), next_posts_link(), posts_nav_link(),와 paginate_links(), 온 자신의 출력을 기반으로 주요 질의 객체를 , $wp_query. 이 기본 쿼리는 페이지 매김이 될 수도 있고 아닐 수도 있습니다. 예를 들어 현재 컨텍스트가 사용자 정의 페이지 템플리트 인 경우 기본 $wp_query오브젝트는 단일 페이지 (사용자 정의 페이지 템플리트가 지정된 페이지의 ID) 로만 구성 됩니다.

현재 상황이 어떤 종류의 아카이브 지수 인 경우, 메인은 $wp_query주를 위해 : 문제의 다음 부분에 이르게 매김 일으킬만큼 게시물로 구성 될 수있다 $wp_query객체, 워드 프레스는 통과 할 paged 에 기초하여, 쿼리에 매개 변수를 pagedURL 쿼리 변수 쿼리를 가져 오면 해당 paged매개 변수를 사용하여 페이지 매김 된 게시물 집합을 확인할 수 있습니다. 표시된 페이지 매김 링크를 클릭하고 다음 페이지가로드되면 맞춤 검색어에 페이지 매김이 변경되었음을 알 수있는 방법이 없습니다 .

해결책

올바른 페이지 매개 변수를 사용자 정의 쿼리에 전달

사용자 정의 쿼리가 args 배열을 사용한다고 가정합니다.

$custom_query_args = array(
    // Custom query parameters go here
);

올바른 paged매개 변수를 배열 로 전달해야합니다 . 다음을 통해 현재 페이지를 결정하는 데 사용되는 URL 쿼리 변수를 가져 와서 수행 할 수 있습니다 get_query_var().

get_query_var( 'paged' );

그런 다음 해당 매개 변수를 사용자 정의 조회 인수 배열에 추가 할 수 있습니다.

$custom_query_args['paged'] = get_query_var( 'paged' ) 
    ? get_query_var( 'paged' ) 
    : 1;

참고 : 페이지가 있으면 정적 프론트 페이지 , 사용하십시오 page대신에 paged정적 앞 페이지를 사용하기 때문에 page하지 paged. 이것이 정적 프론트 페이지에 필요한 것입니다

$custom_query_args['paged'] = get_query_var( 'page' ) 
    ? get_query_var( 'page' ) 
    : 1;

이제 사용자 지정 쿼리를 가져 오면 페이지 매김 된 올바른 게시물 세트가 반환됩니다.

페이지 매김 함수에 사용자 지정 쿼리 개체 사용

페이지 매김 함수가 올바른 출력 (즉, 사용자 정의 쿼리와 관련된 이전 / 다음 / 페이지 링크)을 생성하려면 WordPress에서 사용자 정의 쿼리를 인식해야합니다. 여기에는 약간의 "해킹"이 필요합니다. 기본 $wp_query개체를 사용자 지정 쿼리 개체로 바꾸십시오 $custom_query.

기본 쿼리 객체 해킹

  1. 기본 조회 오브젝트를 백업하십시오. $temp_query = $wp_query
  2. 기본 쿼리 개체를 null로 설정하십시오. $wp_query = NULL;
  3. 사용자 지정 쿼리를 기본 쿼리 개체로 바꾸십시오. $wp_query = $custom_query;

    $temp_query = $wp_query;
    $wp_query   = NULL;
    $wp_query   = $custom_query;
    

이 "해킹"은 페이지 매김 함수를 호출하기 전에 수행해야합니다.

기본 쿼리 개체를 재설정

페이지 매김 함수가 출력되면 기본 쿼리 개체를 재설정하십시오.

$wp_query = NULL;
$wp_query = $temp_query;

페이지 매김 함수 수정

previous_posts_link()기능은 페이지 매김에 관계없이 정상적으로 작동합니다. 단지 현재 페이지를 결정한 다음에 대한 링크를 출력합니다 page - 1. 그러나 next_posts_link()제대로 출력하려면 수정이 필요합니다 . 매개 변수를 next_posts_link()사용 하기 때문입니다 max_num_pages.

<?php next_posts_link( $label , $max_pages ); ?>

다른 쿼리 매개 변수와 마찬가지로 기본적으로이 함수는 max_num_pages기본 $wp_query개체에 사용됩니다. 객체 를 강제 next_posts_link()로 설명 $custom_query하려면를 max_num_pages함수 에 전달해야 합니다. $custom_query객체 에서이 값을 가져올 수 있습니다 . $custom_query->max_num_pages:

<?php next_posts_link( 'Older Posts' , $custom_query->max_num_pages ); ?>

함께 모아서

다음은 올바르게 기능하는 페이지 매김 함수를 가진 사용자 정의 쿼리 루프의 기본 구성입니다.

// Define custom query parameters
$custom_query_args = array( /* Parameters go here */ );

// Get current page and append to custom query parameters array
$custom_query_args['paged'] = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;

// Instantiate custom query
$custom_query = new WP_Query( $custom_query_args );

// Pagination fix
$temp_query = $wp_query;
$wp_query   = NULL;
$wp_query   = $custom_query;

// Output custom query loop
if ( $custom_query->have_posts() ) :
    while ( $custom_query->have_posts() ) :
        $custom_query->the_post();
        // Loop output goes here
    endwhile;
endif;
// Reset postdata
wp_reset_postdata();

// Custom query loop pagination
previous_posts_link( 'Older Posts' );
next_posts_link( 'Newer Posts', $custom_query->max_num_pages );

// Reset main query object
$wp_query = NULL;
$wp_query = $temp_query;

부록 : 어떻 query_posts()습니까?

query_posts() 보조 루프 용

당신이 사용하는 경우 query_posts()출력에 사용자 정의 루프를,보다는 통해 사용자 지정 쿼리에 대해 별도의 객체를 인스턴스화 WP_Query()당신이있어, _doing_it_wrong()그리고 몇 가지 문제 (안으로 실행됩니다 적어도 어느 매김 문제가 될 것입니다). 이러한 문제를 해결하기위한 첫 번째 단계는 부적절한 사용을 query_posts()적절한 WP_Query()통화 로 전환하는 것입니다 .

query_posts()메인 루프 수정에 사용

페이지 당 게시물 수 변경 또는 카테고리 제외와 같은 기본 루프 쿼리에 대한 매개 변수 만 수정하려는 경우 사용하고 싶을 수 있습니다 query_posts(). 그러나 당신은 여전히해서는 안됩니다. 당신이 사용하는 경우 query_posts(), 당신은 할 수 워드 프레스를 강제로 대체 메인 쿼리 개체를. (WordPress는 실제로 두 번째 쿼리를 작성하고 덮어 씁니다 $wp_query.) 문제는 페이지 매김을 업데이트하기 위해 프로세스에서 너무 늦게 교체를 수행한다는 것입니다.

해결책은 후크 를 통해 게시물을 가져 오기 전에 기본 쿼리필터링하는 것pre_get_posts 입니다.

이것을 카테고리 템플릿 파일 ( category.php) 에 추가하는 대신 :

query_posts( array(
    'posts_per_page' => 5
) );

다음에 추가하십시오 functions.php:

function wpse120407_pre_get_posts( $query ) {
    // Test for category archive index
    // and ensure that the query is the main query
    // and not a secondary query (such as a nav menu
    // or recent posts widget output, etc.
    if ( is_category() && $query->is_main_query() ) {
        // Modify posts per page
        $query->set( 'posts_per_page', 5 ); 
    }
}
add_action( 'pre_get_posts', 'wpse120407_pre_get_posts' );

이것을 블로그 게시물 색인 템플릿 파일 ( home.php) 에 추가하는 대신 :

query_posts( array(
    'cat' => '-5'
) );

다음에 추가하십시오 functions.php:

function wpse120407_pre_get_posts( $query ) {
    // Test for main blog posts index
    // and ensure that the query is the main query
    // and not a secondary query (such as a nav menu
    // or recent posts widget output, etc.
    if ( is_home() && $query->is_main_query() ) {
        // Exclude category ID 5
        $query->set( 'category__not_in', array( 5 ) ); 
    }
}
add_action( 'pre_get_posts', 'wpse120407_pre_get_posts' );

이런 식으로 WordPress는 $wp_query템플릿 수정없이 페이지 매김을 결정할 때 이미 수정 된 개체를 사용합니다.

어떤 기능을 사용 하는가

연구 이 질문을하고 답변을 하고 이 질문에 대답 하는 방법과 때 사용할 이해 WP_Query, pre_get_posts그리고 query_posts().


31
코덱의 소원 페이지가 너무 완벽 할 수 있습니다.
Pieter Goosen

칩, 당신은 내 하루를 만들었습니다!
tepkenvannkorn

1
칩, 당신은 항상 너무 많은 시간을 절약! 내가 미친 검색을하기 전에 구글 만 당신이 더 높은 답변 (Google 직원을위한 콜 아웃)이라면;) 감사합니다.
Sagive SEO

귀하의 예제를 사용하여이 페이지의 중간에 (? : 조건부 대신) 발견 된 if-else 블록을 사용하기 전에는 페이징을 작동시킬 수 없었습니다 : themeforest.net/forums/thread/… , 매우 이상합니다. 그렇지 않으면이 대답은 저에게 많은 것을 가르쳐주었습니다.
P aul

2
좋은 대답-1 가지, 아약스 호출에서 다음 / 이전 포스트 링크 기능을 실행하는 데 문제가있었습니다. 약간의 발굴 후에 글로벌 paged이 업데이트되지 않았다는 것을 알았습니다 (관리자와 관련이 있음) ajax.php 환경) 그래서 나는 이것을 추가했다 : global $paged; $paged = $custom_query_args['paged']; 그리고 그것은 효과가 있었다 :)
acSlater

21

페이지 매김과 함께 사용자 정의 루프 에이 코드를 사용합니다.

<?php
if ( get_query_var('paged') ) {
    $paged = get_query_var('paged');
} elseif ( get_query_var('page') ) { // 'page' is used instead of 'paged' on Static Front Page
    $paged = get_query_var('page');
} else {
    $paged = 1;
}

$custom_query_args = array(
    'post_type' => 'post', 
    'posts_per_page' => get_option('posts_per_page'),
    'paged' => $paged,
    'post_status' => 'publish',
    'ignore_sticky_posts' => true,
    //'category_name' => 'custom-cat',
    'order' => 'DESC', // 'ASC'
    'orderby' => 'date' // modified | title | name | ID | rand
);
$custom_query = new WP_Query( $custom_query_args );

if ( $custom_query->have_posts() ) :
    while( $custom_query->have_posts() ) : $custom_query->the_post(); ?>

        <article <?php post_class(); ?>>
            <h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
            <small><?php the_time('F jS, Y') ?> by <?php the_author_posts_link() ?></small>
            <div><?php the_excerpt(); ?></div>
        </article>

    <?php
    endwhile;
    ?>

    <?php if ($custom_query->max_num_pages > 1) : // custom pagination  ?>
        <?php
        $orig_query = $wp_query; // fix for pagination to work
        $wp_query = $custom_query;
        ?>
        <nav class="prev-next-posts">
            <div class="prev-posts-link">
                <?php echo get_next_posts_link( 'Older Entries', $custom_query->max_num_pages ); ?>
            </div>
            <div class="next-posts-link">
                <?php echo get_previous_posts_link( 'Newer Entries' ); ?>
            </div>
        </nav>
        <?php
        $wp_query = $orig_query; // fix for pagination to work
        ?>
    <?php endif; ?>

<?php
    wp_reset_postdata(); // reset the query 
else:
    echo '<p>'.__('Sorry, no posts matched your criteria.').'</p>';
endif;
?>

출처:


1
이 답변의 변형이있는 또 다른 멋진 자습서 : callmenick.com/post/custom-wordpress-loop-with-pagination
mrwweb

5

언제나 칩처럼 굉장합니다. 이에 대한 부록으로서, "소개 텍스트"에 대해 페이지에 첨부 된 글로벌 페이지 템플리트를 사용하고 그 다음에 페이징하려는 서브 쿼리가 뒤 따르는 상황을 고려하십시오.

사용 ) (paginate_links를 위에서 언급으로, 대부분 기본값으로, (당신은 꽤 영구 링크가 설정 한 가정) 당신의 페이지 매김 링크가 기본값으로하는하는 mysite.ca/page-slug/page/#사랑이다하지만 발생합니다 404워드 프레스는 특정 URL 구조에 대해 알고하지 않기 때문에 실제로 오류를합니다 "page-slug"의 하위 인 "page"의 하위 페이지를 찾으십시오.

여기서의 트릭은 /page/#/구조 를 승인하고 WordPress CAN이 이해할 수있는 쿼리 문자열, 즉 구조 를 승인하는 특정 "의사 아카이브 페이지"페이지 슬러그에만 적용되는 멋진 다시 쓰기 규칙을 삽입하는 것 mysite.ca/?pagename=page-slug&paged=#입니다. 참고 pagenamepaged하지 namepage(여기 답을 동기 부여, 나에게 슬픔의 말 그대로 시간이 발생하는!).

리디렉션 규칙은 다음과 같습니다.

add_rewrite_rule( "page-slug/page/([0-9]{1,})/?$", 'index.php?pagename=page-slug&paged=$matches[1]', "top" );

항상 다시 쓰기 규칙을 변경할 때 관리자 백엔드에서 설정> 영구 링크 를 방문 하여 영구 링크플러시해야합니다 .

이러한 방식으로 작동 할 페이지가 여러 개인 경우 (예 : 여러 사용자 정의 게시물 유형을 처리 할 때) 각 페이지 슬러그에 대해 새 재 작성 규칙을 작성하지 않을 수 있습니다. 식별 한 모든 페이지 슬러그에 대해보다 일반적인 정규식을 작성할 수 있습니다.

한 가지 접근 방식은 다음과 같습니다.

function wpse_120407_pseudo_archive_rewrite(){
    // Add the slugs of the pages that are using a Global Template to simulate being an "archive" page
    $pseudo_archive_pages = array(
        "all-movies",
        "all-actors"
    );

    $slug_clause = implode( "|", $pseudo_archive_pages );
    add_rewrite_rule( "($slug_clause)/page/([0-9]{1,})/?$", 'index.php?pagename=$matches[1]&paged=$matches[2]', "top" );
}
add_action( 'init', 'wpse_120407_pseudo_archive_rewrite' );

단점 /주의 사항

입에서 약간의 소리를내는이 접근법의 한 가지 단점은 페이지 슬러그의 하드 코딩입니다. 관리자가 해당 의사 아카이브 페이지의 페이지 슬러그를 변경하면 다시 작성됩니다.

이 방법에 대한 해결 방법을 생각할 수는 없지만 글로벌 페이지 템플릿이 다시 쓰기 규칙을 트리거 한 경우 좋을 것입니다. 언젠가 다른 사람이 그 특정 너트에 금을 입히지 않으면이 답변을 다시 볼 수 있습니다.


1
게시 저장을 연결하고 페이지에 메타 키 아래에 보관 템플릿이 있는지 확인한 _wp_page_template다음 다른 다시 쓰기 및 플러시 규칙을 추가 할 수 있습니다.
Milo

2

를 통해 기본 루프 쿼리를 수정했습니다 query_posts(). 페이지 매김이 작동하지 않는 이유는 무엇이며 어떻게 수정합니까?

오늘 생성 된 훌륭한 답변 칩을 수정해야합니다.
얼마 동안 우리는 메인 쿼리가 실행 된 직후에 전역 $wp_the_query변수와 같아야하는 변수가 있습니다 $wp_query.

이것이 이것이 칩의 답변에서 나온 부분입니다.

기본 쿼리 객체 해킹

더 이상 필요하지 않습니다. 임시 변수를 만들어이 부분을 잊을 수 있습니다.

// Pagination fix
$temp_query = $wp_query;
$wp_query   = NULL;
$wp_query   = $custom_query;

이제 전화 할 수 있습니다 :

$wp_query   = $wp_the_query;

또는 더 나은 전화 :

wp_reset_query();

다른 칩이 설명하는 모든 것은 유지됩니다. 해당 쿼리 리셋 부분 후에는 페이지 매김 기능을 호출 할 수 있습니다 f($wp_query)그들이에 따라 달라집니다 -, $wp_query세계를.


페이지 매김 메커니즘을 추가로 개선하고 query_posts기능에 더 많은 자유를주기 위해 다음과 같은 가능한 개선을 만들었습니다.

https://core.trac.wordpress.org/ticket/39483


1
global $wp_query;
        $paged = get_query_var('paged', 1);

    $args = array( 
        'post_type' => '{your_post_type_name}',
        'meta_query' => array('{add your meta query argument if need}'),  
        'orderby' => 'modified',
        'order' => 'DESC',
        'posts_per_page' => 20,
        'paged' => $paged 
    );
    $query = new WP_Query($args);

    if($query->have_posts()):
        while ($query->have_posts()) : $query->the_post();
            //add your code here
        endwhile;
        wp_reset_query();

        //manage pagination based on custom Query.
        $GLOBALS['wp_query']->max_num_pages = $query->max_num_pages;
        the_posts_pagination(array(
            'mid_size' => 1,
            'prev_text' => __('Previous page', 'patelextensions'),
            'next_text' => __('Next page', 'patelextensions'),
            'before_page_number' => '<span class="meta-nav screen-reader-text">' . __('Page', 'patelextensions') . ' </span>',
        ));
    else:
    ?>
        <div class="container text-center"><?php echo _d('Result not found','30'); ?></div>
    <?php
        endif;
    ?>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.