I have a custom post named blog, I am using a page with url - slug blog, with custom template for displaying the blog arhive.
This is the query I am using in the template file:
global $wp_query;
$wp_query = new WP_Query( array( 'post_type' => 'blog', /*'cat' => $cat_id, */'orderby' => 'date', 'posts_per_page' => 2, 'paged' => $paged ) );
if ($wp_query -> have_posts()) {
while ($wp_query -> have_posts()) {
$wp_query -> the_post();
echo '<div class="f4">';
echo '<div class = "left">';
echo '<a href = "'; the_permalink(); echo '">';
echo '<div class = "image">';
the_post_thumbnail('home-thumbnail');
echo '</div>';
echo '</a>';
echo '</div>';
echo '<div class = "right">';
echo '<a href = "'; the_permalink(); echo '">';
echo '<h3>'; the_title(); echo '</h3>';
echo '</a>';
echo '<div class = "post-date">Posted on: '; echo get_the_date(); echo '</div>';
the_excerpt();
echo '</div>';
echo '</div>';
};
};
wp_reset_postdata();
// wp_reset_query();
?>
</div>
</div>
<?php echo '<div class = "wrap blog-pagination">';
the_posts_pagination( array( 'mid_size' => 2, 'screen_reader_text' => __( ' ', 'textdomain' ), 'prev_text' => __( '< PREVIOUS', 'textdomain' ),
'next_text' => __( 'NEXT >', 'textdomain' ), ) );
echo '</div>'; ?>
I am Using this script that generates the cpt - blog, and a default custom taxonomy for the blog.
<?php
/*
Plugin Name: blog and taxonomy
Plugin URI: http://www.yashar.site/
Description: A sample plugin to register blog CPT and blog_cat custom taxonomy and add a default category.
Version: 1.0
Author: Yashar Hosseinpour
Author URI: http://www.yashar.site/
*/
namespace My_Plugin;
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
class Blog
{
/**
* Instance of Blog
* @access protected
* @var object $instance The instance of Blog.
*/
private static $instance = null;
/**
* Blog constructor.
* This is a private constructor to be used in getInstance method to do things in a singleton way
* It's a good idea to leave this constructor empty and make `init` method public to use it outside of the class, which is a good thing for Unit Testing
* @access private
*/
private function __construct()
{
$this->init();
}
/**
* Initialize the plugin.
* You can make it public and use it outside of the class
* @access private
* @return void
*/
private function init()
{
// It's possible to use one method to cover these and hook it to `init`. I just like the way using single purpose OOP methods.
// Note the priorities
add_action('init', [$this, 'register_cpt'], 10);
add_action('init', [$this, 'register_blog_cat_tax'], 11);
add_action('init', [$this, 'insert_default_blog_cat_term' ], 12);
// `save_post_{$post->post_type}` hook is used. Doc: https://developer.wordpress.org/reference/hooks/save_post_post-post_type/
add_action( 'save_post_blog', [$this, 'set_default_blog_cat'], 99, 2 );
}
/**
* Register `Blog` CPT and `blog_cat` taxonomy to it
* This should be done after `init`
* @access public
* @wp-hook init
* @return void
*/
public function register_cpt()
{
$labels = array(
'name' => 'Blogs',
'singular_name' => 'Blog',
'add_new' => 'Add New',
'add_new_item' => 'Add New Blog',
'edit_item' => 'Edit Blog',
'new_item' => 'New Blog',
'all_items' => 'All Blogs',
'view_item' => 'View Blog',
'search_items' => 'Search Blogs',
'not_found' => 'No Blogs found',
'not_found_in_trash' => 'No Blogs found in Trash',
'parent_item_colon' => '',
'menu_name' => 'Blog'
);
$args = array(
'public' => true,
'show_in_menu' => true,
'labels' => $labels,
'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments' ),
'taxonomies' => array('post_tag', 'blog_cat')
);
register_post_type('blog', $args);
}
/**
* Register `blog_cat` taxonomy
* This should be done after registering CPT
* @access public
* @wp-hook init
* @return void
*/
public function register_blog_cat_tax() {
$labels = [
'name' => 'blog Categories',
'singular_name' => 'blog Category',
'all_items' => 'All blog Categories',
'edit_item' => 'Edit Category',
'view_item' => 'View Category',
'update_item' => 'Update Category',
'add_new_item' => 'Add New Category',
'new_item_name' => 'Category Name',
'parent_item' => 'Parent Category',
'parent_item_colon' => 'Parent Category:',
'search_items' => 'Search blog Categories',
'popular_items' => 'Popular Categories',
];
register_taxonomy(
'blog_cat',
'blog',
array(
'labels' => $labels,
'show_ui' => true,
'show_tagcloud' => false,
'hierarchical' => true
)
);
}
/**
* Insert default blog_cat
* `default_{$taxonomy}` option is used to make this term as default `blog_cat` term (non-removable)
* @access public
* @wp-hook init
*/
public function insert_default_blog_cat_term()
{
// check if category(term) exists
$cat_exists = term_exists('default_blog_cat', 'blog_cat');
if ( !$cat_exists ) {
// if term is not exist, insert it
$new_cat = wp_insert_term(
'Blog',
'blog_cat',
array(
'description' => ' ',
'slug' => 'blog',
)
);
// wp_insert_term returns an array on success so we need to get the term_id from it
$default_cat_id = ($new_cat && is_array($new_cat)) ? $new_cat['term_id'] : false;
} else {
//if default category is already inserted, term_exists will return it's term_id
$default_cat_id = $cat_exists;
}
// Setting default_{$taxonomy} option value as our default term_id to make them default and non-removable (like default uncategorized WP category)
$stored_default_cat = get_option( 'default_blog_cat' );
if ( empty( $stored_default_cat ) && $default_cat_id )
update_option( 'default_blog_cat', $default_cat_id );
}
/**
* Add an default `blog_cat` taxonomy term for `blog` CPT on save
* If no `blog_cat` is selected, default blog_cat will be registered to the post
* @access public
* @wp-hook save_post_blog
* @param integer $post_id
* @param object $post
*/
public function set_default_blog_cat($post_id, $post)
{
if ( 'publish' === $post->post_status ) {
$blog_cats = wp_get_post_terms( $post_id, 'blog_cat' );
$default_blog_cat = (int) get_option('default_blog_cat');
if ( empty($blog_cats) ) {
wp_set_object_terms( $post_id, $default_blog_cat, 'blog_cat' );
}
}
}
/**
* Instance
* Used to retrieve the instance of this class.
* @access public
* @return object $instance of the class
*/
static public function getInstance() {
if (self::$instance == NULL) {
self::$instance = new self();
}
return self::$instance;
}
}
// Run this
Blog::getInstance();
The problem is that the pagination links are not working. I mean the /blog/page/2/
just end up with the 404 page.
link structure is set to: /%category%/%postname%/ and have to stay this way.