Dynamic grid with filters by categories


Hello, Im working on this website : http://cozy.webstantly.com/recipes/. And i'm trying to have a dynamic grid with filter by categories. This is the markup from uikit:

<!-- Filter Controls -->
<ul id="my-id" class="uk-subnav">
    <li data-uk-filter=""><a href=""></a></li>
    <li data-uk-filter="filter-a"><a href=""></a></li>
    <li data-uk-filter="filter-b"><a href=""></a></li>
</ul>

<!-- Dynamic Grid -->
<div data-uk-grid="{controls: '#my-id'}">
    <div data-uk-filter="filter-a">...</div>
    <div data-uk-filter="filter-b">...</div>
    <div data-uk-filter="filter-a,filter-b">...</div>
</div>

So from there i have done that:

// Display posts in a responsive dynamic grid.
add_action( 'wp', 'wst_posts_grid' );

function wst_posts_grid() {

  // Only apply to posts page.
  if ( ! is_home() ) {
    return;
 }

 //filters
 beans_add_smart_action( 'beans_content_before_markup', 'wst_display_grid_filter' );
 function wst_display_grid_filter() {
    $categories = wst_get_categories();
//   d($categories);
   ?>
    <ul id="grid-filter"
        class="uk-subnav uk-container-center">
      <?php
     foreach ( $categories as $category ) {
        $filter      = $category->name;
       $filter_slug = $category->slug;
       ?>
        <li data-uk-filter="<?php echo $filter_slug; ?>"><a href=""><?php echo $filter; ?></a></li>
     <?php } ?>
    </ul>
 <?php }

 function wst_get_categories() {
   return get_categories( array(
     'parent' => 0,
    ) );

  }

 // Add grid.
  beans_wrap_inner_markup( 'beans_content', 'beans_child_posts_grid', 'div', array(
   'data-uk-grid' => "{gutter: 20, controls: '#grid-filter'}"
  ) );
  beans_wrap_markup( 'beans_post', 'beans_child_post_grid_column', 'div', array(
    'class' => 'uk-width-large-1-3 uk-width-medium-1-2'
 ) );

  global $post;
 $post_categories = get_the_category( $post->ID );
 $filters[]       = array( $post_categories->slug );
 $filters         = implode( ',', $filters );

  foreach ( $post as $item ) {

    beans_add_attribute( 'beans_post', 'data-uk-filter', $filters );
  }

 // Move the posts pagination after the new grid markup.
 beans_modify_action_hook( 'beans_posts_pagination', 'beans_child_posts_grid_after_markup' );

}

The filters menu is displayed, but this is the problematic part

  global $post;
 $post_categories = get_the_category( $post->ID );
 $filters[]       = array( $post_categories->slug );
 $filters         = implode( ',', $filters );

  foreach ( $post as $item ) {

    beans_add_attribute( 'beans_post', 'data-uk-filter', $filters );
  }

I don't find how to display the categories as data-uk-filter to each post I think i'm not very far, but i am seraching and searching, and need a little help now 🙂


Hey Alex,

The issue here is that beans_add_attribute( 'beans_post', 'data-uk-filter', $filters ); is called in wp (globally) in your example and not in the post loop. To assign a dynamic attribute using the post data the you need to use a callback which will be called in the loop. Likely Beans as a filter {$markup_id}_attributes which filter each markup (with markup ID) attributes.

So in your case here is the snippet you are looking for:

add_filter( 'beans_post_attributes', 'example_post_attributes' );

function example_post_attributes( $attributes ) {

  // Get the categories and build and array with its slugs.
 $categories = wp_list_pluck( get_the_category( get_the_ID() ), 'slug' );

  return array_merge( $attributes, array(
   'data-uk-filter' => implode( ',', (array) $categories ) // automatically escaped.
 ) );

}

Hope that helps,


Thank you Thierry, yes it works in the sense that the attributes are there, and all my code seems to be as it is shown on uikit, but unfortunately the filters don't work : http://cozy.webstantly.com/recipes/ i don't know where is my mistake


Hey Alex, I see that you added the filters to the `` and not the grid div which is the causing the issue.

Replace your filter from beans_post_attributes to beans_child_post_grid_column_attributes.

Thanks,


Thank you Thierry ! It works now 🙂


hi Alex, This is Ramesh. I am also trying to do it for the same. but no luck. I dont know where i made mistake. Can you help me with your corrected code?


Hi Ramesh,

Here is a working complete snippet that you can use in your child theme functions.php:

// Enqueue UIkit assets.
add_action( 'beans_uikit_enqueue_scripts', 'example_enqueue_uikit_assets' );

