WPutopia

How to Build a Brand Page (Kadence Woo Extras – Product Brands)

Background:

  • We need a page that dynamically shows all Brands with their logos and links to their products
  • Brand is a custom post type
  • There are two. We are using the one kadence made but might be better method (please advise as best)
build a brand page in Kadence

Is is possible to create a page to show all the products brands with their logos/feature images and brand names? Is it possible to do it via Kadence blocks – portfolio or post grid, or by using shortcodes?

we need make a page with hundreds of brands and doing it manualy is disaster

It’s best to leverage the built-in “brand category” that is created by the Kadence woocommerce shop kit.

So I explored into the source code of that plugin and found out a solution.

Simply put the codes into your functions.php or any plugin like “code snippet” so to make the short code work.

After that, simply create a page that you want to show all the brads in the “brand category”.

Short code is

 [brands_list] 

It also has a pagination function: it loads 12 brads per page then paginated the rest.

Here’s the code to put into the functions.php

/**
 * Custom Brands Shortcode for WordPress
 * To use this shortcode, make sure to activate Kadence shop kit
 * 
 * Usage: [brands_list] or [brands_list columns="4" show_count="true" show_image="true"]
 * 
 * Requirements: 
 * - WooCommerce plugin must be active
 * - Kadence WooCommerce Extras (Shop Kit) plugin must be active
 * - Product brands feature must be enabled in Kadence settings
 */

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

/**
 * Check if all required plugins and features are available
 * 
 * @return array Array with 'status' (bool) and 'message' (string)
 */
function check_brands_requirements() {
    // Check if WooCommerce is active
    if (!class_exists('WooCommerce')) {
        return array(
            'status' => false,
            'message' => 'WooCommerce plugin is required but not active. Please install and activate WooCommerce.'
        );
    }
    
    // Check if Kadence WooCommerce Extras is active by checking for its constants or functions
    if (!defined('KADENCE_WOO_EXTRAS_VERSION') && !function_exists('init_kadence_woo_extras')) {
        return array(
            'status' => false,
            'message' => 'Kadence WooCommerce Extras (Shop Kit) plugin is required but not active. Please install and activate the plugin.'
        );
    }
    
    // Check if product brands feature is enabled
    $shopkit_settings = get_option('kt_woo_extras');
    if (!is_array($shopkit_settings)) {
        $shopkit_settings = json_decode($shopkit_settings, true);
    }
    
    if (empty($shopkit_settings['kt_product_brands_options'])) {
        return array(
            'status' => false,
            'message' => 'Product brands feature is not enabled in Kadence Shop Kit settings. Please enable it in WooCommerce > Shop Kit > Product Brands.'
        );
    }
    
    // Check if the product brands taxonomy exists
    if (!taxonomy_exists('product_brands')) {
        return array(
            'status' => false,
            'message' => 'Product brands taxonomy is not available. Please check your Kadence Shop Kit configuration.'
        );
    }
    
    return array(
        'status' => true,
        'message' => ''
    );
}

/**
 * Register the brands list shortcode
 */
function register_brands_list_shortcode() {
    add_shortcode('brands_list', 'display_brands_list_shortcode');
}
add_action('init', 'register_brands_list_shortcode');

/**
 * Display brands list shortcode
 * 
 * @param array $atts Shortcode attributes
 * @return string HTML output
 */
