Unterschiede zwischen Custom Post Type Archiv und Custom Post Type Query Template

Bildquelle: Pixabay, tdahl

Es gibt unterschiedliche Wege, wie man das Archiv eines selbst definierten Inhaltstyps in WordPress auf den Screen bringt. Je nach Anwendungsfall mag es gute Gründe geben, dafür ein Seiten-Template vorzusehen, und ein Custom Query zu schreiben (oder ihn in eine Funktion packen, um ggf. in einem Shortcode wiederzugeben).

Post Type Archiv

Eigentlich benötigt es kein Template, um ein Post Type Archiv anzuzeigen. Allerdings werden dann (je nach Verfügbarkeitarchive.php oder index.php) nur die Standardelemente angezeigt, in der Anordnung wie sie auch für Beiträge gilt.

Der native und einfachste Weg ist ein Post Type Archiv. Gibt es eigene Felder oder sonstige spezielle Elemente, die der Inhaltstyp wiedergeben soll, wird dies im Inhaltstemplate festgelegt (z.B. template-parts/post/content-news.php), unabhängig davon, ob das Archiv nativ ist, in einem Template definiert wird, oder einer Funktion.

Die index.php ist eine gute Vorlage für das Post Type Archiv. Für den Inhaltstypen news eine Kopie als archive-news.php speichern und ggf. auch den Page-Header modifizieren.

Beispiel-Modifikation archive-news.php

<?php
/**
 *
 * archive for post type "news"
 * 
 */

get_header(); ?>

<div class="wrap">
	<header class="page-header">
		<h2 class="page-title"><?php _e( 'News (Archive) main-query', 'twentyseventeen' ); ?></h2>
	</header>

	<div id="primary" class="content-area">
		<main id="main" class="site-main" role="main">

			<?php
			if ( have_posts() ) :
			
				while ( have_posts() ) : the_post(); 
					/* unter template-parts post muss es ein template content-news.php geben */
					get_template_part( 'template-parts/post/content', 'news' );

				endwhile;
				
				the_posts_pagination( array(
					'prev_text' => twentyseventeen_get_svg( array( 'icon' => 'arrow-left' ) ) . '<span class="screen-reader-text">' . __( 'Previous page', 'twentyseventeen' ) . '</span>',
					'next_text' => '<span class="screen-reader-text">' . __( 'Next page', 'twentyseventeen' ) . '</span>' . twentyseventeen_get_svg( array( 'icon' => 'arrow-right' ) ),
					'before_page_number' => '<span class="meta-nav screen-reader-text">' . __( 'Page', 'twentyseventeen' ) . ' </span>',
				) );
						
			else :

				get_template_part( 'template-parts/post/content', 'none' );

			endif;
			?>

		</main><!-- #main -->
	</div><!-- #primary -->
	<?php get_sidebar(); ?>
</div><!-- .wrap -->

<?php get_footer();

Soll sich die Anzahl angezeigter Elemente von der Standardeinstellung in WordPress unterscheiden, muss folgendes in die functions.php des Childthemes:

function custom_number_of_news($query) {
	if ( ! is_admin() && $query->is_post_type_archive( 'news' ) && $query->is_main_query() ) {
		$query->set( 'posts_per_page', 3 ); /* 3 Elemente pro Seite */
	}	
}
add_filter( 'pre_get_posts', 'custom_number_of_news' );

Custom Post Type Query Template

Soll das Archiv über ein Template in eine Seite geholt werden, ist ein eigener Query erforderlich, und das sieht aus wie folgt.

Beispiel page-news.php

Um als Template in einer Seite wählbar zu sein, muss die Vorlage einen einzigartigen Namen haben, und im Theme oder ggf. Childtheme untergebracht sein.

<?php
/**
 * Template Name: News
 *
 * a custom post type page template
 *
 */
get_header(); ?>

