Frontend developer focused on inclusive design

HTML attributes in WordPress block

HTML attributes are special words used inside the opening tag of an element, to control the element's behavior or provide additional information about it. In WordPress, they are used in customizing the appearance and behavior of blocks.

Class attribute

By default, each WordPress block is equipped with a class attribute, displaying its specific name like a badge. For instance, the Sortable Entry block is labeled with the wp-block-sortable-entry class.

Here’s how to add additional CSS classes to a WordPress block:

/**
 * Utility to conditionally join classNames together.
 *
 * @see https://www.npmjs.com/package/classnames
 */
import classnames from "classnames";

/**
 * React hook that is used to mark the block wrapper element.
 * It provides all the necessary props like the class name.
 *
 * @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/#useblockprops
 */
useBlockProps.save({
	// Add has-separator class if any of the separator properties exist
		"has-separator": width || style || color,
	}),
}),

In the code example above, we’ve employed classnames, a utility for joining class names, and useBlockProps.save function to add the has-separator class, contingent upon the existence of separator properties.

Style attribute

When set with custom styles, like custom text or background color, a WordPress block also displays a style attribute.

Here’s how to add additional inline styles to a WordPress block:

// Construct style properties based on the separator properties.
const separatorStyles = {
	...(width && { "--wp--sortable-container--separator--width": width }),
	...(style && { "--wp--sortable-container--separator--style": style }),
	...(color && { "--wp--sortable-container--separator--color": color }),
};

// Set additional styles in block.
useBlockProps.save({
	style: {
		...separatorStyles,
	},
}),

In the code snippet, separatorStyles is used to hold additional inline styles.

It checks if width, style, and color have values. If they do, it stores them. Then, useBlockProps.save applies those stored styles to the block. So, if width, style, or color are not given a value, the block won’t have those styles applied.

Custom attributes

WordPress allows to define own custom attributes, specifically data attributes. They can store extra information directly within the HTML, making it accessible to CSS and JavaScript.

Here’s how you can implement a custom attribute:

// Create custom attribute value.
const filterDateAttribute =
		attributes.filter.displayType === "date"
			? `${attributes.filter.dateFilterType}|${attributes.filter.date}|${
					attributes.filter.includeDateTime ? "withTime" : "withoutTime"
			  }`
			: "";

// Create filter-date attribute.
useBlockProps.save({
	"data-filter-date": filterDateAttribute,
}),

In this snippet, filterDateAttribute is being assigned a value based on certain conditions.

If attributes.filter.displayType equals "date", it creates a string that combines dateFilterType, date, and whether or not time is included. This string is then assigned as a value to the data-filter-date attribute of a WordPress block using useBlockProps.save.

If attributes.filter.displayType is not "date", filterDateAttribute stays empty, meaning no data-filter-date attribute is added to the block.

Front-end usage

This custom attribute is not just a passive element. It can be used in frontend JavaScript manipulations. Take a look at the following example:

/**
 * Self-invoking anonymous function to ensure no global variables are created.
 * This function will execute as soon as the script file is loaded.
 */
(function () {
	"use strict"; // Enables strict mode to catch common JavaScript pitfalls.

	/**
	 * Checks if the document is still loading, and initializes the core function
	 * once the DOM is fully loaded. This ensures that all DOM elements are accessible.
	 */
	if ("loading" === document.readyState) {
		// The DOM has not yet been loaded.
		document.addEventListener("DOMContentLoaded", initFilter);
	} else {
		// The DOM has already been loaded.
		initFilter();
	}

	/**
	 * The initCore function is the main function that gets executed once the DOM is loaded.
	 * This function contains the logic to filter and style sortable blocks based on date attributes.
	 */
	function initFilter() {
		// Query all elements with the class .wp-block-sortable-container
		const sortableBlocks = document.querySelectorAll(
			".wp-block-sortable-container",
		);

		// Exit early if there are no sortable blocks on the page
		if (!sortableBlocks.length) {
			return;
		}

		// Iterate over each sortable block container
		sortableBlocks.forEach((container) => {
			// Parse the data-filter-date attribute into individual parts
			const filterData = container.getAttribute("data-filter-date").split("|");

			// Validate the format of the data-filter-date attribute
			if (filterData.length !== 3) {
				console.error(
					"Malformed filter date data, expected 3 segments but got:",
					filterData.length,
					"- Data:",
					container.getAttribute("data-filter-date"),
				);
				return; // Exit early if data is malformed
			}

			// Validate the presence of the date value in the data-filter-date attribute
			if (!filterData[1]) {
				console.error(
					"Missing date value in filter data:",
					container.getAttribute("data-filter-date"),
				);
				return; // Exit early if date is missing
			}

			// Destructure the filter data into meaningful variables
			const filterDateType = filterData[0]; // "on", "before", or "after"
			const filterDateValue = filterData[1]; // The date value as a string
			const includeTime = filterData[2] === "withTime"; // true if time is included, false otherwise.

			// Validate the date value
			const filterDate = new Date(filterDateValue);
			if (isNaN(filterDate.getTime())) {
				console.error("Invalid date:", filterDateValue);
				return; // Exit early if date is invalid
			}
			
			// Rest functionality.
			...
		});
	}
})();

In this code snippet, a self-invoking anonymous function is used to run a script as soon as it’s loaded on the webpage, without creating global variables.

The function checks if the webpage’s Document Object Model (DOM) is fully loaded. If it is, it runs the initFilter function immediately; if it isn’t, it waits until the DOM is ready. This ensures that all elements are accessible when the script runs.

The initFilter function looks for elements with the class .wp-block-sortable-container. If it doesn’t find any, it stops running. If it does find such elements, it looks at each one to get the value of the data-filter-date attribute and splits this value into parts. Then, it checks if this data is in the expected format and if the date value is valid.