Using Advanced Custom Fields for custom styles and scripts

There are a plethora of plugins available in the WordPress repository or for sale online that are advertised as the “Best Solution” for injecting custom styles or scripts into your pages, but there is another trick available that not everyone thinks of even though they probably already use the Advanced Custom Fields (ACF) plugin.

Using ACF and just a little custom code [either inserted into your functions.php, must-use plugin or using a code snippet plugin] that makes it very easy to inject custom CSS and JavaScript into a page, post or custom post type or even a Taxonomy/Term, without adding additional plugins into the mix. In this article, I hope to provide you the tools you need in order to achieve this.

The biggest thing to note about this is these styles and script will have no affect within the Gutenberg editor or your page builder as they will only be rendered and parsed on the front-end of your website.

Step 1: Install ACF (if not already installed)

This step is mostly self-explanatory, but for those that need a little help here lets first navigate to our WordPress admin (https://domain.name/wp-admin/) and login if you have not already done so. Next, navigate to the ‘Plugins > Add New’ from the admin sidebar and in the ‘search’ box type ‘Advanced Custom Fields’. Finally click ‘Install’, then click ‘Activate’.

Step 2: Create Field Group

There are two methods for creating field groups using ACF and ACF Pro, and we will touch on both for this tutorial as i feel it benefits anyone that is interested in learning the ins and outs of ACF.

Create ACF Field Groups using WordPress Admin

From the WordPress admin panel, locate the “Custom Fields” menu and click on it or on the fly-out menu click ‘Add New’

Add New Field Group in Advanced Custom Fields

Clicking the “Add New” button will create a new Field Group. The screen is broken down into three sections: Field Group Title, Field Group Fields and Field Group Settings. Lets first look at the field group title

acf new field group header

Next is the set of fields for the group… you can add as many as you would like by Clicking the ‘Add Field’ button. Each field required a Label, Name and Type and we configure these and other options using the 4 Tabs just below the Field header (bluish bar in screenshot below) labeled: General, Validation, Presentation and Conditional Logic. For our purposes we will look at General and Presentation.

Add new Field Group - Custom Styles and Scripts
New Field Group – Field General Settings

For our example, we will name our field group ‘Custom Styles and Scripts’ and for the first field we will choose ‘Text Area’ as the Field Type, ‘Page Specific Styles’ as the Field Label (note: the field will will be auto-sanitized from the label) and leave the ‘Default Value’ field empty.

Next we will click the ‘Presentation’ tab and enter our options/settings for the field.

Add new Field Group - Field One Part Two
New Field Group – Field Presentation Settings

In this example, we are adding instructions on how to use the field, setting the number of row to five and setting some Placeholder text using the BODY selector. Once you are done configuring the field options, click the ‘Close Field’ button and ‘Save Changes’ at the top right. Finally we will click the ‘Add Field’ button and build out our second field (Page Specific Scripts) using the same process as above,

Note: The field label is visible when entering content but is not used by the API, use capitals and spaces for a human friendly field label.

Moving on to the Field Group Settings section, you will note three tabs (Location Rules, Presentation and Group Settings).

acf create fields location rules
Field Group Settings – Location Rules

For our example, we re only going to use the Location Rules (these rule define when and where to add these fields to the edit screen / post object).

Note: Location rules can be grouped together to create any combination of and/or statements.

For our example, we are going to use ‘Post Type Is Equal To Page’ OR ‘Post Type Is Equal To Post’, this will limit the custom fields to only be available to Single Pages and Posts on our site.

Create ACF Field Groups using PHP Code

For this method, we will be referring to the official ACF Documentation to ensure proper implementation of Local Field Groups.

To register a field group we need to start with the basics:

function cpwd_register_fields() {
    if( ! function_exists('acf_add_local_field_group') ) return;
    acf_add_local_field_group([
      'key' => 'group_my_fields',
      'title' => __('My fields', 'txtdomain'),
      'label_placement' => 'top',
      'menu_order' => 0,
      'style' => 'default',
      'position' => 'normal',
      'fields' => [],
      'location' => [],
      'instruction_placement' => 'label',
      'hide_on_screen' => '',
    ]);
}
add_action( 'acf/init', 'cpwd_register_fields' );

Here we hook into the ACF Init action, and call our custom hook that first checks if the function exists and then we register our local field group. The skeleton code includes all the configuration options, but the minimal required elements include Key, Title, Fields and Location.

With all that out of the way, lets create the code to generate our Style and Script fields. For simplicity, I am only going to replace the ‘acf_add_local_field_group’ definition.

acf_add_local_field_group([
	'key' => 'cpwd_styles_scripts',
	'title' => __( 'Page Specific Styles and Scripts', 'cpwd' ),
	'label_placement' => 'top',
	'menu_order' => 0,
	'style' => 'default',
	'position' => 'normal',
	'fields' => [
		[
			'key' => 'page_specific_styles',
			'label' => 'Page Specific Styles',
			'name' => 'page_specific_styles',
			'type' => 'textarea',
			'rows' => 4,
			'new_lines' => '',
			'instructions' => 'Type your CSS code in the box, there is no need to include the STYLE tag.',
			'placeholder' => 'BODY{}',
		],
		[
			'key' => 'page_specific_scripts',
			'label' => 'Page Specific Scripts',
			'name' => 'page_specific_scripts',
			'type' => 'textarea',
			'rows' => 4,
			'new_lines' => '',
			'instructions' => 'Type your JavaScript code in the box, there is no need to include the SCRIPT tag.',
			'placeholder' => '(($) => {})(jQuery);',
		],
	],
	'location' => [
		[
			[
				'param' => 'post_type',
				'operator' => '==',
				'value' => 'page'
			]
		].
		[
			[
				'param' => 'post_type',
				'operator' => '==',
				'value' => 'post'
			]
		].
	],
	'instruction_placement' => 'label',
]);

In the code above, we are adding our custom fields to all Pages and Posts via the ‘location’ array.

Step 3: Add our WordPress Hook

Which ever method you prefer (editing your child theme’s functions.php, creating a must-use plugin or using a code snippet plugin), these same functions can be used to inject our custom fields into a page, post or custom post-type.

In our example, we set-up the custom fields to be injects on pages only, so the code below includes a conditional that checks to see if a single page is being requested, otherwise it will return from the function and not inject the custom field data.

The two IF clauses check to make sure that we have data in the custom fields, if the field is empty it will not be injected into the page.

Finally, the use of ‘add_inline_style’ and ‘add_inline_script’ allow as to inject our custom field content with the main style sheet (you need to know the handle to use this method).

function inject_custom_scripts() {
    if( function_exists( 'get_field' ) && $styles = get_field( 'page_specific_styles' ) ):
        add_inline_style( 'main-css-handle', trim( $styles ) );
    endif;
    if( function_exists( 'get_field' ) && $scripts = get_field( 'page_specific_scripts' ) ):
        add_inline_script( 'main-js-handle', trim( $scripts ) );
    endif;
}
add_action( 'wp_enqueue_scripts', 'inject_custom_scripts', 11 );

An alternative method would be to use the ‘wp_head’ and ‘wp_footer’ hooks and output the custom field data wrapped within STYLE or SCRIPT tags. You may want to add ‘async’ or ‘defer’ attributes to improve overall page speed scores

function inject_custom_styles() {
    if( ! function_exists( 'get_field' ) || ! is_singular( [ 'page', 'post' ] ) ) return;
    if( false !== ( $styles = get_field( 'page_specific_styles' ) ) ):
        echo '<style>' . trim( $styles ) . '</style>';
    endif;
}
add_action( 'wp_head', 'inject_custom_style', 20 );
function inject_custom_scripts() {
    if( ! function_exists( 'get_field' ) || ! is_singular( [ 'page', 'post' ] ) ) return;
    if( false !== ( $scripts = get_field( 'page_specific_scripts' ) ) ):
        echo '<script>' . trim( $scripts ) . '</script>';
    endif;
}
add_action( 'wp_footer', 'inject_custom_scripts', 20 );

Note: you need the Field Name (the sanitized version that is lowercase and includes the underscore character) for use with the get_field function.

Results

Lets take a look at the final result (both in the editor and on the front-end)…

Bonus Tips

Custom styles and script for Taxonomies/Terms

You can also trigger these fields for Taxonomies and terms (to include WooCommerce Product Categories); in order to do this we need to add an additional Location Rule and change parameters passed to the get_field() function. First, we check that we are on a taxonomy/term, then we get the term object using ‘get_queried_object’ and use the ‘taxonomy’ and ‘term_id’ object properties (concatenated with an underscore) to query the ACF field.

function cpwd_enqueue_taxonomy_assets() {
    if( ! is_tax() ) return;
    $object = get_queried_object();
    if( $styles = get_field( 'page_specific_styles', $object->taxonomy . '_' . $object->term_id ) ):
       add_inline_style( 'main-css-handle', trim( $styles ) );
    endif;
    if( $scripts = get_field( 'page_specific_scripts', $object->taxonomy . '_' . $object->term_id ) ):
        add_inline_script( 'main-js-handle', trim( $scripts ) );
    endif;
}
add_action( 'wp_enqueue_scripts', 'cpwd_enqueue_taxonomy_assets' );

Bundle ACF with your theme

To bundle ACF with your theme, create a folder called ‘includes’ and extract the contents of the ACF Plugin into this folder, then in your functions.php file include the following snippet:

if( !class_exists('acf') ):
  require_once get_theme_file_path( '/includes/advanced_custom_fields/acf.php' );
  // Customize the url setting to fix incorrect asset URLs.
  function my_acf_settings_url( $url ) {
    return get_theme_file_uri( '/includes/advanced_custom_fields/' );
  }
  add_filter( 'acf/settings/url', 'my_acf_settings_url' );
  // (Optional) Hide the ACF admin menu item.
  add_filter( 'acf/settings/show_admin', '__return_false' );
  // When including the PRO plugin, hide the ACF Updates menu
  add_filter( 'acf/settings/show_updates', '__return_false', 100 );
endif;

Note: This methodology can be used for Child Themes as well as standard themes.

Summary

In this tutorial I took you on a deep dive into Advanced Custom Fields by create a field group consisting of two TextAreas that we use for injecting custom CSS and JS into our Pages and Posts. We further discuss how to create the same field group via custom PHP code. Finally, we covered how to use these same field in Taxonomies/Terms as well as how to bundle ACF into our Theme/Child Theme.

To grab the code used in this tutorial, check out our GitHub Repository: https://github.com/CP-Web-Designs/Custom-styles-and-scripts-with-ACF

I really hope that you found this tutorial helpful.


If you found this article helpful, we hope you will share it and provide feedback using the comments form below…

Leave a Reply

Your email address will not be published. Required fields are marked *