<div class="wrap">
	<header class="page-header">
		<h1 class="page-title"><?php single_post_title(); ?></h1>
	</header>

	<div id="primary" class="content-area">
		<main id="main" class="site-main" role="main">

		<?php
		$args = array(
			'post_type'       => array( 'news' ),
			'post_status'     => array( 'publish' ),
			'posts_per_page'  => '3',
			'paged' => ( get_query_var('paged') ? get_query_var('paged') : ( get_query_var('page') ? get_query_var('page') : 1 ) ),
		);
			

		$loop = new WP_Query( $args );
			
		if ( $loop->have_posts() ) :
		
			while ( $loop->have_posts() ) : $loop->the_post(); 

				/* unter template-parts post muss es ein template content-news.php geben */
				get_template_part( 'template-parts/post/content', 'news' );

			endwhile;
			
			wp_reset_postdata();	
					
			$total_pages = $loop->max_num_pages;

			if ( $total_pages > 1 ) :

				$current_page = max(1, get_query_var('paged'));
				
				$pagination = '<div class="posts-navigation clearfix">'; 
				$pagination .= paginate_links( array(
					'base' => get_pagenum_link(1) . '%_%',
					'format' => '/page/%#%',
					'current' => max(1, get_query_var('paged')),
					'total' => $total_pages,
					'prev_text'    => __('« prev'),
					'next_text'    => __('next »'),
				) );
				
				$pagination .= '</div>';
				echo $pagination;
				
			endif;
			
		
		else :

			get_template_part( 'template-parts/post/content', 'none' );

		endif;	
		?>

		</main><!-- #main -->
	</div><!-- #primary -->
</div><!-- .wrap -->

<?php get_footer();

Pagination in Custom Queries außerhalb von Archiven

Hier wird die Funktion the_posts_pagination() nichts anzeigen.

The posts pagination function outputs a set of page numbers with links to the previous and next pages of posts. These functions are used for post listings (like index.php) or archives (like archives.php).

Würde also jemand vorsehen, die News mit einem Custom Query in einem Seiten-Template abzubilden (das dann auf einer beliebigen Seite in den Page-Attributen zur Auswahl steht), muss der Loop anders aussehen (die Beispieldatei wird unter page-templates/page-news.php des Childthemes abgelegt).

Die Pagination kann mit paginate_links() eingefügt werden (man findet unterschiedliche Snippets dazu im Netz, auch benutzerdefinierte Funktionen). Eine pre_get_posts-Action für eine abweichende Anzahl von Elementen pro Seite gilt bereits über die Definition in den Query-Argumenten, da der main_query schon durch ist, bevor Templates an die Reihe kommen.

Wesentliche Unterschiede zwischen Post Type Archiv und Custom Query Template

  • Im Page-Template muss ein neuer Query angelegt werden, im Post Type Archiv „weiß“ WordPress, um welchen Inhaltstypen es geht.
  • Die Paginierung mit the_posts_pagination funktioniert im Page-Template nicht, stattdessen paginate_links verwenden
  • Das Page-Template muss einer Seite zugewiesen werden, eine korrekt benannte Post Type Archiv-Datei erkennt WordPress automatisch
  • Eine von den WordPress-Einstellungen abweichende Anzahl von Elementen pro Seite muss für das Archiv über pre_get_posts modifiziert werden, im Page-Template gilt das Argument posts_per_page

Auch bei einem Custom Query auf einer Archivseite ist ein Filter erforderlich wenn die Anzahl angezeigter Posts niedriger ist als in den Blog-Einstellungen definiert. Die Anzahl der Seiten wird zwar richtig berechnet, und die Pagination sieht korrekt aus, übersteigt die Seitenanzahl jedoch jene die mit den Blogeinstellungen erreicht würde, zeigt jede darüber hinausgehende Seite 404 an. Sind Custom Taxonomies im Spiel, gilt das auch für sie. Es funktioniert bei einem Archiv-Custom Query sowohl the_posts_pagination als auch paginate_links

function custom_number_of_news($query) {
	if ( $query->is_main_query() && !is_admin() ) {
		if ( $query->is_tax('news_tags') || $query->is_tax('news_category') || $query->is_post_type_archive('news') ) {
			$query->set( 'posts_per_page', 3 );
		}
	}
}
add_filter( 'pre_get_posts', 'custom_number_of_news' );

Bitte Kommentarfunktion nicht für Supportanfragen nutzen. Dem kann hier nicht entsprochen werden. Die Angabe einer E-Mail-Adresse und eines Namens ist nicht erforderlich. Einen (Spitz)-Namen zu nennen wäre aber doch nett.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Hinweis: Sowohl angegebener Name als auch E-Mail-Adresse (beides ist optional, dafür werden alle Kommentare vor Veröffentlichung geprüft) werden dauerhaft gespeichert. Du kannst jeder Zeit die Löschung Deiner Daten oder / und Kommentare einfordern, direkt über dieses Formular (wird nicht veröffentlicht, und im Anschluss gelöscht), und ich werde das umgehend erledigen. – Mit hinterlassenen Kommentaren hinterlegte IP-Adressen werden nach zwei Monaten automatisch gelöscht

publicly queryable