This tutorial provides the steps to set up entries of a portfolio custom post type that can be filtered by the terms of associated portfolio_category custom taxonomy using Isotope in Oxygen.

Live Demo

We shall

  • create a template and apply it on the `portfolio` CPT archive page
  • edit the template and add a Easy Posts element inside Inner Content’s Section
  • use a custom query in Easy Posts so we can show all the entries
  • load and initialize Isotope in a custom plugin
  • add a custom callback function to output space separated terms of the specified taxonomy for the current entry
  • echo the space separated terms for div.oxy-post by editing the template’s PHP for Easy Posts grid
  • add a custom callback function that displays buttons with specified taxonomy terms as values of custom data-filter attribute
  • add a Code Block element, move it above the Easy Posts element and call the above function to display the filtering buttons row

This technique can also be applied to posts of any post type and any taxonomy.

Step 1

Install and activate my custom functionality plugin.

Step 2

Connect to your server using a FTP client.

Upload isotope.pkgd.min.js and imagesloaded.pkgd.min.js to assets/js directory.

Create a file named say, isotope-init.js in the same location having this code:

(function ($) {

    // init Isotope
    var $grid = $('.oxy-posts').isotope({

        // specifies which child elements will be used as item elements in the layout
        itemSelector: '.oxy-post',

        // sets item positions in percent values, rather than pixel values
        percentPosition: true,

        // lays out items to (mostly) maintain horizontal left-to-right order
        horizontalOrder: true,

        layoutMode: 'fitRows'

    // filter items on button click
    $('.filter-button-group').on('click', 'button', function () {
        var filterValue = $(this).attr('data-filter');

        $grid.isotope({ filter: filterValue });



    // layout Isotope after each image loads
    $grid.imagesLoaded().progress(function () {

Step 3

In your plugin’s main PHP file, inside custom_enqueue_files() add

if ( is_post_type_archive( 'portfolio' ) ) {

        plugin_dir_url( __FILE__ ) . 'assets/js/isotope.pkgd.min.js',
        array( 'jquery' ),

        plugin_dir_url( __FILE__ ) . 'assets/js/imagesloaded.pkgd.min.js',

        plugin_dir_url( __FILE__ ) . 'assets/js/isotope-init.js',
        array( 'isotope', 'imagesLoaded' ),


Step 4

Install and activate Portfolio Post Type plugin.

Add your portfolio entries and set featured images.

Assign the entries to their corresponding portfolio categories.

Step 5

Create a template named say, Filterable Portfolio in Oxygen.

You might want to import a Main template that has your site header and footer (with a Inner Content in between).

Set this to be applied on portfolio CPT archive.

Also, set its priority to 10 to ensure that it takes precedence over other generic template(s) that may be set to apply for archives.

Edit the template and add a Section and inside that, Easy Posts element.

In the Query area, set a custom one with Post Type set to portfolio, and to show all posts in the Count area.

In your custom functionality plugin’s PHP file, add

 * Callback function to output space separated terms of the specified taxonomy for the current entry.
 * @param string $taxonomy Name of the taxonomy.
 * @return string Space separated classes.
function sk_get_terms( $taxonomy ) {

    $terms = get_the_terms( get_the_ID(), $taxonomy );

    if ( $terms ) {
        foreach ( $terms as $term ) {
            $classes[] = esc_attr( $term->slug );

        return ' ' . implode( ' ', $classes );
    } else {
        return '';


Back in Oxygen, go to Templates area for the Easy Posts element and add this PHP:

<div class='oxy-post<?php echo sk_get_terms( "portfolio_category" ); ?>'>

    <a class='oxy-post-image' href='<?php the_permalink(); ?>'>
      <div class='oxy-post-image-fixed-ratio' style='background-image: url(<?php echo get_the_post_thumbnail_url(); ?>);'>

      <div class='oxy-post-image-date-overlay'>
        <?php the_time(get_option('date_format')); ?>


    <a class='oxy-post-title' href='<?php the_permalink(); ?>'><?php the_title(); ?></a>


Step 6

In your custom functionality plugin’s PHP file, add

 * Callback function that displays buttons with specified taxonomy terms as values of custom data-filter attribute.
 * @param string $taxonomy Name of the taxonomy.
 * @return void
function sk_get_filters( $taxonomy ) {

    $terms = get_terms( $taxonomy );

    $count = count( $terms );

    if ( $count > 0 ) { ?>
        <div class="portfolio-categories filter-button-group">
            <button class="active" data-filter="*"><?php esc_html_e( 'All', 'text-domain' ); ?></button>

            <?php foreach ( $terms as $term ) { ?>
                <button data-filter=".<?php echo esc_attr( $term->slug ); ?>"><?php echo esc_html( $term->name ); ?></button>
            <?php } ?>


Add a Code Block element and move it to above Easy Posts.

Add this for PHP:

    sk_get_filters( 'portfolio_category' );

You might want to give it 15px of margin on left and right and some 20px at the bottom.

To style the filter buttons you could use the Selector Detector feature in Oxygen or alternatively, put this in the CSS area:

.filter-button-group button {
    margin-right: 6px;
    margin-bottom: 14px;
    padding: 12px 30px;
    border: none;
    border-radius: 0;
    background-color: #000;
    color: #fff;
    font-weight: normal;
    letter-spacing: normal;
    text-transform: uppercase;
    cursor: pointer;
    font-size: 12px;

.filter-button-group button:hover,
.filter-button-group {
    color: #fff;
    background-color: #6799b2;

.filter-button-group button:focus {
    outline-style: none;
    outline-color: transparent;

That should be it!

Visit and check out your filterable portfolio on the frontend.

Need help implementing a tutorial in your site or want to hire me for custom work?


Find the article helpful and wish to donate?



For adding code blocks wrap the code in three backticks. Markdown should work.
Provide a URL of your site/webpage if something is not working.
  • Hi Sridhar, nice toturial but I have a problem – when I inspect portfolio site, there are 2 error:

    “Uncaught SyntaxError: Unexpected token <”

    in isotope.pkgd.min.js?ver=3.0.6

    “Uncaught TypeError: $(…).isotope is not a function
    at isotope-init.js?ver=1.0.0:4
    at isotope-init.js?ver=1.0.0:36”

    in isotope-init.js?ver=1.0.0

    Do you know what is that? I tested on Oxygen 2.2 beta

  • Hey, Tried to implement your tut using CPT and ACF, but I get the error:

    Warning: count(): Parameter must be an array or an object that implements Countable in /home/produktf/domains/ on line 110


    Would you mind sparing some time to try to get it working with CPT/ACF plugins?

  • magnifiercross
    linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram
    %d bloggers like this: