Chap WordPress theme
Chap

functions.php

If you’re using the child theme and need to add advanced custom features to your site, then the child theme’s functions.php (/wp-content/themes/chap-child/functions.php) is the most common place to add your code.

PHP knowledge required.

The contents of this file are completely up to you, this is how it looks like by default (since Chap 1.19.9):

PHP
Chap Child theme’s default functions.php
<?php
/**
 * Chap Child theme functions.php
 *
 * How to use this file:
 * @see https://chap.website/functions-php
 */
defined('ABSPATH') || exit;
define('CHAP_CHILD_VER', wp_get_theme()->get('Version'));

/**
 * Load child theme assets.
 */
add_action('wp_enqueue_scripts', function() {
	wp_enqueue_style('chap-child', get_stylesheet_directory_uri() . '/style.css', false, CHAP_CHILD_VER);
	wp_enqueue_script('chap-child/js', get_stylesheet_directory_uri() . '/scripts.js', ['chap/js'], CHAP_CHILD_VER, true);
}, 150);

/** Add custom filters, actions and functions below. */

Adding custom actions, filters and functions

Simply add your custom code at the end of the file. It’s a good idea to add comment blocks above your code to have a reference of what the code does when you come back to it months or years later.

PHP
functions.php with custom code
<?php

...

/** Add custom filters, actions and functions below. */

/**
 * Add a custom image size.
 */
add_action('after_setup_theme', function() {
	add_image_size('custom-image-size', 28, 28, true);
});

/**
 * Modify the title.
 */
add_filter('the_title', function($title) {
	return 'The ' . $title . ' was filtered';
});

In the above example anonymous functions are being passed to the WordPress add_action and add_filter functions. This is the cleanest and most readable way of doing it (personal opinion). When reading various WordPress guides and tutorials you may see filters like:

PHP
<?php

...

/** Add custom filters, actions and functions below. */

function myprefix_add_settings() {
	?>
	New 1: <input id="new_setting" name="new_settings" type="text">
	<?php
}
add_action('wporg_after_settings_page_html', 'myprefix_add_settings');

function wporg_filter_title($title) {
	return 'The ' . $title . ' was filtered';
}
add_filter('the_title', 'wporg_filter_title');

and adding them in this format is fine as well, except in that case you will have to make sure that your function name has a unique prefix in order to not conflict with any other functions from core or other plugins that may use the same name.

Overriding theme core functions Advanced

Chap theme includes pluggable functions in PHP namespaces that can be overridden if you wish to change the default functionality.

To override a function in a namespace a new file with the appropriate namespace should be created and included from the main functions.php file of the child theme.

First let’s create the file that defines a chap_render_header_open function in the Chap\TemplateFunctions namespace to override it:

PHP
Create /chap-child/overrides.php
<?php
/**
 * Chap core functions overrides.
 */

namespace Chap\TemplateFunctions {
	use Chap\Options;
	use Chap\Helpers;

	/**
	 * Custom header opening tag function.
	 */
	function chap_render_header_open() {
		$header_classes = Helpers\classnames([
			'ui',
			'inverted' => Options\get('header_inverted'),
			'segment',
		]);

		?>
		Custom content before header opening tag.
		<div class="<?php echo esc_attr($header_classes); ?>">
		<?php
	}
}

Next, this file should be included from the functions.php file:

PHP
Including overrides.php in functions.php
<?php
/**
 * Chap Child theme functions.php
 *
 * How to use this file:
 * @see https://chap.website/functions-php
 */
defined('ABSPATH') || exit;
define('CHAP_CHILD_VER', wp_get_theme()->get('Version'));

/**
 * Load child theme assets.
 */
add_action('wp_enqueue_scripts', function() {
	wp_enqueue_style('chap-child', get_stylesheet_directory_uri() . '/style.css', false, CHAP_CHILD_VER);
	wp_enqueue_script('chap-child/js', get_stylesheet_directory_uri() . '/scripts.js', ['chap/js'], CHAP_CHILD_VER, true);
}, 150);

/** Add custom filters, actions and functions below. */

include_once 'overrides.php';

Now the Chap\TemplateFunctions\chap_render_header_open function is defined and Chap theme will use it instead of the initial one in the theme core.

Page 2 contains documentation of the old functions.php that was provided before Chap version 1.19.9. This version used PHP Namespaces out of the box to allow more intuitive overriding of core functions, how ever this often proved to be too confusing for users with no PHP knowledge.
This page documents the Chap Child functions.php that was provided before Chap version 1.19.9.
If your file doesn’t look like that go to the previous page.