function example_enqueue_uikit_assets() {

 beans_uikit_enqueue_components( array( 'grid' ), 'add-ons' );

}

// Display posts in a responsive dynamic grid.
add_action( 'wp', 'example_posts_grid' );

function example_posts_grid() {

  // Only apply to posts page.
  if ( ! is_home() ) {
    return;
 }

 // Add grid.
  beans_wrap_inner_markup( 'beans_content', 'example_posts_grid', 'div', array(
   'data-uk-grid' => "{gutter: 20, controls: '#tm-grid-filter'}",
  ) );
  beans_wrap_markup( 'beans_post', 'example_post_grid_column', 'div', array(
    'class' => 'uk-width-large-1-3 uk-width-medium-1-2',
  ) );

  // Move the posts pagination after the new grid markup.
 beans_modify_action_hook( 'beans_posts_pagination', 'example_posts_grid_after_markup' );

}

// Add posts filter.
add_action( 'beans_content_before_markup', 'example_posts_filter' );

function example_posts_filter() {

  $categories = get_categories( array(
    'parent' => 0,
  ) );

  ?>
  <ul id="tm-grid-filter" class="uk-subnav uk-container-center">
    <?php foreach ( $categories as $category ) : ?>
     <li data-uk-filter="<?php echo esc_attr( $category->slug ); ?>">
        <a href="#"><?php echo esc_attr( $category->name ); ?></a>
      </li>
   <?php endforeach; ?>
  </ul>
 <?php
}

// Add filter data to each post.
add_filter( 'example_post_grid_column_attributes', 'example_post_attributes' );

function example_post_attributes( $attributes ) {

  // Get the categories and build and array with its slugs.
 $categories = wp_list_pluck( get_the_category( get_the_ID() ), 'slug' );

  return array_merge( $attributes, array(
   'data-uk-filter' => implode( ',', (array) $categories ), // automatically escaped.
  ) );

}

Since the snippet is quite long and we ideally don't want to "polute" the child theme functions.php, it is a great opportunity to use a page template. Since we assume that these codes are only for the blog home, you are going to add a home.php (one of the automatically recognized WordPress Core Template File) file in your child theme which will contain the following code:

<?php

// Enqueue UIkit assets.
add_action( 'beans_uikit_enqueue_scripts', 'example_enqueue_uikit_assets' );

function example_enqueue_uikit_assets() {

 beans_uikit_enqueue_components( array( 'grid' ), 'add-ons' );

}

// Display posts in a responsive dynamic grid.
add_action( 'beans_before_load_document', 'example_posts_grid' );

function example_posts_grid() {

  // Add grid.
  beans_wrap_inner_markup( 'beans_content', 'example_posts_grid', 'div', array(
   'data-uk-grid' => "{gutter: 20, controls: '#tm-grid-filter'}",
  ) );
  beans_wrap_markup( 'beans_post', 'example_post_grid_column', 'div', array(
    'class' => 'uk-width-large-1-3 uk-width-medium-1-2',
  ) );

  // Move the posts pagination after the new grid markup.
 beans_modify_action_hook( 'beans_posts_pagination', 'example_posts_grid_after_markup' );

}

// Add posts filter.
add_action( 'beans_content_before_markup', 'example_posts_filter' );

function example_posts_filter() {

  $categories = get_categories( array(
    'parent' => 0,
  ) );

  ?>
  <ul id="tm-grid-filter" class="uk-subnav uk-container-center">
    <?php foreach ( $categories as $category ) : ?>
     <li data-uk-filter="<?php echo esc_attr( $category->slug ); ?>">
        <a href="#"><?php echo esc_attr( $category->name ); ?></a>
      </li>
   <?php endforeach; ?>
  </ul>
 <?php
}

// Add filter data to each post.
add_filter( 'example_post_grid_column_attributes', 'example_post_attributes' );

function example_post_attributes( $attributes ) {

  // Get the categories and build and array with its slugs.
 $categories = wp_list_pluck( get_the_category( get_the_ID() ), 'slug' );

  return array_merge( $attributes, array(
   'data-uk-filter' => implode( ',', (array) $categories ), // automatically escaped.
  ) );

}

// Load the document which is always needed at the bottom of template files.
beans_load_document();

Note the differences:

  1. The wp action becomes beans_before_load_document.
  2. We can remove the is_home() check in example_posts_grid() since we know this template file only applies to the blog home.
  3. We call beans_load_document() at the bottom of the file which is always needed at the bottom of template files.

One last thing, this snippet doesn't handle pagination which may be an issue when you filter depending on the number of posts. This is something that you need to handle via ajax or reload if you need it.

Happy coding,


Thanks a lot Thierry.. I will try it now..


