Simple working examples
Playing with simple working examples is my favorite way of figuring out more advanced functionality. Hope these are useful!
Using the default loop to output:
Using WP_Query to output:
Custom posts
Regular, custom posts type by custom taxonomy
Regular, custom post type by category
The Loop is WordPress
WordPress is a secure, user-friendly “free and open source content management system” (Wikipedia) that stores and retrieves posts (pieces of content, various types). So, by retrieving posts, “The Loop” essentially powers what WordPress “does.”
The following default and custom queries both look for template tag information (data from posts) from the database, stored in the global $post variable, codex, global variables, WP_Post class.
Terms
The Loop (default query), WP developer docs — the PHP that outputs both regular and custom posts onto their default pages, whether single or archive (a collection of posts). The “posts page,” assigned in the Reading Settings, is the archive that displays regular WordPress posts.
The single and archive pages both use index.php, archive.php or single.php, which have almost identical content, the default query loop.
And, within The Loop, WP_Query (custom query), WP developer docs — The WP_Query class lets you query the database directly to output posts that aren’t default to that page. So, for instance, you can output regular posts outside the posts page by assigning categories to the posts, and then retrieving posts by those categories. Essentially, WP_Query lets you retrieve posts by type and category.
The WP_Query class object provides safety and simplicity (protects against SQL injection attacks, ensures proper data types, just “create an arguments array and instantiate the class!” Smashing Magazine) but use the default loop whenever possible, instead, to prevent WP_Query from eating RAM.
Template tags, WP Codex Tag Templates — PHP functions that operate within the loop, and are used to retrieve post data like the post title, URL or author.
Example: <h2><?php get_title(); ?></h2>
the_post() function — “Sets up the global variable with the current post, so that the_title() or the_content() use the title and content from the current post in the query as you loop through it,” Peattie, WP docs
get_posts(), WP Developer docs — a WP_Query class method that can also retrieve posts. It automatically resets The Loop after each call to the database, and outputs posts using a foreach method. More on the differences between get_posts() and WP_Query from Giorgos Sarigiannidis, who prefers get_posts() for simple tasks.
Avoid query_posts(), though, because it changes the variables of the global.
Example of get_posts() from Hubspot
<?php
$count = 1;
$sample_array = get_posts();
foreach( $sample_array as $post )
{
echo "<h3> ${count}. " . $post->post_title . "</h3>";
++$count;
}
?>
You can also directly access the post object, but it’s better to use template tags within The Loop (ie, the previous examples). “Only access the $post
global directly if you’re unable to access the information you want through an existing function,” NateWR.
That being said, here’s an example of retrieving a post ID from the global $post
<?php global $post;
echo $post->ID; ?>
My sample page
(Nothing fancy)
The default loop
A basic loop (below), returns a regular post type to its default pages
<?php
if ( have_posts() ) :
while ( have_posts() ) : the_post(); ?>
<a href="<?php get_permalink() ?>">
<h2><?php get_title() ?></h2>
</a>
<?php endwhile;
else :
_e( 'Sorry, no matches' );
endif;
?>
Output category and taxonomy names
These names link to the archive of all the posts, regular and custom, in that category or taxonomy. Essentially, it’s a clickable “menu” output by the default loop (get_categories(), WP docs).
<div class="container">
<h3>Return category names</h3>
<?php $args = array(
'taxonomy' => 'category',
// for a custom taxonomy, instead use the taxonomy's name:
// 'taxonomy' => 'subjects',
'orderby' => 'name',
'order' => 'ASC',
// to return both used and unused categories
'hide_empty' => false
);
$cats = get_categories( $args );
foreach( $cats as $cat ) { ?>
<a href="<?php echo get_category_link( $cat );?>">
// for a custom taxonomy, instead use:
// <a href="<?php echo get_term_link( $cat );?>">
<?php echo $cat->name; ?><br>
</a>
<?php } ?>
</div>
Helpful post: SO: how to list all category from custom post type?
Output a specific post’s categories
Linked title of the archive page for each category. You might want to add this after the post content on single.php.
<?php
foreach((get_the_category()) as $cat){ ?>
// to output custom taxonomies ("subjects" is the taxonomy name)
// foreach (get_the_terms(get_the_ID(), 'subjects') as $cat) { ?>
<a href="<?php echo get_category_link( $cat->term_id );?>">
// <a href="<?php echo get_term_link( $cat->term_id ) ?>">
<?php echo $cat->name; ?><br>
</a>
<?php } ?>
Helpful posts: SO, List categories of a custom post type, SO: Correct use of get the terms
WP_Query
<?php
/* the query */
$query = new WP_Query( $args );
if ( $the_query->have_posts() ) :
/* the loop */
while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
<h2><?php the_title(); ?></h2>
<?php endwhile;
/* end of the loop */
/* if the query uses the_post(), this reset lets template tags use the main query’s current post again */
wp_reset_postdata();
else :
_e( 'Sorry, no posts match.' );
endif;
?>
WP_Query uses the loop as a method of the object:$category_posts->have_posts()
vs. the default loop:have_posts()
Restore the $post global to its former state with wp_reset_postdata(); otherwise, the $post global will be “stuck on your custom query.” NateWR, SO: “When to use global $post and other global variables”
<?php
endwhile;
wp_reset_postdata();
else:
endif;
?>
Custom Posts
Whether or not you use custom posts depends on how your site is organized. They can be a logical way to sort topics, though. If you create “apple” and “orange” categories for posts about fruit and want to get more specific, it might be simpler to register an “apple” custom post type, and assign it “red” and “golden” categories.
Helpful post: When Do You Need a Custom Post Type, WP Beginner
Register a new custom post type
functions.php
A sample of arguments for a simple, working example. (FYI, if you’re new at this, it’s safest to add code to the bottom of functions.php.)
/* custom post type */
/* Allows your theme to use post thumbnails (images) */
add_theme_support('post-thumbnails');
/* Which post type gets this feature? Also, which feature? */
add_post_type_support( 'Articles', 'thumbnail' );
function create_posttype() {
register_post_type( 'articles',
array(
// How the labels will appear to a user (here, capitalized)
'labels' => array(
'name' => __( 'Articles' ),
'singular_name' => __( 'Article' )
),
'public' => true,
// Allows these posts to show on an archive page
'has_archive' => true,
'rewrite' => array('slug' => 'articles'),
// Makes the posts available to the REST API and the block editor
'show_in_rest' => true,
// Allows the posts to be in both custom and regular categories
'taxonomies' => array( 'subjects', 'category' ),
// Allows you to edit the title, content or add a featured image in the WP backend
'supports' => array('title', 'editor', 'thumbnail'),
)
);
}
add_action( 'init', 'create_posttype' );
The custom post option should now automatically show up here:
Flush permalinks
If everything isn’t displaying at this point, you may need to flush permalinks.
Go to settings > permalinks
You don’t need to make any actual changes, just click “save changes”
Custom post archive and single pages
Create a page in the backend called “Articles” (use the name of your own custom post type) and WordPress will output the custom posts using archives.php (to display all posts) and single.php (single posts).
To customize the output, create an archive-articles.php (paste in a copy of archives.php) and single-articles.php (single.php), and edit them. You can place them directly in the child theme folder.
Output custom post types
<div class="container">
<h3>Returning custom posts</h3>
<?php $args = array(
'post_type'=> 'articles',
'order' => 'ASC',
'posts_per_page' => -1,
);
$query = new WP_Query( $args );
if($query->have_posts() ) :
while ( $query->have_posts() ) :
$query->the_post(); ?>
<div class="row">
<a href="<?php the_permalink(); ?>">
<h5><?php the_title(); ?></h5>
</a>
<?php the_excerpt(); ?>
</div>
<?php
endwhile;
wp_reset_postdata();
else:
endif;
?>
</div>
Custom Taxonomies
Register a new custom taxonomy
“Subjects” is the name of my sample custom taxonomy.
functions.php
/* custom taxonomy */
add_action( 'init', 'create_subjects_hierarchical_taxonomy', 0 );
// highlighted part should be taxonomy name
function create_subjects_hierarchical_taxonomy() {
$labels = array(
'name' => _x( 'Subjects', 'taxonomy general name' ),
'singular_name' => _x( 'Subject', 'taxonomy singular name' ),
'search_items' => __( 'Search Subjects' ),
'all_items' => __( 'All Subjects' ),
'parent_item' => __( 'Parent Subject' ),
'parent_item_colon' => __( 'Parent Subject:' ),
'edit_item' => __( 'Edit Subject' ),
'update_item' => __( 'Update Subject' ),
'add_new_item' => __( 'Add New Subject' ),
'new_item_name' => __( 'New Subject Name' ),
'menu_name' => __( 'Subjects' ),
);
// can be assigned to both regular posts and the custom post type, "articles"
register_taxonomy('subjects', array( 'post', 'articles' ), array(
'hierarchical' => true,
'labels' => $labels,
'show_ui' => true,
'show_in_rest' => true,
'show_admin_column' => true,
'query_var' => true,
'rewrite' => array( 'slug' => 'subject' ),
));
}
Helpful posts: How to Create Custom Taxonomies in WordPress, WP Beginner,
WP Beginner custom taxonomies, Smashing Magazine custom taxonomies,
Add custom taxonomy to custom post type: WP Beginner, How to Create Custom Taxonomies,
Customize a taxonomy or category’s archive page
Regular category — To customize the page that shows all the posts in a specific, regular category, create a category.php file, and paste in the contents of archive.php. Then, edit it and place it in the child theme folder.
Custom taxonomy — To customize the page that shows all the posts in a specific custom taxonomy, create a taxonomy-subjects.php, edit it, and place it in the child theme folder.
Output posts from one or more custom taxonomies
<div>
<?php $args = array(
'post_type'=> array('post', 'articles'),
'order' => 'ASC',
'posts_per_page' => -1,
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'subjects',
'field' => 'slug',
'terms' => 'math',
),
array(
'taxonomy' => 'subjects',
'field' => 'slug',
'terms' => 'english',
),
),
);
$query = new WP_Query( $args );
if($query->have_posts() ) :
while ( $query->have_posts() ) :
$query->the_post(); ?>
<div class="row">
<a href="<?php the_permalink(); ?>">
<h5><?php the_title(); ?></h5>
</a>
<?php the_excerpt(); ?>
</div>
<?php
endwhile;
wp_reset_postdata();
else:
endif;
?>
</div>
Output posts from one or more regular categories
<div class="container">
<h3>Return posts by regular category</h3>
<?php $args = array(
// to return both regular and custom posts
'post_type'=> array('post', 'articles'),
// example of returning all posts from two categories:
'category_name' => 'cheetahs, dolphins',
'order' => 'ASC',
'posts_per_page' => -1,
);
$query = new WP_Query( $args );
if($query->have_posts() ) :
while ( $query->have_posts() ) :
$query->the_post(); ?>
<div class="row">
<a href="<?php the_permalink(); ?>">
<h5><?php the_title(); ?></h5>
</a>
<?php the_excerpt(); ?>
</div>
<?php
endwhile;
wp_reset_postdata();
else:
endif;
?>
</div>
Feedback welcome! Find me on Twitter @SaraHarvy