Jump to Navigation Jump to Main Content Jump to Footer
Home » Docs » Features » Utility and helper functions

Utility and helper functions

Chisel provides a focused set of helper functions (PHP, Twig, and JavaScript) to speed up development, keep templates clean, and standardize output. PHP helpers are organized by domain in core/Helpers/, Twig functions are registered in core/WP/Twig.php, and JavaScript utilities live in src/scripts/modules/.

All helpers are namespaced under Chisel\Helpers and use static methods for easy access throughout the codebase. Twig functions wrap these helpers for template use, maintaining a consistent API between PHP and template contexts.

Common patterns include BEM class generation, responsive image handling, environment detection, cache management, and AJAX communication. Helpers integrate seamlessly with WordPress, Timber, ACF, WooCommerce, Gravity Forms, and Yoast SEO.

Twig helpers

File: core/WP/Twig.php

Twig functions are registered via the Twig class which extends the Timber Twig environment. All functions are automatically available in Twig templates.

Navigation

get_nav_menu(name)

Returns a Timber menu object from the global context.

Source: Chisel\WP\Twig::get_nav_menu()

{{ get_nav_menu('primary') }}
Twig

Post and product handling

timber_set_product(post)

Ensures global $product is set correctly in WooCommerce loops.

Source: WoocommerceHelpers::timber_set_product()