Hi Ramesh, sorry, Thierry answered before me, let me know if you need something more...


Hi Alex,

Thanks a lot for showing interest to resove my issue. the above code is working fine. But i have few issues:

  • In front blog page, If i click dynamic category header which shows only one post in a page.
  • When i click next page in pagination, it is not shown the selected dynamic category, however it shows all the category posts unnecessarily.

Any idea how to resolve it Alex?


Hi Ramesh, i don't know exactly what is your issue, bit if you like i can share the child theme i used to build that : http://cozy.webstantly.com/recipes/ (in this version we have infinite scroll, because the client wanted that, but it doesn'wt work very well with the animation, in the local version it is with pagination, and we managed to make the filter work with pagination) send me your email if you want me to send you the child


That is great help Alex. Thanks a lot again.. rameshkmscct@gmai.com.. I seen your client site. It is very nice.


For animation effects, try to add like below code which works fine for me.

// Add grid.
beans_wrap_inner_markup( 'beans_content', 'beans_child_posts_grid', 'div', array(
'data-uk-grid' => "{gutter: 20, controls: '#tm-grid-filter'}"
) );
beans_wrap_markup( 'beans_post', 'beans_child_post_grid_column', 'div', array(
'class' => 'uk-width-large-1-3 uk-width-medium-1-2 uk-animation-scale-up'
) );

Here it is on bitbucket https://bitbucket.org/alexadark/cozy/, the child theme and core functionalities plugin which includes shortcodes, custom fields with carbon fields i don't remember everything as i am working on other things now, but will come back to these theme to reuse things

this site is nice, and i had my worst client, who because of ego decided to not use my work and go with another dev (my worst client story, and fortunately the only one !) i am also preparing comercial themes, i would be happy to exchange with you about this this is my email: alexaspalato@gmail.com First i am finishing my own site on beans too !


Hi Alex,

I dont know how to tell thank you. It is not easy to share our hard works just like that. But you did it. hatsoff. I will check it.

I am also facing worst client stories, yes in my case it's many. Happy to here that you are preparing for the commecial themes using beans. All the best for your successfull business based on this.


I'm always happy to share, i am also preparing a blog part on my site to publish tutorials feel free to email me 🙂


Dynamic filter grid is so cool. 🙂 I use it on my project, but I stuck when comes to dependent filters. I'm working on a wine catalog, and for this i used my own taxonomy (used in custom post type).

Structure of wine catalog looks like this:

  1. Country:
    • Portugal
    • Catalan
    • French
  2. Color:
    • Red
    • White
    • Pink

And when I click on Portugal, then Red, I want to show Portugal Red wines. To achieve this I need to add two strings into data-uk-filter separated by coma like this "portugal, red"...

I'm wondering if there is elegant and efficient way to do this without using jQuery by saving "clicked" elements in an array and then passing them into data-uk-filter.

Here's snippet I have:

function posts_filter() {
    $taxonomy_name = 'wine_category';
    $taxonomy = get_terms( $taxonomy_name, array( 'parent' => 0 ) );
    ?>
    <div class="uk-grid">
    
    // First loop, takes care of displaying parent ellements
        <?php foreach ( $taxonomy as $term_parent ) : ?>
            <div class="uk-width-1-2">
                <h3><?php echo esc_attr( $term_parent->name ); ?></h3>
                <?php
                $terms = get_terms( $taxonomy_name, array( 'parent' => $term_parent->term_id, 'orderby' => 'slug', 'hide_empty' => false ) );
                ?>
                <ul id="tm-grid-filter" class="uk-subnav uk-container-center uk-margin-large-bottom">
                
                // Second loop takes care of children terms
                    <?php foreach ( $terms as $term ) :
                        ?>
                        <li data-uk-filter="<?php echo esc_attr( $term->slug ); ?>">
                            <a href="#"><?php echo esc_attr( $term->name ); ?></a>
                        </li>
                    <?php endforeach; ?>
                </ul>
            </div>
        <?php endforeach; ?>
    </div>
    <?php
}

Hey Mariusz,

Glad to hear you are making good use of the dynamic grid. I don't see any other way to have multiple filters the way you want it. So I'd say extending it using JS is perfectly acceptable in this case 🙂

Have fun,


Hi Mariusz, Here you have an example of a grid with several filters https://uikitplay.com/plays/FXsJ i have not tried that for the moment, but i believe it can help ! uikitplay is a good resource !


Thank You Thierry, I think this is what I wanted to hear 😉

And also thanks a lot Alexandra! 🙂 I didn't know this resource, it's really good.

  • 1
  • 2

Write a reply

Login or register to write a reply, it's free!