Filter Custom Post Type by category on Category Page

Hi,
/shop/ is using page-shop.php template
/shop/rings is using archive.php template, and it should load only load Custom Post Type: 'products', and filter by getting category from url (rings, necklaces...)

I have tried but I don't get it... Any idea? Thanks :slight_smile:

  • Raul
    • WPMU DEV Initiate

    Hi Ash!
    I would implement foxy.io so I have to build my own page system.

    /shop/ is working well, it shows all Custom Posty Type: Products

    issue----> /shop/rings/ should filter by "rings" category (check archive.php)

  • Ash
    • WordPress Hacker

    Hello Raul

    This would be tough and need some custom development work. WooCommerce doesn't recommend to remove that part "product-category" from the permalink. You can check here: https://docs.woocommerce.com/document/removing-product-product-category-or-shop-from-the-urls/

    If you still want to remove, there are two ways:
    1. You need to use add_rewrite_rule to write new rule for the new URL structure: https://codex.wordpress.org/Rewrite_API/add_rewrite_rule
    2. You can create a child page under shop, called "ring". Then use shortcode to show the product from ring category in that page. But this way, you have to create pages for all categories manually.

    If you want, I can move your thread to Web Development & Coding category of the members forum where more members can chime in with more suggestions. Let me know if you want me to move.

    Have a nice day!

    Cheers,
    Ash

  • Ash
    • WordPress Hacker

    Still, you will need a rewrite rule using add_rewrite_rule to create new rule. The rule should be for /shop/{any character followed by number}

    And then you can use get_query_var to get the variable after /shop/ and show the products of that category programmatically: https://codex.wordpress.org/Function_Reference/get_query_var

    I am not familiar with Foxy.io so I am not sure how the products are populated or queried :slight_frown:

  • Konstantinos Xenos
    • Rubber Duck Debugger

    Hi Raul ,

    One easier way doing it basically within the admin without creating re-writes of URLs and giving you the extra step of being able to select multiple different templates as well, would be to actually create Pages for each category you want.

    As an example you could:

    Make a Page with a slug "shop" and create each of your categories as children pages of Shop ( for example another page with slug "rings", this will unlock basically all of themes settings for your templates as well if you need them since we're talking about pages now and not simple archives.

    Your URLs should now look like "www.example.com/shop/rings" when you visit the rings Page.

    In your .php you can easily grab the category now by doing something like this ( I'll provide a code for a custom post type of "products" that uses a custom taxonomy called "product-categories" and it has a category named "rings" but you can alter this to fit your foxy.io settings & loop ).

    I don't know if you're actually importing products from foxy.io or just doing queries on it straight away but the code following is just a WP native example to easily use basename() and get the last item from the url as a category name.

    I hope this helps a bit as an idea so you can more easily utilize your theme styles etc ( you might want different for each category for example :slight_smile: ).

    <?php
    // find last word from URL ( this will basically give you "rings" )
    $cat = basename( parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH ) );
    
    // the query
    $args = array(
    	'post_type'      => 'products',
    	'posts_per_page' => -1,
    	'orderby'        => 'DATE',
    	'order'          => 'ASC',
    	'tax_query'      => array(
    		array(
    			'taxonomy' => 'product-categories',
    			'field'    => 'slug',
    			'terms'    => esc_attr( $cat ),
    		),
    	),
    );
    
    // query results
    $the_query = new WP_Query( $args );
    
    // display results
    if ( $the_query->have_posts() ) {
    	while ( $the_query->have_posts() ) {
    		$the_query->the_post();
    		echo '<h2>' . get_the_title() . '</h2>';
    	}
    	// reset post
    	wp_reset_postdata();
    }
    ?>

    Regards,
    Konstantinos

    • Raul
      • WPMU DEV Initiate

      Konstantinos that worked! Thanks a lot!
      I got a little extra question:

      Both the general shop page (/shop/) and category page (the one you help me /shop/rings/) I have a sidebar that is common for both, and I am not able to make a .current class on li ('All' in Shop, and the one on category). Could you help me please?

      <div class="sidebar">
        <div class="vertical-center">
          <ul id="colections" class="filters-button-group">
            <li><a href="/shop/">shop (0)</a></li>
            <li><a href="/shop/">all</a></li>
            <?php
              $args = array(
              'current_category' => 1,
              'orderby' => 'count',
              'order' => 'DESC',
              'exclude' => '1',
              );
      
              $categories = get_categories($args);
              foreach($categories as $category) {
                echo '<li><a href="/shop/' . $category->slug . '/">' . $category->name.'</a></li>';
                }
            ?>
            <li><a href="#">check out</a></li>
          </ul>
        </div>
      </div>
      • Konstantinos Xenos
        • Rubber Duck Debugger

        Ah I see that you also created categories. Hm no idea if there's an easier way for you since I don't know the whole context ( there might be but it's hard to guess ).

        In any case you could still use the basename to find the slug again so your custom menu could become something like this.

        <ul id="colections" class="filters-button-group">
        	<?php
        	$cat    = basename( parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH ) );
        	$classy = '';
        	if ( 'shop' === $cat ) {
        		$classy = ' current';
        	}
        	?>
        	<li><a href="/shop/">shop (0)</a></li>
        	<li class="<?php echo $classy; ?>"><a href="/shop/">all</a></li>
        	<?php
        	$args = array(
        		'current_category' => 1,
        		'orderby'          => 'count',
        		'order'            => 'DESC',
        		'exclude'          => '1',
        		'hide_empty'       => 0,
        	);
        
        	$categories = get_categories( $args );
        	foreach ( $categories as $category ) {
        		$classy = '';
        		if ( $cat === $category->slug ) {
        			$classy = ' current';
        		}
        		echo '<li class="' . $classy . '"><a href="/shop/' . $category->slug . '/">' . $category->name . '</a></li>';
        	}
        	?>
        	<li><a href="#">check out</a></li>
        </ul>

        Note I also added 'hide_empty' => 0, so your list shows the empty categories as well plus, I've added 2 class checks so /shop/ and /rings/ etc will ad the class .current to your

      • items.

        I hope this helps ( and that I understood correctly what you wanted as I got a bit confused of why you created categories as well ).

        Best regards,
        Konstantinos

        • Raul
          • WPMU DEV Initiate

          Hey Konstantinos Xenos,
          may I ask you another related question?

          I am proceding with WPML site translation, both english and spanish, and the sidebar we creates works fine, but on the secundary language (lang=es) is not creating the full slug, example:

          - /shop/rings/ (OK in english)
          - /shop/anillos/ should be /shop/anillos/?lang=es

          Any idea how to add that /?lang=es to sidebar links in case of being on spanish?

          <div class="sidebar">
            <div class="vertical-center">
              <ul id="colections" class="filters-button-group">
          	<?php
          	$cat    = basename( parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH ) );
          	$classy = '';
          	if ( 'shop' === $cat ) {
          		$classy = 'current';
          	}
          	?>
          	<li><a href="/shop/">shop (0)</a></li>
          	<li class="<?php echo $classy; ?>"><a href="/shop/">all</a></li>
          	<?php
          	$args = array(
          		'current_category' => 1,
          		'orderby'          => 'count',
          		'order'            => 'DESC',
          		'exclude'          => '1',
          		'hide_empty'       => 0,
          	);
          
          	$categories = get_categories( $args );
          	foreach ( $categories as $category ) {
          		$classy = '';
          		if ( $cat === $category->slug ) {
          			$classy = ' current';
          		}
          		echo '<li class="' . $classy . '"><a href="/shop/' . $category->slug . '/">' . $category->name . '</a></li>';
          	}
          	?>
          	<li><a href="#">check out</a></li>
          </ul>
            </div>
          </div>
  • Ash
    • WordPress Hacker

    Hello Raul

    Please try the following code:

    <div class="sidebar">
      <div class="vertical-center">
        <ul id="colections" class="filters-button-group">
    	<?php
    	$cat    = basename( parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH ) );
    	$classy = '';
    	if ( 'shop' === $cat ) {
    		$classy = 'current';
    	}
    	?>
    	<li><a href="/shop/">shop (0)</a></li>
    	<li class="<?php echo $classy; ?>"><a href="/shop/">all</a></li>
    	<?php
    	$args = array(
    		'current_category' => 1,
    		'orderby'          => 'count',
    		'order'            => 'DESC',
    		'exclude'          => '1',
    		'hide_empty'       => 0,
    	);
    
    	$categories = get_categories( $args );
    	foreach ( $categories as $category ) {
    		$classy = '';
    		if ( $cat === $category->slug ) {
    			$classy = ' current';
    		}
    
    		$lang = defined( 'ICL_LANGUAGE_CODE' ) && ICL_LANGUAGE_CODE ? ICL_LANGUAGE_CODE : '';
    
    		echo '<li class="' . $classy . '"><a href="/shop/' . $category->slug . '/?lang=' . $lang . '">' . $category->name . '</a></li>';
    	}
    	?>
    	<li><a href="#">check out</a></li>
    </ul>
      </div>
    </div>

    Let us know if that works. Have a nice day!

    Cheers,
    Ash

Thank NAME, for their help.

Let NAME know exactly why they deserved these points.

Gift a custom amount of points.