function display_brands_list_shortcode($atts) {
    // Check requirements first
    $requirements_check = check_brands_requirements();
    if (!$requirements_check['status']) {
        return '<div class="brands-error" style="padding: 15px; background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 4px; color: #856404; margin: 10px 0;"><strong>Brands Shortcode Error:</strong> ' . esc_html($requirements_check['message']) . '</div>';
    }
    
    // Default attributes
    $atts = shortcode_atts(array(
        'columns' => '3',           // Number of columns (1-6)
        'show_count' => 'true',     // Show product count
        'show_image' => 'true',     // Show brand image/logo
        'image_size' => 'medium',   // Image size (thumbnail, medium, large, full)
        'hide_empty' => 'true',     // Hide brands with no products
        'orderby' => 'name',        // Order by (name, count, slug, term_group)
        'order' => 'ASC',           // Order direction (ASC, DESC)
        'limit' => '',              // Limit number of brands (empty for all)
        'class' => '',              // Additional CSS classes
        'per_page' => '12',         // Number of brands per page
        'show_pagination' => 'true', // Show pagination navigation
    ), $atts, 'brands_list');

    // Get current page number
    $current_page = 1;
    if (isset($_GET['brands_page']) && is_numeric($_GET['brands_page'])) {
        $current_page = max(1, intval($_GET['brands_page']));
    }
    
    // Calculate pagination
    $per_page = intval($atts['per_page']);
    $offset = ($current_page - 1) * $per_page;
    
    // Prepare query arguments for counting total brands
    $count_args = array(
        'taxonomy' => 'product_brands',
        'hide_empty' => ($atts['hide_empty'] === 'true'),
        'fields' => 'count',
    );
    
    // Get total count
    $total_brands = get_terms($count_args);
    $total_pages = ceil($total_brands / $per_page);
    
    // Prepare query arguments for actual brands
    $args = array(
        'taxonomy' => 'product_brands',
        'hide_empty' => ($atts['hide_empty'] === 'true'),
        'orderby' => $atts['orderby'],
        'order' => $atts['order'],
        'number' => $per_page,
        'offset' => $offset,
    );

    // Override with limit if specified (takes precedence over pagination)
    if (!empty($atts['limit']) && is_numeric($atts['limit'])) {
        $args['number'] = intval($atts['limit']);
        unset($args['offset']);
        $atts['show_pagination'] = 'false'; // Disable pagination when limit is used
    }

    // Get brand terms
    $brands = get_terms($args);

    if (is_wp_error($brands) || empty($brands)) {
        return '<p>No brands found.</p>';
    }

    // Start building output
    $columns = max(1, min(6, intval($atts['columns'])));
    $additional_class = !empty($atts['class']) ? ' ' . esc_attr($atts['class']) : '';
    
    $output = '<div class="brands-list-container' . $additional_class . '">';
    $output .= '<div class="brands-grid brands-columns-' . $columns . '">';

    foreach ($brands as $brand) {
        $brand_link = get_term_link($brand);
        $brand_image = '';
        $product_count = $brand->count;
        
        // Get brand image if enabled
        if ($atts['show_image'] === 'true') {
            $image_id = get_term_meta($brand->term_id, '_kt_woo_extras_brand_image', true);
            if (!empty($image_id) && is_array($image_id) && isset($image_id[0])) {
                $image_url = wp_get_attachment_image_url($image_id[0], $atts['image_size']);
                if ($image_url) {
                    $brand_image = '<div class="brand-image"><img src="' . esc_url($image_url) . '" alt="' . esc_attr($brand->name) . '" /></div>';
                }
            }
        }

        // Build brand item HTML
        $output .= '<div class="brand-item">';
        $output .= '<a href="' . esc_url($brand_link) . '" class="brand-link">';
        
        if (!empty($brand_image)) {
            $output .= $brand_image;
        }
        
        $output .= '<div class="brand-info">';
        $output .= '<h3 class="brand-name">' . esc_html($brand->name) . '</h3>';
        
        if (!empty($brand->description)) {
            $output .= '<p class="brand-description">' . esc_html($brand->description) . '</p>';
        }
        
        if ($atts['show_count'] === 'true' && $product_count > 0) {
            $output .= '<span class="brand-count">(' . $product_count . ' ' . _n('product', 'products', $product_count, 'textdomain') . ')</span>';
        }
        
        $output .= '</div>'; // .brand-info
        $output .= '</a>'; // .brand-link
        $output .= '</div>'; // .brand-item
    }

    $output .= '</div>'; // .brands-grid
    
    // Add pagination if enabled and there are multiple pages
    if ($atts['show_pagination'] === 'true' && $total_pages > 1) {
        $output .= '<div class="brands-pagination">';
        
        // Get current URL without brands_page parameter
        $current_url = remove_query_arg('brands_page');
        
        // Previous page link
        if ($current_page > 1) {
            $prev_url = add_query_arg('brands_page', $current_page - 1, $current_url);
            $output .= '<a href="' . esc_url($prev_url) . '" class="brands-pagination-prev">&laquo; Previous</a>';
        } else {
            $output .= '<span class="brands-pagination-prev disabled">&laquo; Previous</span>';
        }
        
        // Page numbers
        $output .= '<span class="brands-pagination-info">';
        
        // Show page numbers (with ellipsis for large page counts)
        $start_page = max(1, $current_page - 2);
        $end_page = min($total_pages, $current_page + 2);
        
        if ($start_page > 1) {
            $first_url = add_query_arg('brands_page', 1, $current_url);
            $output .= '<a href="' . esc_url($first_url) . '" class="brands-pagination-number">1</a>';
            if ($start_page > 2) {
                $output .= '<span class="brands-pagination-ellipsis">...</span>';
            }
        }
        
        for ($i = $start_page; $i <= $end_page; $i++) {
            if ($i == $current_page) {
                $output .= '<span class="brands-pagination-number current">' . $i . '</span>';
            } else {
                $page_url = add_query_arg('brands_page', $i, $current_url);
                $output .= '<a href="' . esc_url($page_url) . '" class="brands-pagination-number">' . $i . '</a>';
            }
        }
        
        if ($end_page < $total_pages) {
            if ($end_page < $total_pages - 1) {
                $output .= '<span class="brands-pagination-ellipsis">...</span>';
            }
            $last_url = add_query_arg('brands_page', $total_pages, $current_url);
            $output .= '<a href="' . esc_url($last_url) . '" class="brands-pagination-number">' . $total_pages . '</a>';
        }
        
        $output .= '</span>';
        
        // Next page link
        if ($current_page < $total_pages) {
            $next_url = add_query_arg('brands_page', $current_page + 1, $current_url);
            $output .= '<a href="' . esc_url($next_url) . '" class="brands-pagination-next">Next &raquo;</a>';
        } else {
            $output .= '<span class="brands-pagination-next disabled">Next &raquo;</span>';
        }
        
        $output .= '</div>'; // .brands-pagination
    }
    
    $output .= '</div>'; // .brands-list-container

    return $output;
}

