In this post I’ve will teach you how to build a portfolio gallery with Filtering, using custom post types. You don’t need any plugins for this, only code.

How to create a portfolio gallery with filtering in WordPress without Plugins
Step 1. Add the following code to WordPress
In the WordPress dashboard, go to Appearance ➡ Theme File Editor and copy the following code into the theme’s functions.php file and save it.
You must create a child theme before making any changes to functions.php
file. Otherwise, the applied changes will be lost after each update.
Create child theme in WordPress step by step [without plugin]
As an alternative method, you can use the Code Snippets plugin to insert your codes into WordPress.
/*
* [wpcookie-Portfolio description="1"]
* Portfolio gallery with filtering by WPCookie
* https://redpishi.com/wordpress-tutorials/portfolio-gallery-with-filtering-in-wordpress/
*/
add_shortcode( 'wpcookie-Portfolio', 'addmeta_shortcode' );
function addmeta_shortcode($atts) {
$atts = shortcode_atts( array(
'description' => '1',
), $atts, 'wpcookie-Portfolio' );
// static $Portfolio_call = 1;
$description = $atts["description"];
$buffer= '<section class="WPCookie-portfolio section">
<div class="container">
<div class="filters">
<ul>';
$catList='<li class="active" data-filter="*">All</li>';
$terms = get_terms("portfolio_category");
foreach ( $terms as $term ) {
$catList .= '<li data-filter=".'.$term->slug.'">'.$term->name.'</li> ';
}
$buffer .= $catList .'</ul> </div> <div class="filters-content"> <div class="row grid">';
$q = new WP_Query(array(
'post_type' => 'portfolio',
'posts_per_page' => -1,
// 'cat' => $cat,
));
if( $q->have_posts() ) :
while ($q->have_posts()) :
$q->the_post();
$termSlug = "";
$termsArr = get_the_terms(get_the_ID(), 'portfolio_category');
foreach ( $termsArr as $term ) {
$termSlug .= $term->slug . ' ';
}
$buffer .= ' <div class="all '.$termSlug.'">
<div class="item">
<a href="'.get_permalink( get_the_ID() ).'"> '.get_the_post_thumbnail( get_the_ID(), "post-thumbnail" ).' </a>
';
if ( $description == 1 ) {
$buffer .= '<div class="p-inner">
<h5>'.get_the_title().'</h5>
<div class="cat">'.get_the_content().'</div>
</div>';
} else { $buffer .= '<style>.section.WPCookie-portfolio .filters-content .item { --card-shadow : none; }</style>'; }
$buffer .= '</div></div>';
endwhile;
endif;
$buffer.='</div></div></div></section>';
add_action("wp_footer", function(){ ?>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.isotope/3.0.6/isotope.pkgd.min.js"></script>
<style>
.WPCookie-portfolio .row.grid > div {
max-width: 300px;
margin-left: 30px;
}
.WPCookie-portfolio.section {
padding: 30px 0;
color: #333;
--card-shadow : 0px 10px 25px -10px #0000001a;
}
.WPCookie-portfolio.section .top-side {
text-align: center;
}
.WPCookie-portfolio.section .top-side .title {
font-weight: 500;
font-size: 15px;
display: inline-block;
}
.WPCookie-portfolio.section .top-side .title:after {
content: "";
display: block;
width: 50%;
border-bottom: 1px solid #494949;
margin: 8px auto;
}
.section .top-side h2 {
font-weight: 700;
}
.section.WPCookie-portfolio .filters {
text-align: center;
margin-top: 50px;
}
.section.WPCookie-portfolio .filters ul {
padding: 0;
}
.section.WPCookie-portfolio .filters ul li {
list-style: none;
display: inline-block;
padding: 20px 30px;
cursor: pointer;
position: relative;
}
.section.WPCookie-portfolio .filters ul li:after {
content: "";
display: block;
width: calc(0% - 60px);
position: absolute;
height: 2px;
background: #333;
transition: width 350ms ease-out;
}
.section.WPCookie-portfolio .filters ul li:hover:after {
width: calc(100% - 60px);
transition: width 350ms ease-out;
}
.section.WPCookie-portfolio .filters ul li.active:after {
width: calc(100% - 60px);
}
.section.WPCookie-portfolio .filters-content {
margin-top: 50px;
}
.section.WPCookie-portfolio .filters-content .show {
opacity: 1;
visibility: visible;
transition: all 350ms;
}
.section.WPCookie-portfolio .filters-content .hide {
opacity: 0;
visibility: hidden;
transition: all 350ms;
}
.section.WPCookie-portfolio .filters-content .item {
text-align: center;
cursor: pointer;
margin-bottom: 30px;
box-shadow: var(--card-shadow);
border-radius: 5px;
}
.section.WPCookie-portfolio .filters-content .item .p-inner {
padding: 6px 17px 20px 17px;
}
.section.WPCookie-portfolio .filters-content .item .p-inner h5 {
font-size: 15px;
}
.section.WPCookie-portfolio .filters-content .item .p-inner .cat {
font-size: 13px;
}
.section.WPCookie-portfolio .filters-content .item img {
width: 100%;
}
</style>
<script>
var filters = document.querySelectorAll(".WPCookie-portfolio .filters ul li");
var grid = document.querySelector(".WPCookie-portfolio .grid");
var iso = new Isotope(grid, {
itemSelector: ".all",
percentPosition: true,
masonry: {
columnWidth: ".all"
}
});
filters.forEach(function (filter) {
filter.addEventListener("click", function () {
filters.forEach(function (li) {
li.classList.remove("active");
});
this.classList.add("active");
var data = this.getAttribute("data-filter");
iso.arrange({
filter: data
});
});
});
document.addEventListener("DOMContentLoaded", function(){
document.querySelector(".section.WPCookie-portfolio .filters ul li").click();
});
</script>
<?php });
wp_reset_postdata();
//$Portfolio_call = $Portfolio_call + 1;
return $buffer;
}
add_action( 'init', 'wpcookie_register_taxonomy' );
function wpcookie_register_taxonomy() {
$args = [
'label' => esc_html__( 'Portfolio Categories', 'text-domain' ),
'labels' => [
'menu_name' => esc_html__( 'Portfolio Categories', 'wpcooike_portfolio' ),
'name' => esc_html__( 'Portfolio Categories', 'wpcooike_portfolio' ),
'singular_name' => esc_html__( 'Portfolio Category', 'wpcooike_portfolio' ),
'add_new_item' => esc_html__( 'Add new Portfolio Category', 'wpcooike_portfolio' ),
'new_item' => esc_html__( 'New Portfolio Category', 'wpcooike_portfolio' ),
'view_item' => esc_html__( 'View Portfolio Category', 'wpcooike_portfolio' ),
'not_found' => esc_html__( 'No Portfolio Categories found', 'wpcooike_portfolio' ),
'not_found_in_trash' => esc_html__( 'No Portfolio Categories found in trash', 'wpcooike_portfolio' ),
'all_items' => esc_html__( 'All Portfolio Categories', 'wpcooike_portfolio' ),
],
'public' => true,
'show_ui' => true,
'show_in_nav_menus' => true,
'show_admin_column' => true,
'show_in_rest' => false,
'hierarchical' => true,
'rewrite' => array( 'slug' => 'portfolio-category' ),
];
register_taxonomy( 'portfolio_category', 'portfolio', $args );
}
add_action( 'init', 'wpcookie_register_post_type' );
function wpcookie_register_post_type() {
$args = [
'label' => esc_html__( 'Portfolio', 'text-domain' ),
'labels' => [
'menu_name' => esc_html__( 'Portfolio', 'wpcooike_portfolio' ),
'name' => esc_html__( 'Portfolio', 'wpcooike_portfolio' ),
'singular_name' => esc_html__( 'item', 'wpcooike_portfolio' ),
'add_new' => esc_html__( 'Add item', 'wpcooike_portfolio' ),
'add_new_item' => esc_html__( 'Add new item', 'wpcooike_portfolio' ),
'new_item' => esc_html__( 'New item', 'wpcooike_portfolio' ),
'edit_item' => esc_html__( 'Edit item', 'wpcooike_portfolio' ),
'view_item' => esc_html__( 'View item', 'wpcooike_portfolio' ),
'update_item' => esc_html__( 'View item', 'wpcooike_portfolio' ),
'all_items' => esc_html__( 'All items', 'wpcooike_portfolio' ),
'search_items' => esc_html__( 'Search item', 'wpcooike_portfolio' ),
],
'public' => true,
'exclude_from_search' => false,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_nav_menus' => true,
'show_in_admin_bar' => false,
'show_in_rest' => false,
'capability_type' => 'post',
'hierarchical' => true,
'has_archive' => 'portfolio',
'query_var' => true,
'can_export' => true,
'rewrite_no_front' => false,
'show_in_menu' => true,
'menu_position' => 5,
'menu_icon' => 'dashicons-images-alt2',
'supports' => [
'title',
'editor',
'thumbnail',
],
'taxonomies' => [
'portfolio_category',
],
'rewrite' => array( 'slug' => 'portfolio' ),
];
register_post_type( 'portfolio', $args );
}
Step 2. Add your items in the portfolio section
Once you have inserted the code into your WordPress site, you will see a portfolio option in your dashboard menu. Click on it and then click on Add New to create a new portfolio item.

Give your item a title and a short description in the text editor. You can also assign it to a category or make a new one by using the Portfolio Categories box. When you are done, click on Publish to save your item.

Step 3. Use the shortcode to add the portfolio gallery to your page
The following shortcode will allow you to display your portfolio gallery on your page.
[wpcookie-Portfolio]
To hide the item descriptions from the gallery, you can use this shortcode instead:
[wpcookie-Portfolio description="0"]
Portfolio gallery pro
The pro version comes with these new features:
- You can choose which categories to show, instead of showing them all.
- You can add multiple galleries on each page.
Show code
You can specify which categories to show by entering their ID in the cat argument.
[wpcookie-Portfolio description="1" cat="10,15..."]
If this article is difficult for you to read in text, you can watch the video version below.