WP_query (), query_posts () 및 pre_get_posts

@nacin “s 을 읽었습니다. a> 당신은 쿼리를 몰라 어제 약간의 쿼리 토끼 구멍을 보냈습니다. 어제 전에는 모든 쿼리 요구 사항에 query_posts() 를 (잘못) 사용했습니다. 이제는 WP_Query() 사용에 대해 조금 더 현명하지만 여전히 회색 영역이 있습니다.

확실히 알고있는 것 :

추가 사이드 바, 바닥 글, 모든 종류의 “관련 게시물”등 페이지의 모든 곳에서 반복됩니다. . 나는 그것을 한 페이지에서 아무런 해없이 반복해서 사용할 수 있습니다. (권리?).

확실히 모르는 것

  1. 언제 @nacin “s pre_get_posts a를 사용합니까? > 대 WP_Query() ? 지금 모든 작업에 pre_get_posts 를 사용해야합니까?
  2. 템플릿 페이지에서 루프를 수정하려면 — 분류 아카이브 페이지를 수정하고 싶다고 가정 해 보겠습니다. if have_posts : while have_posts : the_post 부분을 제거하고 WP_Query() 를 소유하고 계십니까? 또는 functions.php 파일에서 pre_get_posts 를 사용하여 출력을 수정합니까?

tl; dr

tl; dr 규칙 여기서 그리는 것은 다음과 같습니다.

  1. query_posts 를 사용하지 마십시오. 더 이상
  2. 한 페이지에서 여러 쿼리를 실행할 때 WP_Query()
  3. 를 사용하세요.

  4. 루프를 수정할 때 __________________을 수행하십시오.

지혜 감사합니다

테리

ps : 저는보고 읽었습니다. WP_Query 대 query_posts () 대 get_posts ()는 언제 사용해야합니까? 다른 차원을 추가하는 경우 — get_posts . 그러나 pre_get_posts 를 전혀 처리하지 않습니다. .

댓글

답변

다음과 같이 말할 수 있습니다.

더 이상 query_posts 사용 안함

pre_get_posts

pre_get_posts 모든 쿼리. “기본 쿼리”만 변경하는 데 가장 자주 사용됩니다.