{% for post in posts %}
    {{ timber_set_product(post) }}
    {# Now $product global is available #}
{% endfor %}
Twig

post_classes(classes, prefix='c-post')

Transforms WordPress post classes into ITCSS/BEM style.

Source: Chisel\WP\Twig::post_classes()

<article class="{{ post_classes(post.class, 'c-article') }}">
Twig

Images

get_responsive_image(image_id, size='medium', attrs={})

Outputs responsive <img> with proper dimensions to reduce CLS (Cumulative Layout Shift).

Source: ImageHelpers::get_responsive_image()

{{ get_responsive_image(post.thumbnail.id, 'large', { class: 'c-image' }) }}
Twig

Components and UI

get_icon(args)

Renders an SVG icon by name and options. See views/objects/icon.twig for full argument list.

Source: Chisel\WP\Components::get_icon()

{{ get_icon({ name: 'arrow-right', inline: true }) }}
Twig

comments_template()

Outputs comments pattern if supported/open.

Source: CommentsHelpers::comments_template()

{{ comments_template() }}
Twig

breadcrumbs()

Renders Yoast SEO breadcrumbs (if plugin active).

Source: YoastHelpers::breadcrumbs()

{{ breadcrumbs() }}
Twig

BEM and styling

bem(name, ...modifiers)

Generates BEM class names with modifiers from booleans, strings, or keyed values.

Source: ThemeHelpers::bem()

<div class="{{ bem('c-card', 'featured', post.sticky ? 'sticky' : false) }}">
    {# Outputs: c-card c-card--featured c-card--sticky #}
</div>

<div class="{{ bem('c-btn', { size: 'large', color: 'primary' }) }}">
    {# Outputs: c-btn c-btn--size-large c-btn--color-primary #}
</div>
Twig

PHP helpers

All helpers are located in core/Helpers/ and use static methods.

ThemeHelpers

File: core/Helpers/ThemeHelpers.php

Environment detection:

ThemeHelpers::is_dev_env(): bool
PHP

Checks if WP_ENVIRONMENT_TYPE is 'development'

ThemeHelpers::is_fast_refresh(): bool
PHP

Checks if development mode with fast refresh enabled (checks for build/runtime.js).

Theme information:

ThemeHelpers::get_theme_version(): string
PHP

Returns theme version from stylesheet.

ThemeHelpers::get_theme_name(): string
PHP

Returns site title from get_bloginfo('name').

BEM class generation:

ThemeHelpers::bem( string $name = '', mixed ...$modifiers ): string
PHP

Generates BEM classes from modifiers. Supports booleans, strings, arrays, and associative arrays.

// Simple modifiers
ThemeHelpers::bem('c-btn', 'primary', 'large');
// Output: c-btn c-btn--primary c-btn--large

// Conditional modifiers
ThemeHelpers::bem('c-card', $is_featured ? 'featured' : false);
// Output: c-card c-card--featured (if $is_featured is true)

// Keyed modifiers
ThemeHelpers::bem('c-btn', array( 'size' => 'large', 'color' => 'primary' ));
// Output: c-btn c-btn--size-large c-btn--color-primary
PHP

Color palettes:

ThemeHelpers::get_colors_palette( string $type ): string|array
PHP

Returns color palettes from theme.json for ACF or TinyMCE.

Parameters:

  • $type → 'acf' (returns array of hex colors) or 'tinymce' (returns formatted string)
$acf_colors = ThemeHelpers::get_colors_palette('acf');
// Returns: ['#ff0000', '#00ff00', '#0000ff']

$tinymce_colors = ThemeHelpers::get_colors_palette('tinymce');
// Returns: "ff0000", "Red", "00ff00", "Green", ...
PHP

Login logo data:

ThemeHelpers::get_login_page_logo_data(): array
PHP

Returns array with logo URL, width, height for WP login page CSS.

AssetsHelpers

File: core/Helpers/AssetsHelpers.php

get_final_handle($handle): string

Returns namespaced asset handle; appends -fast-refresh suffix in dev hot module mode.

$handle = AssetsHelpers::get_final_handle('app');
// Production: 'chisel-app'
// Development (with fast refresh): 'chisel-app-fast-refresh'
PHP

ImageHelpers

File: core/Helpers/ImageHelpers.php

get_image_url($name, $is_icon=false): string

Returns URL to theme asset in /assets/images/ or /assets/icons/.

$logo_url = ImageHelpers::get_image_url('logo.svg');
// Returns: https://example.com/wp-content/themes/chisel/assets/images/logo.svg

$icon_url = ImageHelpers::get_image_url('search.svg', true);
// Returns: https://example.com/wp-content/themes/chisel/assets/icons/search.svg
PHP

get_responsive_image($id, $size='medium', $attrs=[]): string

Returns responsive image HTML with srcset and sizes. Optional width/height override to prevent layout shifts.

echo ImageHelpers::get_responsive_image(123, 'large', [
    'class' => 'c-hero__image',
    'alt' => 'Hero image'
]);
PHP

CacheHelpers

File: core/Helpers/CacheHelpers.php

expiry($custom = null): int

Returns theme’s cache expiry (0 if chisel_environment_cache filter returns false).

$expiry = CacheHelpers::expiry();
// Returns: HOUR_IN_SECONDS or 0

$custom_expiry = CacheHelpers::expiry(DAY_IN_SECONDS);
PHP

clear_environment_cache(): void

Clears Twig loader cache.

CacheHelpers::clear_environment_cache();
PHP

DataHelpers

File: core/Helpers/DataHelpers.php

json_encode_for_data_attribute($data): string

JSON encodes data for embedding into data-* HTML attributes (properly escaped).

$json = DataHelpers::json_encode_for_data_attribute(array('key' => 'value'));
// Returns: escaped JSON string safe for HTML attributes
PHP

object_to_array($obj): array

Converts object to array via JSON encode/decode.

$array = DataHelpers::object_to_array($stdClass);
PHP

AjaxHelpers

File: core/Helpers/AjaxHelpers.php

get_ajax_endpoint_url(): string

Returns full REST URL for theme AJAX (namespace/base from AjaxController).

$url = AjaxHelpers::get_ajax_endpoint_url();
// Returns: https://example.com/wp-json/chisel/v2/ajax
PHP

ajax_json_decode($value): mixed

Safe JSON decode for POSTed strings. Returns original value if not valid JSON.

$data = AjaxHelpers::ajax_json_decode($_POST['data']);
PHP

BlocksHelpers

File: core/Helpers/BlocksHelpers.php

get_block_object_classnames($blockName): string

Generates BEM classes for blocks.

$classes = BlocksHelpers::get_block_object_classnames('chisel/slider');
// Returns: c-block c-block--chisel c-block--slider
PHP

render_twig_file($blockName, $context): string

Renders a block’s Twig template (render.twig or {block-name}.twig).

echo BlocksHelpers::render_twig_file('chisel/accordion', $context);
PHP

acf_block_render($block, $content, $is_preview, $post_id): void

Main ACF block renderer. Builds context with fieldswrapper_attributes, etc., applies filters, and renders block Twig.

BlocksHelpers::acf_block_render($block, $content, $is_preview, $post_id);
PHP

get_block_inline_css($blocksUrl, $blockName): string

Fetches built CSS from script.css for inlining (critical CSS).

$css = BlocksHelpers::get_block_inline_css($blocks_url, 'accordion');
PHP

AcfHelpers

File: core/Helpers/AcfHelpers.php

Safe wrappers for ACF functions that return false if ACF is not active.

get_field($selector, $postId=false, $format=true, $escape=false): mixed

$value = AcfHelpers::get_field('field_name', $post_id);
PHP

update_field($selector, $value, $postId=false): bool

AcfHelpers::update_field('field_name', 'new value', $post_id);
PHP

CommentsHelpers

File: core/Helpers/CommentsHelpers.php

comments_template(): string

Returns comments block pattern when comments are supported and open.

echo CommentsHelpers::comments_template();
PHP

YoastHelpers

File: core/Helpers/YoastHelpers.php

is_yoast_active(): bool

Checks if Yoast SEO plugin is active.

if ( YoastHelpers::is_yoast_active() ) {
    // Use Yoast features
}
PHP

breadcrumbs(): string

Returns breadcrumb HTML, empty if not active or on front page.

echo YoastHelpers::breadcrumbs();
PHP

WoocommerceHelpers

File: core/Helpers/WoocommerceHelpers.php

is_woocommerce_active(): bool

Checks if WooCommerce plugin is active.

if ( WoocommerceHelpers::is_woocommerce_active() ) {
    // Use WooCommerce features
}
PHP

timber_set_product($post): void

Fixes loop product context for Timber/Twig templates.

WoocommerceHelpers::timber_set_product($post);
PHP

get_products_grid_classnames($products, $has_sidebar): string

Returns o-grid classes capped at 4 columns for product grids.

$classes = WoocommerceHelpers::get_products_grid_classnames($products, false);
PHP

GravityFormsHelpers

File: core/Helpers/GravityFormsHelpers.php

is_gf_active(): bool

Checks if Gravity Forms plugin is active.

if ( GravityFormsHelpers::is_gf_active() ) {
    // Use Gravity Forms features
}
PHP

get_forms_list(): array

Returns array of form ID => title pairs, useful for ACF select field population. Useful to prefill ACF select field for choosing a form.

$forms = GravityFormsHelpers::get_forms_list();
// Returns: array( 1 => 'Contact Form', 2 => 'Newsletter Signup' )
PHP

get_form($id, $showTitle=false, $showDesc=false, $showInactive=false, $fieldValues=null, $ajax=true, $tabindex=0, $echo=false): string

Renders Gravity Form programmatically by ID.

echo GravityFormsHelpers::get_form(
    1,              // Form ID
    false,          // Show title
    false,          // Show description
    false,          // Show inactive
    null,           // Field values
    true,           // AJAX
    0,              // Tab index
    false           // Echo (return string instead)
);
PHP

Javascript helpers

File: src/scripts/helpers/utils.js

ajaxRequest utility

Signature: ajaxRequest(action, ajaxData = {}, ajaxParams = {}, ajaxHeaders = {}) => Promise

Purpose: Thin wrapper over fetch for authenticated REST AJAX calls to theme endpoints.

Behavior:

  • Builds endpoint from localized chiselScripts.ajax.url and action
  • Example: /wp-json/chisel/v2/ajax/load-more
  • Automatically adds X-WP-Nonce header
  • Handles both plain objects and FormData instances
  • Serializes nested objects to JSON strings in FormData

Security context: URL and nonce come from PHP localization in Assets::set_properties() under chiselScripts.ajax.

Response format: Matches theme endpoints (e.g., { error: 0|1, data, message? })

Usage:

import Utils from './helpers/utils';

// Basic request
const response = await Utils.ajaxRequest('load-more', {
    post_type: 'post',
    per_page: 10,
    page: 2
});

if (response.error) {
    console.error(response.message);
} else {
    console.log(response.data);
}

// With FormData
const formData = new FormData(form);
const response = await Utils.ajaxRequest('contact-form', formData);

// Custom params and headers
const response = await Utils.ajaxRequest(
    'search-posts',
    { query: 'wordpress' },
    { method: 'GET' },
    { 'Custom-Header': 'value' }
);
JavaScript

JavaScript modules

Load more module

File: src/scripts/modules/load-more.js

Purpose: Attaches “Load more” behavior to listings using the utils.ajaxRequest('load-more', ...) endpoint.

DOM hooks:

  • Container: .js-load-more-container (where items are appended)
  • Wrapper: .js-load-more (requires dataset attributes)
  • Button: .js-load-more-button (adds .is-loading class while fetching)

Required data attributes:

  • data-post-type → Post type to load
  • data-per-page → Number of posts per page
  • data-max-page → Maximum pages available

Behavior:

  • Starts at page: 2
  • Stops when page >= maxPage and removes wrapper
  • Server renders templates via Twig item templates (see LoadMoreEndpoint::handle())

HTML structure:

<div class="js-load-more-container">
    <!-- Posts rendered here -->
</div>

<div class="js-load-more" 
     data-post-type="post" 
     data-per-page="10" 
     data-max-page="5">
    <button class="js-load-more-button c-btn">
        Load More
    </button>
</div>
HTML

Slider module

File: src/scripts/modules/slider.js

Purpose: Initializes Swiper instances for elements with .js-slider. Dynamically imports Swiper (CSS + JS).

DOM hooks:

  • Slider root: .js-slider (expects .swiper-slide children)
  • Container: .js-slider-container (optional wrapper)

Data attributes:

AttributeTypeDefaultDescription
data-typestring'default'Slider type for custom params
data-arrows'yes'|'no''no'Enable navigation arrows
data-dots'yes'|'no''no'Enable pagination dots
data-dots-dynamicnumber0Dynamic bullets count
data-autoplay'yes'|'no''no'Enable autoplay
data-autoplay-timeoutnumber5000Autoplay delay (ms)
data-loop'yes'|'no''no'Enable infinite loop
data-speednumber1000Transition speed (ms)
data-slides-per-viewnumber1Visible slides
data-space-betweennumber10Gap between slides (px)
data-directionstring'horizontal''horizontal' or 'vertical'
data-auto-height'yes'|'no''no'Auto-adjust height per slide
data-center'yes'|'no''no'Center active slide
data-scrollbar'yes'|'no''no'Enable scrollbar
data-effectstring'slide'Transition effect
data-free-mode'yes'|'no''no'Free mode scrolling
data-parallax'yes'|'no''no'Parallax effect
data-initial-slidenumber0Start slide index
data-breakpointsJSONResponsive breakpoints
data-argsJSONOverride Swiper params
data-thumbnailsnumber0Enable thumbnails with count

Custom slider types:

Create type-specific params by adding a method to the Slider class:

productsSliderParams() {
    this.params = {
        ...this.params,
        spaceBetween: 20,
        slidesPerView: 3,
        breakpoints: {
            320: { slidesPerView: 1 },
            768: { slidesPerView: 2 },
            1024: { slidesPerView: 3 }
        }
    };
};
JavaScript

Then use: data-type="products"

Thumbnails feature:

  • Each slide needs data-thumbnail-url attribute
  • Set data-thumbnails="{count}" to enable
  • Script clones slider for thumbnails and wires via Swiper’s Thumbs module
  • Automatically sets width/height to avoid CLS

Accessibility:

  • ARIA live region announces slide changes
  • Navigation buttons include proper ARIA labels
  • Screen reader friendly

Best practices

PHP helpers

  • Use static methods: All helpers are static—no instantiation needed
  • Check plugin availability: Use is_*_active() helpers before plugin-specific code
  • Leverage BEM helper: Use ThemeHelpers::bem() for consistent class generation
  • Environment awareness: Use is_dev_env() and is_fast_refresh() for conditional dev features
  • Safe ACF access: Always use AcfHelpers wrappers instead of direct ACF functions

Twig functions

  • Wrap PHP helpers: Twig functions should wrap PHP helpers for consistency
  • Use custom hooks: Extend Twig via chisel_twig_register_* action hooks
  • Keep templates clean: Move complex logic to PHP helpers, keep Twig declarative

JavaScript utilities

  • Use Utils.ajaxRequest: Always use the provided wrapper for AJAX calls
  • Handle errors: Check response.error flag in all AJAX responses
  • Module pattern: Keep features isolated in separate module files
  • Dynamic imports: Use dynamic imports for large libraries like Swiper

General

  • Namespace custom helpers: Create helpers in custom/app/Helpers/ folder with clear naming
  • Filter integration: Use provided filters to extend core helpers
  • Documentation: Document custom helpers with comments

Do you like Chisel?

Give it a star on GitHub!