If you’re using the child theme and need to add advanced custom features to your site, then the child theme’s functions.php (/wp-content/themes/chap-child/functions.php) is the most common place to add your code.

The contents of this file are completely up to you, how ever by default it is set up with some PHP namespaces and an action that includes the child theme’s style and script files.

PHP
Chap theme’s default functions.php
<?php

namespace Chap\Child {

	/**
	 * Load the child theme assets.
	 */
	function assets() {
		wp_enqueue_style('chap-child', get_stylesheet_directory_uri() . '/style.css', false, wp_get_theme()->get('Version'));
		wp_enqueue_script('chap-child/js', get_stylesheet_directory_uri() . '/scripts.js', ['chap/js'], wp_get_theme()->get('Version'), true);
	}
	add_action('wp_enqueue_scripts', __NAMESPACE__ . '\\assets', 150);

}

namespace Chap\TemplateFunctions {

	/**
	 * Override any template function here.
	 */

}

Adding an action

With the PHP namespaces, all code should be contained within the brackets of a namespace. When adding an action you should specify the namespace in front of the function name that you’re adding.

PHP
<?php

namespace Chap\Child {

	/**
	 * Load the child theme assets.
	 */
	function assets() {
		wp_enqueue_style('chap-child', get_stylesheet_directory_uri() . '/style.css', false, wp_get_theme()->get('Version'));
		wp_enqueue_script('chap-child/js', get_stylesheet_directory_uri() . '/scripts.js', ['chap/js'], wp_get_theme()->get('Version'), true);
	}
	add_action('wp_enqueue_scripts', __NAMESPACE__ . '\\assets', 150);
  
	/**
	 * Add a custom image size.
	 */
	function add_custom_image_size() {
		add_image_size('custom-image-size', 28, 28, true);
	}
	add_action('after_setup_theme', __NAMESPACE__ . '\\add_custom_image_size');

}

Alternatively, you could use the global namespace namespace { ... } without needing to prefix the function with the current namespace, how ever if any plugin anywhere uses the same function name (in this example add_custom_image_size()) then it will cause a conflict.

PHP
<?php

namespace Chap\Child {

	/**
	 * Load the child theme assets.
	 */
	function assets() {
		wp_enqueue_style('chap-child', get_stylesheet_directory_uri() . '/style.css', false, wp_get_theme()->get('Version'));
		wp_enqueue_script('chap-child/js', get_stylesheet_directory_uri() . '/scripts.js', ['chap/js'], wp_get_theme()->get('Version'), true);
	}
	add_action('wp_enqueue_scripts', __NAMESPACE__ . '\\assets', 150);

}

namespace {

	/**
	 * Add a custom image size.
	 */
	function add_custom_image_size() {
		add_image_size('custom-image-size', 28, 28, true);
	}
	add_action('after_setup_theme', 'add_custom_image_size');

}

The simplest way would be to use anonymous functions directly as the second argument to add_action(), which saves you the trouble of defining a separate function and then assigning it. It looks much more compact and readable, how ever with this approach it is not possible to later conditionally remove that specific action with some other code.

PHP
<?php

namespace Chap\Child {

	/**
	 * Load the child theme assets.
	 */
	function assets() {
		wp_enqueue_style('chap-child', get_stylesheet_directory_uri() . '/style.css', false, wp_get_theme()->get('Version'));
		wp_enqueue_script('chap-child/js', get_stylesheet_directory_uri() . '/scripts.js', ['chap/js'], wp_get_theme()->get('Version'), true);
	}
	add_action('wp_enqueue_scripts', __NAMESPACE__ . '\\assets', 150);
  
	/**
	 * Add a custom image size.
	 */
	add_action('after_setup_theme', function() {
		add_image_size('custom-image-size', 28, 28, true);
	});

}

Finally, you could opt out of all the namespaces by getting rid of them entirely:

PHP
<?php

/**
 * Load the child theme assets.
 */
function assets() {
	wp_enqueue_style('chap-child', get_stylesheet_directory_uri() . '/style.css', false, wp_get_theme()->get('Version'));
	wp_enqueue_script('chap-child/js', get_stylesheet_directory_uri() . '/scripts.js', ['chap/js'], wp_get_theme()->get('Version'), true);
}
add_action('wp_enqueue_scripts', __NAMESPACE__ . '\\assets', 150);