/**
 * Add CSS styles for the brands shortcode
 */
function brands_list_shortcode_styles() {
    if (has_shortcode(get_post()->post_content, 'brands_list') || is_admin()) {
        ?>
        <style type="text/css">
        .brands-list-container {
            margin: 20px 0;
        }
        
        .brands-grid {
            display: grid;
            gap: 20px;
            margin-bottom: 20px;
        }
        
        .brands-columns-1 { grid-template-columns: 1fr; }
        .brands-columns-2 { grid-template-columns: repeat(2, 1fr); }
        .brands-columns-3 { grid-template-columns: repeat(3, 1fr); }
        .brands-columns-4 { grid-template-columns: repeat(4, 1fr); }
        .brands-columns-5 { grid-template-columns: repeat(5, 1fr); }
        .brands-columns-6 { grid-template-columns: repeat(6, 1fr); }
        
        @media (max-width: 768px) {
            .brands-columns-3,
            .brands-columns-4,
            .brands-columns-5,
            .brands-columns-6 {
                grid-template-columns: repeat(2, 1fr);
            }
        }
        
        @media (max-width: 480px) {
            .brands-grid {
                grid-template-columns: 1fr !important;
            }
        }
        
        .brand-item {
            border: 1px solid #e0e0e0;
            border-radius: 8px;
            overflow: hidden;
            transition: transform 0.3s ease, box-shadow 0.3s ease;
            background: #fff;
        }
        
        .brand-item:hover {
            transform: translateY(-5px);
            box-shadow: 0 5px 15px rgba(0,0,0,0.1);
        }
        
        .brand-link {
            display: block;
            text-decoration: none;
            color: inherit;
            height: 100%;
        }
        
        .brand-image {
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 20px;
            background: #f9f9f9;
            min-height: 160px;
        }
        
        .brand-image img {
            max-width: 100%;
            height: auto;
            max-height: 120px;
            object-fit: contain;
        }
        
        .brand-info {
            padding: 15px;
            text-align: center;
        }
        
        .brand-name {
            margin: 0 0 10px 0;
            font-size: 18px;
            font-weight: 600;
            color: #333;
        }
        
        .brand-description {
            margin: 0 0 10px 0;
            font-size: 14px;
            font-weight: 400;
            color: #666;
            line-height: 1.4;
        }
        
        .brand-count {
            font-size: 12px;
            color: #999;
            font-style: italic;
        }
        
        /* Alternative list style */
        .brands-list-style .brands-grid {
            display: block;
        }
        
        .brands-list-style .brand-item {
            display: flex;
            align-items: center;
            margin-bottom: 15px;
            padding: 15px;
        }
        
        .brands-list-style .brand-image {
            flex: 0 0 80px;
            margin-right: 15px;
            padding: 10px;
        }
        
        .brands-list-style .brand-image img {
            max-height: 60px;
        }
        
        .brands-list-style .brand-info {
            flex: 1;
            text-align: left;
            padding: 0;
        }
        
        /* Pagination Styles */
        .brands-pagination {
            display: flex;
            justify-content: center;
            align-items: center;
            margin-top: 30px;
            padding: 20px 0;
            gap: 10px;
            flex-wrap: wrap;
        }
        
        .brands-pagination a,
        .brands-pagination span {
            display: inline-block;
            padding: 8px 12px;
            text-decoration: none;
            border: 1px solid #ddd;
            border-radius: 4px;
            color: #333;
            background: #fff;
            transition: all 0.3s ease;
            font-size: 14px;
            line-height: 1;
        }
        
        .brands-pagination a:hover {
            background: #f5f5f5;
            border-color: #999;
            color: #000;
        }
        
        .brands-pagination .current {
            background: #0073aa;
            color: #fff;
            border-color: #0073aa;
            font-weight: bold;
        }
        
        .brands-pagination .disabled {
            color: #999;
            background: #f9f9f9;
            border-color: #e0e0e0;
            cursor: not-allowed;
        }
        
        .brands-pagination-info {
            display: flex;
            align-items: center;
            gap: 5px;
        }
        
        .brands-pagination-ellipsis {
            padding: 8px 4px;
            border: none;
            background: none;
            color: #666;
        }
        
        .brands-pagination-prev,
        .brands-pagination-next {
            font-weight: 500;
        }
        
        @media (max-width: 480px) {
            .brands-pagination {
                gap: 5px;
            }
            
            .brands-pagination a,
            .brands-pagination span {
                padding: 6px 8px;
                font-size: 12px;
            }
            
            .brands-pagination-prev,
            .brands-pagination-next {
                padding: 6px 10px;
            }
        }
        </style>
        <?php
    }
}
add_action('wp_head', 'brands_list_shortcode_styles');

