Skip to content

Conversation

@crftwrk
Copy link
Member

@crftwrk crftwrk commented Sep 20, 2024

This PR adds numerous filters and introduces actions. All changes are additions and do not affect overridden template files in the child theme.

Motivation & context

I'm currently working on two themes that I want to deeply customize without overriding any template files. Everything is achieved using filters/actions and a bit of additional CSS/JS.

Both themes are a work in progress but demonstrate how these filters and actions can be used and have the same sample content. Pay special attention to:

Header

There is an additional static header that changes when scrolling. The Fashion theme includes an extra scrolling menu, and the main menu is placed inside the burger button on all screen sizes. All button and widget positions have been adjusted, and Fashion has a dedicated mobile logo.

Breadcrumb

The default and WC breadcrumbs are now unified instead of having two (similar-looking) separate ones. Both use the same filters.

  • Unfortunately, I had to copy the WC breadcrumb.php file to the theme to add the filter, but I’m fine with maintaining this file.
  • The WC home icon is now a real icon instead of a ::before mask-image. The icon has a filter that allows you to change it in both breadcrumbs with a single function.
  • I have added a breadcrumb to both themes for pages (except the *-blank.php templates) and archives via an action hook. Check the custom breadcrumb on posts, pages, WC pages, archives, and search results. They are still different breadcrumbs but are modified by filters shared across the breadcrumb files.

Loop

The index, archive, and search results now have filters and actions that allow you to fully customize the loop. You can modify the cards, adjust the columns, add more meta information, or remove existing meta. You can also change font-size classes or create vertical cards. Everything is possible (see the example snippets).

The author archive now includes the Gravatar, added via an action.

Icons

These themes have Font Awesome disabled and use Bootstrap Icons or Boxicons instead. Each icon can be modified with a filter. Add an item to the cart to see the icons in the offcanvas cart.

Content

Posts include additional meta information and the updated date above the tags.

Sidebar

The sidebar title and icon are different on WC pages.

I’ve already implemented this on a customer’s live site, https://song-ev.de, where these hooks are used to create a secondary burger menu next to the navbar, as well as the triangle above the footer and below the header (not on the front page).

Filters