/**
 * Add a custom image size.
 */
function add_custom_image_size() {
	add_image_size('custom-image-size', 28, 28, true);
}
add_action('after_setup_theme', 'add_custom_image_size');

or create a new file my-functions.php to house your unnamespaced code:

PHP
/wp-content/themes/chap-child/my-functions.php
<?php

/**
 * Add a custom image size.
 */
function add_custom_image_size() {
	add_image_size('custom-image-size', 28, 28, true);
}
add_action('after_setup_theme', 'add_custom_image_size');

and simply include it in the original functions.php:

PHP
Chap theme’s default functions.php
<?php

namespace Chap\Child {

	/**
	 * Load the child theme assets.
	 */
	function assets() {
		wp_enqueue_style('chap-child', get_stylesheet_directory_uri() . '/style.css', false, wp_get_theme()->get('Version'));
		wp_enqueue_script('chap-child/js', get_stylesheet_directory_uri() . '/scripts.js', ['chap/js'], wp_get_theme()->get('Version'), true);
	}
	add_action('wp_enqueue_scripts', __NAMESPACE__ . '\\assets', 150);

	include_once 'my-functions.php';

}

All of the above applies for add_filter(), add_shortcode() etc as well.

Overriding theme core functions Advanced

Besides preventing conflicts, the PHP namespaces are also good for overriding Chap theme’s pluggable functions.

Hypothetically if you were looking around Chap source code for a way to add some text before the header you would come across this “pluggable function”:

PHP
/chap/lib/template-functions/action-chap-render-header.php
<?php

namespace Chap\TemplateFunctions;
use Chap\Options;
use Chap\Helpers;

if(!function_exists(__NAMESPACE__ . '\\chap_render_header_open')):
	/**
	 * Renders the header opening tag.
	 */
	function chap_render_header_open() {
		$header_classes = Helpers\classnames([
			'ui',
			'inverted' => Options\get('header_inverted'),
			'segment',
		]);

		?>
		<div class="<?php echo esc_attr($header_classes); ?>">
		<?php
	}
endif;

You couldn’t modify this function directly because theme updates would just overwrite it, but since the function checks whether or not it exists before creating it you could add your own version to the child theme’s functions.php in the same namespace that it originates from, in this case Chap\TemplateFunctions.

PHP
/chap-child/functions.php
<?php

namespace Chap\Child {

	/**
	 * Load the child theme assets.
	 */
	function assets() {
		wp_enqueue_style('chap-child', get_stylesheet_directory_uri() . '/style.css', false, wp_get_theme()->get('Version'));
		wp_enqueue_script('chap-child/js', get_stylesheet_directory_uri() . '/scripts.js', ['chap/js'], wp_get_theme()->get('Version'), true);
	}
	add_action('wp_enqueue_scripts', __NAMESPACE__ . '\\assets', 150);

}

namespace Chap\TemplateFunctions {
	use Chap\Options;
	use Chap\Helpers;

	/**
	 * Custom header opening tag function.
	 */
	function chap_render_header_open() {
		$header_classes = Helpers\classnames([
			'ui',
			'inverted' => Options\get('header_inverted'),
			'segment',
		]);

		?>
		Custom content before header opening tag.
		<div class="<?php echo esc_attr($header_classes); ?>">
		<?php
	}

}

If the function utilizes Chap functions from other namespaces don’t forget to “use” them as well: use Chap\Options;

Alternatively they can be called directly by specifying the full namespace \Chap\Helpers\function():

PHP
/chap-child/functions.php
<?php

namespace Chap\Child {

	/**
	 * Load the child theme assets.
	 */
	function assets() {
		wp_enqueue_style('chap-child', get_stylesheet_directory_uri() . '/style.css', false, wp_get_theme()->get('Version'));
		wp_enqueue_script('chap-child/js', get_stylesheet_directory_uri() . '/scripts.js', ['chap/js'], wp_get_theme()->get('Version'), true);
	}
	add_action('wp_enqueue_scripts', __NAMESPACE__ . '\\assets', 150);

}

namespace Chap\TemplateFunctions {

	/**
	 * Custom header opening tag function.
	 */
	function chap_render_header_open() {
		$header_classes = \Chap\Helpers\classnames([
			'ui',
			'inverted' => \Chap\Options\get('header_inverted'),
			'segment',
		]);

		?>
		Custom content before header opening tag.
		<div class="<?php echo esc_attr($header_classes); ?>">
		<?php
	}

}