/**
 * Alternative shortcode for simple brand links list
 */
function display_brands_links_shortcode($atts) {
    // Check requirements first
    $requirements_check = check_brands_requirements();
    if (!$requirements_check['status']) {
        return '<div class="brands-error" style="padding: 15px; background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 4px; color: #856404; margin: 10px 0;"><strong>Brands Shortcode Error:</strong> ' . esc_html($requirements_check['message']) . '</div>';
    }
    
    $atts = shortcode_atts(array(
        'separator' => ' | ',
        'show_count' => 'false',
        'hide_empty' => 'true',
        'orderby' => 'name',
        'order' => 'ASC',
        'limit' => '',
    ), $atts, 'brands_links');

    $args = array(
        'taxonomy' => 'product_brands',
        'hide_empty' => ($atts['hide_empty'] === 'true'),
        'orderby' => $atts['orderby'],
        'order' => $atts['order'],
    );

    if (!empty($atts['limit']) && is_numeric($atts['limit'])) {
        $args['number'] = intval($atts['limit']);
    }

    $brands = get_terms($args);

    if (is_wp_error($brands) || empty($brands)) {
        return '<p>No brands found.</p>';
    }

    $links = array();
    foreach ($brands as $brand) {
        $brand_link = get_term_link($brand);
        $link_text = $brand->name;
        
        if ($atts['show_count'] === 'true' && $brand->count > 0) {
            $link_text .= ' (' . $brand->count . ')';
        }
        
        $links[] = '<a href="' . esc_url($brand_link) . '">' . esc_html($link_text) . '</a>';
    }

    return '<div class="brands-links">' . implode($atts['separator'], $links) . '</div>';
}
add_shortcode('brands_links', 'display_brands_links_shortcode');