Filter list (including existing ones)
  • bootscore/class/header
    • header.php
  • bootscore/class/header/navbar/breakpoint
    • header.php
  • bootscore/class/container ($location)
    • header.php, 404.php, archive.php, footer.php, index.php, page.php, search.php, single.php, woocommerce.php, /page-templates/page-blank-container.php, /page-templates/page-full-width-image.php, /page-templates/page-sidebar-none.php, /page-templates/page-sidebar-left.php, /single-templates/single-full-width-image.php, /single-templates/single-sidebar-left.php, /single-templates/single-sidebar-none.php, /template-parts/header/collapse-search-woocommerce.php, /template-parts/header/collapse-search.php
  • bootscore/class/header/navbar-brand
    • header.php
  • bootscore/logo
    • header.php
  • bootscore/class/header/offcanvas/direction ($location)
    • header.php, /template-parts/header/offcanvas-woocommerce.php
  • bootscore/class/offcanvas/header ($location)
    • header.php, sidebar.php, /template-parts/header/offcanvas-woocommerce.php
  • bootscore/offcanvas/navbar/title
    • header.php
  • bootscore/class/offcanvas/body ($location)
    • header.php, sidebar.php, /template-parts/header/offcanvas-woocommerce.php
  • bootscore/class/header-actions
    • header.php
  • bootscore/class/header/button ($location)
    • header.php, /template-parts/header/actions-woocommerce.php, /template-parts/header/actions.php
  • bootscore/class/header/navbar/toggler/breakpoint
    • header.php
  • bootscore/class/header/action/spacer ($location)
    • header.php, /template-parts/header/actions.php, /template-parts/header/actions-woocommerce.php, /inc/widgets.php
  • bootscore/class/header/top-nav-widget-2
    • /inc/widgets.php
  • bootscore/class/header/search/breakpoint
    • /template-parts/header/actions.php, /template-parts/header/collapse-search.php
  • bootscore/class/header/navbar-nav
    • /template-parts/header/main-menu.php
  • bootscore/offcanvas/account/title
    • /template-parts/header/offcanvas-woocommerce.php
  • bootscore/offcanvas/cart/title
    • /template-parts/header/offcanvas-woocommerce.php
  • bootscore/class/cart/product-title
    • /woocommerce/cart/mini-cart.php
  • bootscore/class/cart/enable_cart_product_excerpt (true)
    • /woocommerce/cart/mini-cart.php
  • bootscore/class/cart/product-excerpt
    • /woocommerce/cart/mini-cart.php
  • bootscore/class/cart/enable_cart_stock_quantity (true)
    • /woocommerce/cart/mini-cart.php
  • bootscore/class/header/cart/footer
    • /woocommerce/cart/mini-cart.php
  • bootscore/class/breadcrumb/nav
    • /inc/breadcrumb.php, /woocommerce/inc/wc-breadcrumb.php
  • bootscore/class/breadcrumb/ol
    • /inc/breadcrumb.php, /woocommerce/inc/wc-breadcrumb.php
  • bootscore/class/breadcrumb/item/link
    • /inc/breadcrumb.php, /woocommerce/inc/wc-breadcrumb.php
  • bootscore/class/main/col
    • archive.php, index.php, page.php, search.php, single.php, woocommerce.php, /inc/columns.php, /page-templates/page-full-width-image.php, /page-templates/page-sidebar-left.php, /single-templates/single-full-width-image.php, /single-templates/single-sidebar-left.php
  • bootscore/class/entry/title ($location)
    • 404.php, archive.php, index.php, page.php, search.php, single.php, /page-templates/page-full-width-image.php, /page-templates/page-sidebar-left.php, /page-templates/page-sidebar-none.php, /single-templates/single-full-width-image.php, /single-templates/single-sidebar-left.php, /single-templates/single-sidebar-none.php
  • bootscore/class/content/spacer ($location)
    • 404.php, archive.php, index.php, page.php, search.php, single.php, /page-templates/page-full-width-image.php, /page-templates/page-sidebar-left.php, /page-templates/page-sidebar-none.php, /single-templates/single-full-width-image.php, /single-templates/single-sidebar-left.php, /single-templates/single-sidebar-none.php
  • bootscore/class/featured-full-width-img ($location)
    • /page-templates/page-full-width-image.php, /single-templates/single-full-width-image.php
  • bootscore/class/full-width-img-title-wrapper ($location)
    • /page-templates/page-full-width-image.php, /single-templates/single-full-width-image.php
  • bootscore/class/loop/card ($location)
    • archive.php, index.php, /template-parts/search/content-search.php
  • bootscore/class/loop/card/row ($location)
    • archive.php, index.php, /template-parts/search/content-search.php
  • bootscore/class/loop/card/image/col ($location)
    • archive.php, index.php, /template-parts/search/content-search.php
  • bootscore/class/loop/card/image ($location)
    • archive.php, index.php, /template-parts/search/content-search.php
  • bootscore/class/loop/card/content/col ($location)
    • archive.php, index.php, /template-parts/search/content-search.php
  • bootscore/class/loop/card/body ($location)
    • archive.php, index.php, /template-parts/search/content-search.php
  • bootscore/loop/category (true, $location)
    • archive.php, index.php, /template-parts/search/content-search.php
  • bootscore/class/loop/card/title ($location)
    • archive.php, index.php, /template-parts/search/content-search.php
  • bootscore/loop/meta (true, $location)
    • archive.php, index.php, /template-parts/search/content-search.php
  • bootscore/loop/excerpt (true, $location)
    • archive.php, index.php, /template-parts/search/content-search.php
  • bootscore/class/loop/card-text/excerpt ($location)
    • archive.php, index.php, /template-parts/search/content-search.php
  • bootscore/loop/read-more (true, $location)
    • archive.php, index.php, /template-parts/search/content-search.php
  • bootscore/class/loop/card-text/read-more ($location)
    • archive.php, index.php, /template-parts/search/content-search.php
  • bootscore/class/loop/read-more ($location)
    • archive.php, index.php, /template-parts/search/content-search.php
  • bootscore/loop/read-more/text ($location)`
    • archive.php, index.php, /template-parts/search/content-search.php
  • bootscore/loop/tags (true, $location)
    • archive.php, index.php, /template-parts/search/content-search.php
  • bootscore/class/sidebar/col
    • sidebar.php
  • bootscore/class/sidebar/button
    • sidebar.php
  • bootscore/offcanvas/sidebar/button/text
    • sidebar.php
  • bootscore/class/sidebar/offcanvas
    • sidebar.php
  • bootscore/offcanvas/sidebar/title
    • sidebar.php
  • bootscore/block/archives/content
    • /inc/blocks/block-widget-archives.php
  • bootscore/block/calendar/content
    • /inc/blocks/block-widget-calendar.php
  • bootscore/block/categories/content
    • /inc/blocks/block-widget-categories.php
  • bootscore/block/latest-comments/content
    • /inc/blocks/block-widget-latest-comments.php
  • bootscore/block/latest-posts/content
    • /inc/blocks/block-widget-latest-posts.php
  • bootscore/class/widget/search/button ($location)
    • searchform.php, /inc/blocks/block-widget-search.php
  • bootscore/block/search/content
    • /inc/blocks/block-widget-search.php
  • bootscore/icon/menu
    • header.php
  • bootscore/icon/search ($location)
    • searchform.php, /inc/blocks/block-widget-search.php, /template-parts/header/actions.php, /template-parts/header/actions-woocommerce.php
  • bootscore/icon/user
    • /template-parts/header/actions-woocommerce.php
  • bootscore/icon/arrow-left
    • /template-parts/header/actions-woocommerce.php
  • bootscore/icon/cart
    • /template-parts/header/actions-woocommerce.php
  • bootscore/icon/trash
    • /woocommerce/cart/mini-cart.php
  • bootscore/icon/chevron-up
    • footer.php
  • bootscore/icon/home
    • /inc/breadcrumb.php, /woocommerce/inc/wc-breadcrumb.php
  • bootscore/icon/comments
    • /inc/template-tags.php
  • bootscore/class/comment/avatar
    • comments.php, /woocommerce/single-product/review.php
  • bootscore/class/badge/category
    • /inc/template-tags.php
  • bootscore/meta/time/updated
    • /inc/template-tags.php
  • bootscore/meta/author
    • /inc/template-tags.php
  • bootscore/class/badge/tag
    • /inc/template-tags.php
  • bootscore/class/footer/top
    • footer.php
  • bootscore/class/footer/columns
    • footer.php
  • bootscore/class/footer/col ($location)
    • footer.php
  • bootscore/class/footer/col/spacer ($location)
    • /inc/widgets.php
  • bootscore/class/footer/info
    • footer.php
  • bootscore/class/footer/to_top_button
    • footer.php
  • bootscore/load_fontawesome (true)
    • /inc/enqueue.php
  • bootscore/skip_cart (false)
    • /template-parts/header/actions-woocommerce.php, /woocommerce/wc-functions.php
  • bootscore/load_ajax_cart (true)
    • /woocommerce/wc-functions.php
  • bootscore/scss/skip_environment_check (false)
    • /inc/scss-compiler.php
  • bootscore/scss/disable_compiler (false)
    • /inc/scss-compiler.php
  • bootscore/scss/compiler
    • /inc/scss-compiler.php

Actions

Snippet to hook into all actions

This snippet generates an alert-warning for each action to make them visible:

/**
 * Generate hooks for all bootscore actions
 */
$bootscore_hooks = [
  'bootscore_before_masthead',
  'bootscore_after_masthead_open',
  'bootscore_before_navbar_brand',
  'bootscore_after_nav_toggler',
  'bootscore_before_masthead_close',
  'bootscore_after_masthead',
  'bootscore_after_primary_open',
  'bootscore_before_title',
  'bootscore_after_title',
  'bootscore_before_loop',
  'bootscore_before_loop_item',
  'bootscore_before_loop_title',
  'bootscore_loop_item_after_card_body',
  'bootscore_after_loop_item',
  'bootscore_after_loop',
  'bootscore_after_featured_image',
  'bootscore_before_entry_footer',
  'bootscore_before_sidebar_widgets',
  'bootscore_after_sidebar_widgets',
  'bootscore_before_footer',
  'bootscore_footer_columns_before_container',
  'bootscore_footer_columns_after_container_open',
  'bootscore_footer_columns_before_container_close',
  'bootscore_footer_columns_after_container',
  'bootscore_footer_info_after_container_open',
];

// Add hooks dynamically
foreach ($bootscore_hooks as $hook) {
  add_action($hook, function ($location = null) use ($hook) {
    $output = '<div class="alert alert-warning"><code>' . esc_html($hook) . '</code>';
    if ($location) {
      $output .= ' (Location: <strong>' . esc_html($location) . '</strong>)';
    }
    $output .= '</div>';
    echo $output;
  });
}
Action list and visual map

Header

header

  • bootscore_before_masthead
  • bootscore_after_masthead_open
  • bootscore_before_navbar_brand
  • bootscore_after_nav_toggler
  • bootscore_before_masthead_close
  • bootscore_after_masthead

Loop, content & sidebar

Index

index

Archive

archive

Search

search

Page

page

Page full

page-full

Single

single

Single full

single-full

  • bootscore_after_primary_open ($location)
  • bootscore_before_title ($location)
  • bootscore_after_title ($location)
  • bootscore_before_loop ($location)
  • bootscore_before_loop_item ($location)
  • bootscore_before_loop_title ($location)
  • bootscore_loop_item_after_card_body ($location)
  • bootscore_after_loop_item ($location)
  • bootscore_after_loop ($location)
  • bootscore_after_featured_image ($location)
  • bootscore_before_entry_footer ($location)
  • bootscore_before_sidebar_widgets
  • bootscore_after_sidebar_widgets

Footer

footer

  • bootscore_before_footer
  • bootscore_footer_columns_before_container
  • bootscore_footer_columns_after_container_open
  • bootscore_footer_columns_before_container_close
  • bootscore_footer_columns_after_container
  • bootscore_footer_info_after_container_open

Examples

Here are some rough examples how powerful this filters and actions work together:

Change all icons
/**
 * Change nav-toggler icon
 */
function change_nav_toggler_icon() {
  return '<i class="fa-solid fa-list"></i>';
}
add_filter('bootscore/icon/menu', 'change_nav_toggler_icon');

/**
 * Change search-toggler icon
 */
function change_search_toggler_icon() {
  return '<i class="fa-solid fa-glasses"></i>';
}
add_filter('bootscore/icon/search', 'change_search_toggler_icon');

/**
 * Change account-toggler user icon
 */
function change_account_toggler_icon() {
  return '<i class="fa-solid fa-person-walking-dashed-line-arrow-right"></i>';
}
add_filter('bootscore/icon/user', 'change_account_toggler_icon');

/**
 * Change cart-toggler bag icon
 */
function change_cart_toggler_icon() {
  return '<i class="fa-solid fa-cart-shopping"></i>';
}
add_filter('bootscore/icon/cart', 'change_cart_toggler_icon');

/**
 * Change back-to-cart-toggler arrow icon
 */
function change_back_to_cart_arrow_icon() {
  return '<i class="fa-solid fa-chevron-left d-none d-md-inline me-2"></i>';
}
add_filter('bootscore/icon/arrow-left', 'change_back_to_cart_arrow_icon');

/**
 * Change sidebar offcanvas-toggler icon
 */
function change_sidebar_toggler_icon() {
  return '<i class="fa-solid fa-expand"></i>';
}
add_filter('bootscore/icon/ellipsis-vertical', 'change_sidebar_toggler_icon');

/**
 * Change WooCommerce mini-cart trash icon
 */
function change_trash_icon() {
  return '<i class="fa-solid fa-xmark"></i>';
}
add_filter('bootscore/icon/trash', 'change_trash_icon');

/**
 * Change star icon
 */
function change_star_icon() {
  return '<i class="fa-solid fa-map-pin"></i>';
}
add_filter('bootscore/icon/star', 'change_star_icon');

/**
 * Change comments icon
 */
function change_comments_icon() {
  return '<i class="fa-solid fa-comment-dots"></i>';
}
add_filter('bootscore/icon/comments', 'change_comments_icon');

/**
 * Change breadcrumb home icon
 */
function change_home_icon() {
  return '<i class="fa-solid fa-igloo"></i>';
}
add_filter('bootscore/icon/home', 'change_home_icon');
Add a mobile logo, center the logo and move menu to left
/**
 * Header hook a mobile logo
 */
function hook_before_navbar_brand() {
  ?>
    <a class="position-absolute top-50 start-50 translate-middle d-sm-none" href="<?= esc_url(home_url()); ?>">
      <img src="<?= esc_url(get_stylesheet_directory_uri()); ?>/assets/img/logo/logo-sm.svg" alt="<?php bloginfo('name'); ?> Logo" class="d-td-none">
      <img src="<?= esc_url(get_stylesheet_directory_uri()); ?>/assets/img/logo/logo-sm-theme-dark.svg" alt="<?php bloginfo('name'); ?> Logo" class="d-tl-none">
    </a>  
  <?php
}
add_action( 'bootscore_before_navbar_brand', 'hook_before_navbar_brand' );


/**
 * Header navbar-brand
 */
function header_navbar_brand_class() {
  return "position-absolute top-50 start-50 translate-middle d-none d-sm-block";
}
add_filter('bootscore/class/header/navbar-brand', 'header_navbar_brand_class', 10, 2);


/**
 * Header menu position
 */
function header_navbar_menu_class() {
  return "ms-start";
}
add_filter('bootscore/class/header/navbar-nav', 'header_navbar_menu_class', 10, 2);


/**
 * Header actions
 */
function header_actions_class() {
  return "d-flex align-items-center flex-grow-1 justify-content-lg-end";
}
add_filter('bootscore/class/header-actions', 'header_actions_class', 10, 2);


/**
 * Move nav-toggler to first
 */
function header_nav_toggler_button_spacer_class($string, $location) {
  if ($location == 'nav-toggler') {
    return "order-first me-auto";
  }
  return $string;
}
add_filter('bootscore/class/header/action/spacer', 'header_nav_toggler_button_spacer_class', 10, 2);


/**
 * Change header menu offcanvas direction
 */
function header_menu_offcanvas_directions($string, $location) {
  if ($location == 'menu') {
    return "start";
  }
  return $string;
}
add_filter('bootscore/class/header/offcanvas/direction', 'header_menu_offcanvas_directions', 10, 2);
Search collapse always collapsed (if WC is not installed)
/**
* Change search collapse breakpoint if WooCommerce is not installed
* Leave breakpoint empty to keep search always collapsed
*/
function change_search_collapse_breakpoint() {
return 'xxl';
}
add_filter('bootscore/class/header/search/breakpoint', 'change_search_collapse_breakpoint');
Breadcrumb
/**
 * Change breadcrumb <nav> classes
 */
function change_breadcrumb_nav_class() {
  return 'overflow-x-auto text-nowrap mb-4 mt-2 py-2 px-3 border rounded';
}
add_filter('bootscore/class/breadcrumb/nav', 'change_breadcrumb_nav_class');

/**
 * Change breadcrumb <ol> classes
 */
function change_breadcrumb_ol_class() {
  return 'flex-nowrap mb-0';
}
add_filter('bootscore/class/breadcrumb/ol', 'change_breadcrumb_ol_class');

/**
 * Change breadcrumb <a> classes
 */
function change_breadcrumb_a_class() {
  return 'text-decoration-none link-danger';
}
add_filter('bootscore/class/breadcrumb/item/link', 'change_breadcrumb_a_class');
Change all loop horizontal cards into vertical cards and change read-more
/**
 * Hook the function to 'bootscore_before_loop'
 */
function hook_before_loop() {
  echo '<div class="row">';
}
add_action( 'bootscore_before_loop', 'hook_before_loop' );


/**
 * Hook the function to 'bootscore_before_loop_item'
 */
function hook_before_loop_item() {
  echo '<div class="col-md-6 col-lg-4 mb-4">';
}
add_action( 'bootscore_before_loop_item', 'hook_before_loop_item' );


/**
 * Hook the function to 'bootscore_after_loop_item'
 */
function hook_after_loop_item() {
  echo '</div>';
}
add_action( 'bootscore_after_loop_item', 'hook_after_loop_item' );


/**
 * Hook the function to 'bootscore_after_loop'
 */
function hook_after_loop() {
  echo '</div>';
}
add_action( 'bootscore_after_loop', 'hook_after_loop' );


/**
 * Change loop card class
 */
function loop_card_class() {
  return "card border-0 shadow h-100";
}
add_filter('bootscore/class/loop/card', 'loop_card_class', 10, 2);


/**
 * Change loop card row class
 */
function loop_card_row_class() {
  return "d-flex flex-column h-100";
}
add_filter('bootscore/class/loop/card/row', 'loop_card_row_class', 10, 2);


/**
 * Change loop image col class
 */
function loop_image_col_class() {
  return "";
}
add_filter('bootscore/class/loop/card/image/col', 'loop_image_col_class', 10, 2);


/**
 * Change loop content col class
 */
function loop_content_col_class() {
  return "d-flex flex-column h-100";
}
add_filter('bootscore/class/loop/card/content/col', 'loop_content_col_class', 10, 2);


/**
 * Change loop image class
 */
function loop_image_class() {
  return "card-img-top";
}
add_filter('bootscore/class/loop/card/image', 'loop_image_class', 10, 2);

/**
 * Change loop card-body class
 */
function loop_card_body_class() {
  return "card-body h-100 d-flex flex-column";
}
add_filter('bootscore/class/loop/card/body', 'loop_card_body_class', 10, 2);


/**
 * Change loop excerpt card-text class
 */
function loop_card_text_excerpt_class() {
  return "card-text small";
}
add_filter('bootscore/class/loop/card-text/excerpt', 'loop_card_text_excerpt_class', 10, 2);


/**
 * Change loop read-more card-text class
 */
function loop_card_text_read_more_class() {
  return "card-text mt-auto";
}
add_filter('bootscore/class/loop/card-text/read-more', 'loop_card_text_read_more_class', 10, 2);

/**
 * Change loop read-more class
 */
function loop_read_more_class() {
  return "btn btn-primary d-block";
}
add_filter('bootscore/class/loop/read-more', 'loop_read_more_class', 10, 2);


/**
 * Change loop read-more text
 */
function change_loop_read_more_text($title) {
  return 'Continue reading <i class="fa-solid fa-arrow-right"></i>';
}
add_filter('bootscore/loop/read-more/text', 'change_loop_read_more_text');



// Sticky

/**
 * Hook the function to 'bootscore_before_loop_sticky'
 */
function hook_before_loop_sticky() {
  echo '<div class="row">';
}
add_action( 'bootscore_before_loop_sticky', 'hook_before_loop_sticky' );


/**
 * Hook the function to 'bootscore_before_loop_item'
 */
function hook_before_loop_item_sticky() {
  echo '<div class="col-md-6 mb-4">';
}
add_action( 'bootscore_before_loop_item_sticky', 'hook_before_loop_item_sticky' );


/**
 * Hook the function to 'bootscore_after_loop_item_sticky'
 */
function hook_after_loop_item_sticky() {
  echo '</div>';
}
add_action( 'bootscore_after_loop_item_sticky', 'hook_after_loop_item_sticky' );


/**
 * Hook the function to 'bootscore_after_loop'
 */
function hook_after_loop_sticky() {
  echo '</div>';
}
add_action( 'bootscore_after_loop_sticky', 'hook_after_loop_sticky' );

cc @hsankala

@crftwrk crftwrk marked this pull request as draft September 20, 2024 08:39
@crftwrk crftwrk added the documentation Improvements or additions to documentation label Sep 20, 2024
@crftwrk crftwrk mentioned this pull request Sep 20, 2024
@crftwrk crftwrk marked this pull request as ready for review February 3, 2025 11:32
@crftwrk crftwrk requested a review from justinkruit February 3, 2025 11:32
@crftwrk crftwrk merged commit 86e423f into main Feb 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation feature

Projects

No open projects
Status: Done

Development

Successfully merging this pull request may close these issues.

[BUG] Unable to remove the cookie checkbox

4 participants