add_action("pre_get_posts","wpse50761_alter_query"); function wpse50761_alter_query($query){ if( $query->is_main_query() ){ //Do something to main query } } 

(또한 is_admin() false 를 반환합니다-중복 될 수 있습니다.) 기본 쿼리는 템플릿에 다음과 같이 표시됩니다.

if( have_posts() ): while( have_posts() ): the_post(); //The loop endwhile; endif; 

이 루프를 편집해야 할 필요가 있다면 pre_get_posts. 즉, query_posts()를 사용하고 싶다면 pre_get_posts를 대신 사용하세요.

WP_Query

기본 쿼리는 WP_Query object 의 중요한 인스턴스입니다. 예를 들어 WordPress는이를 사용하여 사용할 템플릿을 결정하고 URL에 전달 된 인수 (예 : 페이지 매김)는 모두 WP_Query 개체의 해당 인스턴스로 전달됩니다.

보조 루프 (예 : 사이드 바 또는 “관련 게시물”목록)의 경우 “WP_Query 개체의 개별 인스턴스를 만들 수 있습니다. 예 :

$my_secondary_loop = new WP_Query(...); if( $my_secondary_loop->have_posts() ): while( $my_secondary_loop->have_posts() ): $my_secondary_loop->the_post(); //The secondary loop endwhile; endif; wp_reset_postdata(); 

알림 wp_reset_postdata();-이는 보조 루프가 전역 $post 변수는 “현재 게시물”을 식별합니다. 이것은 본질적으로 우리가있는 $post로 재설정합니다.

get_posts ()

이것은 본질적으로 WP_Query 객체의 개별 인스턴스에 대한 래퍼입니다. 이것은 post 객체의 배열을 반환합니다. 위의 루프에서 사용 된 메소드는 더 이상 사용할 수 없습니다. ta “Loop”, 단순히 게시물 개체의 배열입니다.

<ul> <?php global $post; $args = array( "numberposts" => 5, "offset"=> 1, "category" => 1 ); $myposts = get_posts( $args ); foreach( $myposts as $post ) : setup_postdata($post); ?> <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li> <?php endforeach; wp_reset_postdata(); ?> </ul> 

귀하의 질문에 대한 답변

  1. pre_get_posts를 사용하여 기본 검색어를 변경합니다. 템플릿 페이지의 보조 루프에 대해 별도의 WP_Query 개체 (방법 2)를 사용합니다.
  2. 기본 루프의 쿼리를 변경하려면

    .

댓글

  • 그러면 WP_Query가 아닌 get_posts ()로 바로 이동하는 시나리오가 있습니까?
  • @drtanz-예. 예를 들어 ‘ 페이지 매김이 필요하지 않거나 상단에 고정 게시물이 필요하지 않다고 가정 해 보겠습니다.이 경우 get_posts()가 더 효율적입니다.
  • 하지만 ‘ 기본 쿼리를 수정하기 위해 pre_get_posts를 수정할 수있는 추가 쿼리를 추가하지 않습니까?
  • @drtanz-그렇게 하시겠습니까 ‘ 기본 쿼리에는 get_posts()를 사용하지 마십시오. 보조 쿼리에는 사용합니다.
  • @StephenHarris Right =) 사용하는 경우 the_post를 사용하는 대신 객체에 next_post ()를 추가하면 ‘ 전역 쿼리를 수행하지 않고 ‘ 기억할 필요가 없습니다. 나중에 wp_reset_postdata를 사용하세요.

Answer

루프에는 두 가지 컨텍스트가 있습니다.

  • URL 요청에 따라 발생하고 템플릿이로드되기 전에 처리되는 메인 루프
  • 보조

템플릿 파일 또는 기타 방식에서 호출되는 다른 방식으로 발생하는 루프

query_posts() 문제 메인 루프를 시도하고 비참하게 실패하는 것은 2 차 루프라는 것입니다. 따라서 존재하는 것을 잊어 버리십시오.

메인 루프를 수정하려면

  • query_posts()를 사용하지 마십시오.
  • 사용 pre_get_posts $query->is_main_query() 확인
  • 또는 request 필터 ( 너무 거칠어 서 위가 더 좋습니다.)

보조 루프를 실행하려면

new WP_Query 또는 는 거의 상호 교환이 가능합니다 (후자는 이전의 경우 얇은 래퍼).

정리하려면

wp_reset_query() 사용 query_posts()를 사용했거나 글로벌 $wp_query를 직접 엉망으로 만든 경우-거의 필요하지 않습니다.

wp_reset_postdata() the_post() 또는 setup_postdata()를 사용했거나 글로벌 포스트 관련 항목의 초기 상태를 복원해야합니다.

댓글

  • Rarst는 wp_reset_postdata()

답변 r

query_posts($query) 사용에 대한 합법적 인 시나리오가 있습니다. 예를 들면 다음과 같습니다.

  1. 페이지 템플릿을 사용하여 페이지에 게시물 목록 또는 사용자 지정 게시물 유형 게시물을 표시하려는 경우

  2. 해당 게시물의 페이지 매김이 작동하도록하려는 경우

  3. p>

이제 아카이브 템플릿을 사용하는 대신 페이지에 표시하려는 이유는 무엇입니까?

  1. 관리자 (귀하의 고객입니까?)- “페이지”에서 페이지를 볼 수 있습니다.

  2. 메뉴에 추가하는 것이 더 좋습니다 (페이지가없는 경우 URL을 직접 추가하려면)

  3. 템플릿에 추가 콘텐츠 (텍스트, 게시물 썸네일 또는 사용자 지정 메타 콘텐츠)를 표시하려면 다음에서 쉽게 가져올 수 있습니다. 페이지 (그리고 모든 것이 고객에게 더 의미가 있습니다). 아카이브 템플릿을 사용했는지 확인하세요. “추가 콘텐츠를 하드 코딩하거나 테마 / 플러그인 옵션 (고객에게 덜 직관적이게 함)을 사용해야합니다.

다음은 간단한 예제 코드입니다 (페이지 템플릿에있을 것입니다-예 : page-page-of-posts.php).

 /** * Template Name: Page of Posts */ while(have_posts()) { // original main loop - page content the_post(); the_title(); // title of the page the_content(); // content of the page // etc... } // now we display list of our custom-post-type posts // first obtain pagination parametres $paged = 1; if(get_query_var("paged")) { $paged = get_query_var("paged"); } elseif(get_query_var("page")) { $paged = get_query_var("page"); } // query posts and replace the main query (page) with this one (so the pagination works) query_posts(array("post_type" => "my_post_type", "post_status" => "publish", "paged" => $paged)); // pagination next_posts_link(); previous_posts_link(); // loop while(have_posts()) { the_post(); the_title(); // your custom-post-type post"s title the_content(); // // your custom-post-type post"s content } wp_reset_query(); // sets the main query (global $wp_query) to the original page query (it obtains it from global $wp_the_query variable) and resets the post data // So, now we can display the page-related content again (if we wish so) while(have_posts()) { // original main loop - page content the_post(); the_title(); // title of the page the_content(); // content of the page // etc... }  

이제 명확하게하기 위해 여기에서도 query_posts() 사용을 피하고 WP_Query 대신-다음과 같이 :

// ... global $wp_query; $wp_query = new WP_Query(array("your query vars here")); // sets the new custom query as a main query // your custom-post-type loop here wp_reset_query(); // ... 

하지만 사용할 수있는 멋진 작은 기능이 있는데 왜 그렇게할까요?

댓글

  • Brian, 감사합니다. 저는 ‘ 당신이 설명하는 시나리오와 정확히 일치하는 페이지에서 pre_get_posts가 작동하도록 고군분투했습니다. 클라이언트는 그렇지 않으면 아카이브 페이지에 사용자 정의 필드 / 콘텐츠를 추가해야합니다. ” 페이지 “를 만들어야합니다. 클라이언트는 사용자 정의 링크를 추가하면 이스케이프되므로 탐색 메뉴에 추가 할 내용이 표시되어야합니다. 등입니다.
  • ” pre_get_posts “를 사용하여 수행 할 수도 있습니다. 이 작업을 수행하여 ” 정적 프론트 페이지 “가 사용자 정의 순서 및 사용자 정의 필터를 사용하여 내 사용자 정의 게시물 유형을 나열했습니다. 이 페이지도 페이지가 매겨져 있습니다. 작동 방식을 보려면 다음 질문을 확인하세요. wordpress.stackexchange.com / questions / 30851 / … 간단히 말해 query_posts를 사용하는 합법적 인 시나리오는 아직 없습니다.)
  • “이를 사용하여 페이지의 기본 쿼리를 대체하면 최악의 시나리오에서 필요한 작업량을 두 배 이상 늘리는 것 이상으로 페이지로드 시간이 늘어날 수 있습니다. 이 함수는 사용하기 쉽지만 나중에 혼란과 문제가 발생하기 쉽습니다. ” 출처 codex.wordpress.org/Function_Reference/ query_posts
  • 이 답변은 모든 종류의 잘못된 것입니다. 사용자 지정 게시물 유형과 동일한 URL로 WP에서 ” 페이지 “를 만들 수 있습니다. 예를 들어 CPT가 Bananas이면 동일한 URL을 가진 Bananas라는 페이지를 얻을 수 있습니다. 그런 다음 ‘ siteurl.com/bananas로 끝납니다. 테마 폴더에 archive-bananas.php가있는 한 템플릿을 사용하고 대신 해당 페이지를 ” 무시 “합니다. . 다른 의견 중 하나에서 언급했듯이이 ” 방법 “을 사용하면 WP에 대한 작업 부하가 두 배가되므로 절대 사용해서는 안됩니다.

답변

functions.php에서 WordPress 쿼리를 수정합니다.

//unfortunately, "IS_PAGE" condition doesn"t work in pre_get_posts (it"s WORDPRESS behaviour) //so you can use `add_filter("posts_where", ....);` OR modify "PAGE" query directly into template file add_action( "pre_get_posts", "myFunction" ); function myFunction($query) { if ( ! is_admin() && $query->is_main_query() ) { if ( $query->is_category ) { $query->set( "post_type", array( "post", "page", "my_postType" ) ); add_filter( "posts_where" , "MyFilterFunction_1" ) && $GLOBALS["call_ok"]=1; } } } function MyFilterFunction_1($where) { return (empty($GLOBALS["call_ok"]) || !($GLOBALS["call_ok"]=false) ? $where : $where . " AND ({$GLOBALS["wpdb"]->posts}.post_name NOT LIKE "Journal%")"; } 

댓글

  • 이 예제를보고 싶지만 where 절이 사용자 정의 메타에 있습니다.

답변

WordPress는 시간이 지남에 따라 진화하고 일부는 지금 (5 년 후) 달라진 이후 수용된 답변에 대한 개선 사항을 간략하게 설명합니다. :

pre_get_posts는 쿼리를 변경하기위한 필터입니다. “기본 쿼리”만 변경하는 데 가장 자주 사용됩니다.

사실은 액션 후크입니다. 필터가 아니며 모든 쿼리에 영향을줍니다.

기본 쿼리는 템플릿에 다음과 같이 표시됩니다.

if( have_posts() ): while( have_posts() ): the_post(); //The loop endwhile; endif; 

사실 이것은 사실이 아닙니다. 함수 have_posts는 기본 검색어와 관련되지 않은 global $wp_query 개체를 반복합니다. global $wp_query;는 보조 쿼리로도 변경 될 수 있습니다.

function have_posts() { global $wp_query; return $wp_query->have_posts(); } 

get_posts ()

이것은 본질적으로 WP_Query 객체의 개별 인스턴스에 대한 래퍼입니다.

사실 오늘날 WP_Query는 클래스이므로 클래스의 인스턴스가 있습니다.


결론 : 당시 @StephenHarris가이 모든 것이 사실 일 가능성이 높았지만 시간이지나면서 WordPress의 내용이 변경되었습니다.

댓글

  • 기술적으로는 ‘ 모든 필터, 액션은 단순한 필터입니다. 하지만 여기에서 맞습니다. ‘ 인수를 참조로 전달하는 작업이며, 이것이 더 단순한 작업과 다른 점입니다.
  • get_postsWP_Query 개체가 아닌 게시 개체의 배열을 반환하므로 여전히 정확합니다. 그리고 WP_Query는 항상 클래스, 클래스 = 객체의 인스턴스였습니다.
  • 감사합니다, @Milo, 제가 머릿속에 모델을 지나치게 단순화 한 이유에서 맞습니다.

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다