/**
 * Register shortcode in Gutenberg
 */
function register_brands_shortcode_block() {
    if (function_exists('register_block_type')) {
        wp_register_script(
            'brands-shortcode-block',
            false,
            array('wp-blocks', 'wp-element', 'wp-editor'),
            '1.0.0',
            true
        );
        
        wp_add_inline_script('brands-shortcode-block', '
            (function(blocks, element, editor) {
                var el = element.createElement;
                var RichText = editor.RichText;
                
                blocks.registerBlockType("custom/brands-shortcode", {
                    title: "Brands List",
                    icon: "tag",
                    category: "widgets",
                    
                    edit: function(props) {
                        return el("div", {
                            className: "brands-shortcode-placeholder",
                            style: { padding: "20px", border: "1px dashed #ccc", textAlign: "center" }
                        }, "[brands_list] - Brands will display on frontend");
                    },
                    
                    save: function(props) {
                        return el("div", {}, "[brands_list]");
                    }
                });
            })(window.wp.blocks, window.wp.element, window.wp.editor);
        ');
    }
}
add_action('enqueue_block_editor_assets', 'register_brands_shortcode_block');

/**
 * Display admin notice if requirements are not met
 */
function brands_shortcode_admin_notice() {
    // Only show to administrators
    if (!current_user_can('manage_options')) {
        return;
    }
    
    $requirements_check = check_brands_requirements();
    if (!$requirements_check['status']) {
        echo '<div class="notice notice-warning is-dismissible">';
        echo '<p><strong>Brands Shortcode:</strong> ' . esc_html($requirements_check['message']) . '</p>';
        echo '</div>';
    }
}
add_action('admin_notices', 'brands_shortcode_admin_notice');

/**
 * Add safety check for function existence to prevent conflicts
 */
if (!function_exists('check_brands_requirements')) {
    /**
     * Fallback function if somehow the main function doesn't exist
     */
    function check_brands_requirements_fallback() {
        return 'Brands shortcode functions are not properly loaded.';
    }
}

/**
 * Deactivation cleanup (optional)
 */
function brands_shortcode_deactivation_cleanup() {
    // Clear any cached data if needed
    delete_transient('brands_list_cache');
}
// Uncomment the line below if you convert this to a plugin
// register_deactivation_hook(__FILE__, 'brands_shortcode_deactivation_cleanup');

Support My Work

If you enjoy my content, consider buying me a coffee or shopping through my Rakuten link to support me!

Victor

Founder of WPUtopia.com🕵️I would appreciate it if you could leave me a comment!

Send Message

Chat with me

Start a Conversation

Hi! Let's connect on your preferred platform.