Guide Archives - ACF https://www.advancedcustomfields.com/blog/category/guide/ Tue, 23 Dec 2025 12:13:50 +0000 en-US hourly 1 https://wordpress.org/?v=6.8.3 How to Add WooCommerce Custom Checkout Fields: Classic vs Block Methods https://www.advancedcustomfields.com/blog/woocommerce-custom-checkout-fields/ https://www.advancedcustomfields.com/blog/woocommerce-custom-checkout-fields/#respond Wed, 24 Dec 2025 14:00:00 +0000 https://www.advancedcustomfields.com/?post_type=blog&p=702729 Key points: With 4.5 million stores using WooCommerce, a lot of revenue flows through its checkout forms. Friction at that final step is where you lose people. Research backs this up: according to the Baymard Institute, around 18% of people abandon checkout because it feels complicated, and most stores request more fields than they actually […]

The post How to Add WooCommerce Custom Checkout Fields: Classic vs Block Methods appeared first on ACF.

]]>
Key points:

  • WooCommerce has Classic Checkout (PHP) and Checkout block (React), each with different customization methods.
  • Add/remove fields via settings, plugins, or custom PHP code, with plugins offering no-code solutions.
  • Advanced Custom Fields (ACF®) lets you visually define and manage custom fields for checkout with minimal code.
  • ACF works for backend data in Block checkout but requires integration with Block APIs for frontend display.

With 4.5 million stores using WooCommerce, a lot of revenue flows through its checkout forms.

Friction at that final step is where you lose people.

Research backs this up: according to the Baymard Institute, around 18% of people abandon checkout because it feels complicated, and most stores request more fields than they actually need.

WooCommerce ships with sensible defaults like billing, shipping, and order notes, yet stores often ask for more information than customers care to provide. Removing fields that serve no purpose and rewriting unclear text helps shoppers move forward with less friction.

Our goal here is to make it easier for your customers to finish paying without guessing what you want from them.

Understanding WooCommerce checkout: Classic vs Block

WooCommerce offers two checkout systems that behave differently.

The older setup, often called Classic checkout, runs through PHP templates and shows itself whenever a page contains the [woocommerce_checkout] shortcode. This version accepts traditional code snippets and many long-standing tutorials still reference it.

WooCommerce might even give you the option to switch to the Checkout block in one click:

WooCommerce one-click classic to block checkout

The newer system, known as the Checkout block, is built on React and appears in the editor as a block labeled Checkout.

WooCommerce checkout block in Gutenberg

It handles layout and interactions in the browser, which means most PHP hooks that worked in Classic simply do nothing here.

Confusing the two systems leads to issues that look like missing fields or plugins that appear installed yet never apply their changes.

A quick way to avoid that trouble is to confirm which checkout architecture is active before attempting edits or installing tools.

One interesting thing to note is that you can switch between these two options regardless of whether you’re using a block or classic theme.

What you can change in WooCommerce checkout

WooCommerce gives you a lot of control over checkout fields, though how much depends on your approach.

You can:

  • Add new fields to collect information WooCommerce doesn’t ask for by default, like delivery dates, VAT numbers, gift messages, or special instructions.
  • Remove fields you don’t need, such as the second address line or company name.
  • Rearrange fields to match how your customers naturally fill out forms.
  • Rename labels and placeholder text to be clearer or match your brand voice.
  • Change validation rules to make fields required, optional, or conditional based on other inputs.

Three paths get you there:

  1. WooCommerce’s built-in settings – limited but don’t require much technical skill.
  2. Custom code using WooCommerce hooks and filters – flexible but requires PHP knowledge.
  3. Plugins like Advanced Custom Fields (ACF®) – the practical middle ground for most store owners.

What you can change with built-in settings

WooCommerce includes toggles that influence the checkout page, but it doesn’t let you edit the fields directly.

There’s no built-in screen where you add, remove, or rearrange inputs, so the controls you do get work indirectly:

  • Store location settings decide which address fields make sense for your region. If your store only sells domestically, you might see fewer inputs than shops selling internationally. Changing selling locations or the default customer location adjusts which fields WooCommerce thinks are relevant.
  • Shipping settings determine whether a shipping address section appears at all. Stores selling only downloads, or shops offering local pickup without delivery, may not show any shipping address form because WooCommerce knows it isn’t needed.
  • Account settings influence whether customers create an account during checkout. Enabling guest checkout removes username and password prompts, which shortens the form.

These toggles help simplify checkout, but they don’t let you customize individual fields. To remove something, add new inputs, or control which fields are optional, you’ll need either a plugin or custom development.

Main approaches to customizing your WooCommerce checkout

There are several paths you can take to change how WooCommerce checkout works, and each one fits a different level of complexity:

  • Stores running the newer Checkout block rely on a React-based system that offers a neat mobile layout, though bigger changes often require development knowledge.
  • Plugins offer a no-code route with a visual editor, so you can add or adjust inputs without touching templates.
  • Code gives the greatest control, but only applies to Classic checkout, because most PHP hooks do nothing in the Block system. If you tried PHP snippets on a Block-based store, nothing would appear.

Match your needs with the right approach:

Scenario (What to do)What to useWhy it works
Toggle optional address fieldsWooCommerce settingsBuilt in and does not require tools
Add a few simple fieldsFree checkout field editor pluginVisual editor without development work
Add fields that change based on cart or productsConditional plugin or ACF with codeFlexible enough to adapt to data
Configure different checkout layouts for varying needsACF plus custom codeACF stores settings and code handles display
Add inputs that need custom validation or processingCode in Classic or JS APIs in BlocksFull control over logic and saving
Deliver a streamlined mobile checkoutCheckout block with compatible pluginsModern layout tuned for smaller screens

How to add WooCommerce custom checkout fields

The WooCommerce checkout experiences for Block and Classic are built on different technologies, so the method for adding custom fields isn’t interchangeable. PHP hooks won’t work on Block checkout, and JavaScript-based solutions won’t work on Classic.

One thing does apply to both, though: if your store uses High-Performance Order Storage (HPOS), you’ll need to save custom field values with $order->update_meta_data() instead of the older post meta functions.

If you’re using classic checkout

Classic checkout runs on PHP, which means you can customize it using WooCommerce’s built-in hooks like woocommerce_checkout_fields or by overriding template files directly.

Most checkout field tutorials and plugins you’ll find online were written for Classic checkout, so compatibility is rarely an issue. If you need deep customization flexibility – conditional fields, complex validation, tight control over markup – Classic checkout with PHP is still the most capable option.

Method 1: Add custom checkout fields using code

Writing your own code gives you full control over checkout fields, but it requires PHP knowledge and careful attention to WooCommerce’s data handling conventions.

The core hook for field customization is woocommerce_checkout_fields, which passes you an array of all checkout fields organized by section: billing, shipping, account, and order. You can modify this array to add new fields, remove existing ones, or change their properties:

  1. Add a custom field by appending a new array to the appropriate section. Each field needs a type, label, and usually a placeholder and required value. You can add fields to billing, shipping, or the order section, depending on where the data belongs.
  2. Remove a field using unset() on the field key. For example, unsetting billing_company removes the company name field.
  3. Modify a field by changing its array values directly. You can update labels, placeholders, CSS classes, or toggle the required property.
  4. Validate input by hooking into woocommerce_checkout_process and checking submitted values. Use wc_add_notice() to display errors.
  5. Save the data using $order->update_meta_data() inside the woocommerce_checkout_create_order hook. This approach is required for HPOS compatibility.

You can also make fields conditional based on cart contents and style them using CSS classes passed in the field array.

Method 2: Add custom checkout fields using plugins

If PHP isn’t your thing, a checkout field plugin handles the technical work and gives you a visual interface for managing fields.

Two popular options are Checkout Field Editor for WooCommerce and Flexible Checkout Fields. Both let you add, edit, reorder, and remove fields using a drag-and-drop UI. They support a wide range of field types, including:

  • Text
  • Email
  • Textarea
  • Select dropdowns
  • Radio buttons
  • Checkboxes
  • Date pickers
  • Color pickers

Most field editor plugins also include conditional logic. You can show or hide fields based on products in the cart, product categories, cart total, shipping method, or user role. This streamlines checkout by only asking relevant questions.

Custom field data typically flows through to order confirmation emails, the admin order screen, and CSV exports, though you’ll want to verify this works as expected for your setup.

  1. With the plugin installed and activated, go to WooCommerce > Checkout Form.
  2. In the Checkout Fields tab, switch to the Classic Checkout option.

Switching between block and classic checkout in Checkout Fields Editor

  1. Click Add Field and add your custom field’s details, with unique names and useful labels, then click Save & Close.

Creating custom checkout fields with Checkout Field Editor

  1. Drag the field where you want it to appear, then save your changes.
  2. Load up the checkout page and confirm it works.

A custom checkout radio field with Checkout Field Editor

If the field doesn’t show, your site is probably using the Checkout block. To switch to classic:

  1. Go to Pages > All Pages and find the checkout page. 
  2. Open it, delete the Checkout block, search for and add the Classic Checkout block. 
  3. If this isn’t available, add a shortcode block with \[woocommerce_checkout].
  4. Save.

⚠A few things can go wrong when using this method.

Theme conflicts sometimes break field display, especially with heavily styled themes. Plugin conflicts can occur if you’re running multiple checkout customization tools. And not all plugins support HPOS yet, so check compatibility before installing. When troubleshooting, disable other plugins temporarily to isolate the issue.

Method 3: Add advanced checkout fields using ACF

ACF sits between hand-coded PHP and scope-limited checkout plugins.

You get a proper UI for defining fields, but with enough flexibility to handle complex requirements, and you won’t outgrow it as your needs evolve.

Say you sell custom engraved products and need to collect engraving text, font choice, and a preview approval checkbox, but only for products in a specific category. ACF lets you define this field group once in the admin, then display it conditionally at checkout with a small snippet of code.

ACF isn’t checkout-specific, which makes it more versatile than single-purpose plugins.

The same field management interface works for product pages, user profiles, settings screens, and more. If you’re already using ACF elsewhere in your store (like for adding custom fields to WooCommerce products), extending it to checkout keeps your workflow consistent.

The setup has two parts: defining the field in ACF’s visual interface, then adding a small code snippet to display and save it.

To create a radio where the customer can choose when they want the order delivered to them from three options.

First, create the field group:

  1. Go to ACF > Field Groups and click Add New. Name it something descriptive like “Delivery window.”
  2. Click Add Field. For this example, set the field type to Radio Button, the label to “Preferred delivery time,” to get a matching field name, then add the options.

ACF delivery window field group for checkout

  1. Add any other fields you need to this group. ACF’s interface lets you set field widths, instructions, and default values, all without code.
  2. To ensure the field doesn’t show up all over your backend, set the location rules to Page is equal to Checkout.

ACF checkout field location rules

  1. Publish the field group.

Next, add the code to display and save the field. This goes in your theme’s functions.php file, code snippet, or a custom plugin. If you’re not comfortable with any of these options, ask your developer to handle this step.

It’s a quick enough job and you’ll usually only need to do it once.

The first part involves adding a radio field to the classic WooCommerce checkout form, under the order notes. Customers see a group labeled “Preferred delivery time” with three choices – Morning, Afternoon, and Evening:

add_action( 'woocommerce_after_order_notes', 'my_delivery_time_field' );
function my_delivery_time_field( $checkout ) {

    woocommerce_form_field( 'preferred_delivery_time', array(
        'type'     => 'radio',
        'label'    => __( 'Preferred delivery time', 'textdomain' ),
        'required' => true,
        'options'  => array(
            'morning'   => __( 'Morning', 'textdomain' ),
            'afternoon' => __( 'Afternoon', 'textdomain' ),
            'evening'   => __( 'Evening', 'textdomain' ),
        ),
        'class' => array( 'form-row-wide' ),
    ), $checkout->get_value( 'preferred_delivery_time' ) );
}

ACF radio button field in checkout for preferred delivery time

Then, take the customer’s selection from the checkout form and store it as order meta, using the key _preferred_delivery_time. That way, the information is permanently attached to the order in the database:

add_action( 'woocommerce_checkout_create_order', 'my_save_delivery_time_field', 10, 2 );
function my_save_delivery_time_field( $order, $data ) {

    if ( ! empty( $_POST['preferred_delivery_time'] ) ) {
        $order->update_meta_data(
            '_preferred_delivery_time',
            sanitize_text_field( $_POST['preferred_delivery_time'] )
        );
    }
}

Finally, display the saved preferred delivery time in the WooCommerce order edit screen, underneath the billing address. Converts the stored value (morning, afternoon, evening) into a human-friendly label before outputting it:

add_action( 'woocommerce_admin_order_data_after_billing_address', 'my_show_delivery_time_admin' );
function my_show_delivery_time_admin( $order ) {

    $time = $order->get_meta( '_preferred_delivery_time' );

    if ( $time ) {
        $labels = array(
            'morning'   => __( 'Morning', 'textdomain' ),
            'afternoon' => __( 'Afternoon', 'textdomain' ),
            'evening'   => __( 'Evening', 'textdomain' ),
        );

        echo '<p><strong>' . __( 'Preferred delivery time', 'textdomain' ) . ':</strong> ' 
            . esc_html( $labels[ $time ] ?? $time ) . '</p>';
    }
}

Once that’s in place, test the full flow: add a product to cart, go through checkout, choose your preferred delivery time, and confirm it appears in the order details.

ACF custom field data for preferred delivery time on the admin order screen

The real value of ACF shows up when you need to change things later.

Adding a new field or adjusting options happens in the ACF interface, with no code changes required. You only touch PHP when you need to display the field somewhere new or change where it appears on the page.

Supercharge Your Website With Premium Features Using ACF PRO

Speed up your workflow and unlock features to better develop websites using ACF Blocks and Options Pages, with the Flexible Content, Repeater, Clone, Gallery Fields & More.

Explore Features View Pricing

PRO Features
ACF Blocks
Options Pages
PRO Fields
Repeater
Flexible Content
Gallery
Clone

If you’re using the Checkout block

As we’ve established, the Checkout block is WooCommerce’s newer checkout experience, built on React and the WordPress block editor. You can customize it visually – toggling fields on or off, reordering sections, adding Express Checkout options – without touching code.

That visual simplicity comes with a tradeoff.

Because the Checkout block runs on JavaScript rather than PHP, the classic customization methods don’t work here. You can’t use woocommerce_checkout_fields or template overrides. Advanced customization means working with WooCommerce’s Block extensibility APIs, which require JavaScript and React knowledge.

For developers, those APIs are capable. You get Slots and Fills for inserting custom components, built-in validation hooks, and conditional visibility rules. But the ecosystem is still maturing. Not all checkout plugins and extensions support the Block checkout yet, so check compatibility before committing to this path.

The upside is that the Checkout block delivers better mobile UX out of the box, modern styling that matches the block editor aesthetic, and improved performance. If your store prioritizes an organized, fast checkout and you don’t need heavy customization, it’s a better foundation going forward.

Method 1: Use Block-compatible checkout field plugins

The easiest way to add custom fields to Block checkout is with a plugin built specifically for it. These plugins give you a no-code interface for creating fields that work within the Block architecture.

When evaluating plugins, check for two things:

  • explicit Checkout block support
  • and HPOS compatibility.

Many older checkout field plugins were built for Classic checkout only and won’t function correctly – or at all – with the block version. Plugin listings and documentation usually state block compatibility clearly; if they don’t mention it, assume it’s not supported.

As you might have guessed, Checkout Field Editor for WooCommerce also works here. The process is the same as before, except now you’re working within the Block Checkout section.

The Block Checkout section in Checkout Field Editor

Just like before, the plugin handles rendering inside the Block checkout and should save data in an HPOS-safe way.

Method 2: Use WooCommerce Blocks extensibility APIs

When plugins can’t deliver what you need, WooCommerce’s Block extensibility APIs give you full control – but you’ll need JavaScript and React experience to use them.

The core concept is Slots and Fills. WooCommerce defines specific Slots throughout the Checkout block where you can inject custom React components. Your code registers a Fill that targets a slot, and WooCommerce renders your component in that location.

The general workflow:

  1. Create a React component for your custom field. This handles the UI, user input, and any client-side validation.
  2. Register your component as a Fill targeting the appropriate checkout slot, like woocommerce_blocks_checkout_order_notes_block for the order section.
  3. Access form values and checkout state through WooCommerce’s React context providers. These give you cart data, shipping info, and other checkout state your field might depend on.
  4. Implement validation by hooking into the checkout validation system. You can prevent submission and display errors if your field’s requirements aren’t met.
  5. Save submitted data by sending it to a PHP endpoint that uses $order->update_meta_data() for HPOS compatibility. The JavaScript side passes data, while the PHP side persists it.

This approach is required for anything interactive or dynamic, like fields that update based on selections, real-time validation feedback, or custom UI elements that go beyond standard form inputs.

Where does ACF fit into block-based WooCommerce checkout?

ACF can’t render fields inside the Checkout block on its own. The Block checkout doesn’t process PHP template hooks or shortcodes – it’s a self-contained React application. So ACF’s usual method of displaying fields on the frontend doesn’t apply here.

That doesn’t make ACF useless for Block checkout stores. It’s extremely valuable for backend work: storing configuration options, building admin settings panels, or managing structured data that influences what appears at checkout. You might use ACF to let store admins define which custom fields should exist, what options a dropdown should contain, or which products trigger additional questions.

The pattern is to pair ACF with the Block extensibility APIs. ACF manages the data and admin interface. A custom JavaScript component reads that data (via REST API or localized script data) and renders the appropriate fields in the Checkout block. PHP handles saving the submitted values.

This split approach takes more setup than the all-in-one Classic checkout method, but it keeps your admin experience consistent while working within the Block checkout’s architecture.

WooCommerce custom checkout fields troubleshooting

If you’ve added custom fields using code or a plugin and something isn’t working, these are the most common issues and how to fix them:

  • Custom fields not appearing on checkout usually means you’re using Classic checkout PHP hooks on a store running Block checkout. Switch to a Block-compatible plugin or rebuild your customization using the WooCommerce Blocks extensibility APIs.
  • Field data that disappears after order submission typically results from saving methods that aren’t compatible with High-Performance Order Storage. Update your code to use $order->update_meta_data() instead of update_post_meta(), or verify your plugin explicitly lists HPOS support.
  • Unexpected errors or broken checkout layouts in Block checkout often point to plugin or theme conflicts because the strict JavaScript architecture surfaces incompatibilities that Classic checkout might tolerate. Disable other plugins one by one to isolate the problem, and test with a default theme like Storefront to rule out theme issues.

Troubleshooting Block checkout problems that you can’t pin down gets easier if you temporarily switch back to Classic checkout to see whether the issue is Block-specific. If your fields work on Classic but fail on Block, the problem is compatibility rather than your field configuration.

Deliver conversion-driven checkout flows with ACF

Getting checkout customization right starts with one question: Are you running Classic checkout or Block checkout? That choice determines everything else.

Classic checkout uses PHP hooks and template overrides. Block checkout requires React components and JavaScript APIs.

The methods aren’t interchangeable, and mixing them up is the most common source of problems.

Whichever path you’re on, save custom field data using $order->update_meta_data() to stay compatible with HPOS. This used to be optional, but now it’s the only way WooCommerce handles order data.

Once you’ve matched your approach to your checkout type, the next challenge is keeping things manageable. Conditional fields, product-specific questions, admin-configurable options – complexity adds up fast.

ACF gives you a structured way to handle that complexity.

You define field groups and metadata in a visual interface, then connect them to your checkout through code or Block APIs. As your store grows and checkout requirements change, you’re editing field settings rather than rewriting PHP or JavaScript.

Download ACF and start building checkout forms that scale with your business.

The post How to Add WooCommerce Custom Checkout Fields: Classic vs Block Methods appeared first on ACF.

]]>
https://www.advancedcustomfields.com/blog/woocommerce-custom-checkout-fields/feed/ 0
How to Use ACF Custom Fields in the Block Editor Without Coding https://www.advancedcustomfields.com/blog/use-custom-fields-in-block-editor/ https://www.advancedcustomfields.com/blog/use-custom-fields-in-block-editor/#respond Tue, 23 Dec 2025 12:03:07 +0000 https://www.advancedcustomfields.com/?post_type=blog&p=702708 Key points: The block editor fully supports custom fields, including those from Advanced Custom Fields (ACF®). ACF and native custom fields share the same metadata system – both store data in wp_postmeta – making them inherently compatible with Gutenberg. Most field visibility issues trace back to disabled panels or incorrect location rules, not actual incompatibility. […]

The post How to Use ACF Custom Fields in the Block Editor Without Coding appeared first on ACF.

]]>
Key points:

  • ACF custom fields work with the WordPress Block Editor, storing data in wp_postmeta and ensuring compatibility with Gutenberg.
  • To display ACF fields, enable the native custom fields panel or use block plugins like Blocks for ACF Fields or native block bindings.
  • For complex layouts, ACF PRO’s Blocks feature enables full control over custom block development using just PHP.
  • ACF Blocks provide a scalable solution for projects requiring custom HTML output, dynamic field integration, or complex structures beyond standard block features.

The block editor fully supports custom fields, including those from Advanced Custom Fields (ACF®). ACF and native custom fields share the same metadata system – both store data in wp_postmeta – making them inherently compatible with Gutenberg.

Most field visibility issues trace back to disabled panels or incorrect location rules, not actual incompatibility.

Once you understand why fields aren’t appearing, fixes are straightforward.

We’re going to cover how to set up fields, display them in blocks, pick the right method for your use case, and avoid common pitfalls. We’ll also show you how to view custom field data in the Block editor through block plugins and block bindings.

For complex layouts involving repeaters or custom markup, ACF PRO’s Blocks provide a PHP-based path that doesn’t require React.

If you’re looking to display custom field values on the frontend instead, you can use a page builder like Divi, Bricks, Beaver Builder, and Elementor, all of which offer native ACF integration.

How custom fields in the block editor work

Custom fields are key/value pairs stored in the wp_postmeta table.

Each field creates a row with a meta key (the field name) and a meta value (the data). WordPress has supported this metadata system since long before Gutenberg existed.

ACF uses the same storage mechanism.

The difference is what ACF layers on top: a visual interface for creating fields, validation rules, conditional logic, and structured field definitions that enforce data consistency. Under the hood, an ACF text field and a native custom field store data identically.

This shared foundation means the block editor doesn’t treat ACF fields as foreign objects. They load, save, and query like any other post meta. The complications people encounter usually involve visibility settings and display methods rather than any fundamental compatibility issues.

The native custom fields panel is disabled in Gutenberg by default, and ACF hides it further to reduce confusion.

Here’s how to enable it when you need direct meta access.

How to enable custom fields in WordPress Block Editor

The block editor hides the native custom fields panel by default, but you can enable it in a few easy steps:

  1. Click the three-dot options menu in the top-right corner of the editor.
  2. Select Preferences.
  3. Navigate to the Advanced section.
  4. Toggle Custom Fields to on.

Toggling on custom fields in Gutenberg

  1. Click Show & Reload Page.

The editor refreshes and displays WordPress’s built-in custom fields panel below your content. This panel shows raw meta keys and values attached to the current post. You can add new fields, edit existing values, or delete entries directly.

The native WordPress custom fields panel

If you don’t see the Custom Fields toggle in Preferences, ACF is likely hiding it. The next section explains why and how to restore access.

Why can’t I see custom fields in Gutenberg?

ACF intentionally hides WordPress’s native custom fields panel. This prevents confusion between the raw meta interface and ACF’s structured field groups – two different ways of viewing the same underlying data.

To restore the native panel while keeping ACF active, add this filter to a custom plugin or custom code snippet:

add_filter( 'acf/settings/remove_wp_meta_box', '__return_false' );

This is useful when debugging field values or accessing meta keys that aren’t part of any field group. Most users won’t need it for daily editing, but developers troubleshooting field issues will find it essential.

Do custom fields work with the block editor?

Yes. Native custom fields and ACF fields both load and save normally in Gutenberg. The block editor reads from and writes to wp_postmeta using standard WordPress functions, so any metadata system built on that table works without modification.

ACF adds validation, sanitization, and conditional logic on top of this flow.

When you save a post, ACF processes field values according to your field group settings before storing them as regular post meta. When you load a post, ACF retrieves that meta and formats it for display in its field UI. The storage layer remains unchanged.

Setting up ACF fields

While WordPress includes a basic custom fields interface, it only handles simple key/value pairs without validation, field types, or organizational structure. ACF gives you a proper custom field management system with repeatable workflows.

ACF organizes custom fields into field groups, containers that hold related fields and control where they appear. Each field group has its own location rules, field definitions, and display settings.

To create a field group with ACF:

  1. Go to ACF > Field Groups > Add New.
  2. Give the group a descriptive name that reflects its purpose, like “Product Details” or “Author Bio.”
  3. Add individual fields using the Add Field button.

Creating an ACF author bio field group

  1. Save the group.

Each field needs a label (what editors see) and a name (what developers reference in code). ACF auto-generates the name from your label, but you can customize it. Use lowercase letters with underscores for consistent, predictable template access.

Location rules determine where your field group appears. Set conditions like Post Type is equal to Product or Page Template is equal to Landing Page to target specific content. You can combine multiple rules for precise control – showing fields only on certain post types, user roles, taxonomies, or page templates.

Creating field groups that work for you

Once you’ve created your first field group, a few structural decisions will save you headaches down the road.

Field names should use lowercase letters with underscores for separation (like event_date or product_price).

То eliminate inconsistencies when referencing fields in templates or debugging database entries, avoid:

  • Spaces
  • Hyphens
  • or camelCase

ACF auto-generates names from labels, but we’d recommend reviewing them before saving, just so you’re familiar.

Location rules need precision.

Post Type is equal to Post works for blog content, but adding a second condition like Post Template equals Default prevents fields from appearing on archive pages or custom templates where they don’t belong. Layer conditions intentionally rather than relying on broad rules that might match unintended contexts.

Incorrect location rules are the most common reason fields don’t appear where expected. Double-check these settings first when troubleshooting missing fields.

Prefix field names on larger projects.

Using product_price instead of just price avoids collisions when multiple field groups contain similarly named fields. This will prove critical when querying meta values across different post types or building reusable template partials.

Field type best practices

With the basics of ACF in place, we can now go over some more advanced field configuration choices that will really start to shape your content model as it expands:

  • Match field types to expected data because ACF enforces format rules automatically and eliminates validation headaches. Choose URL fields for links, Date Pickers for dates, Image fields for media, and Email fields for contact addresses.
  • Write descriptive field labels since they serve as inline documentation and reduce editor confusion. Replace vague labels like “Image” with specific instructions like “Featured Product Image (800×600px minimum)” that set clear expectations.
  • Use structured fields where freeform text creates consistency problems over time. Select fields with predefined options prevent typos, Group fields keep related data together, and Repeaters handle variable-length lists like team members or testimonials.
  • Reserve complex field types for genuinely variable data because unnecessary complexity increases editing overhead. Default to simple fields and reach for things like Repeaters or Flexible Content layouts only when your content model actually requires them.

How to display custom field data in the Block Editor

ACF fields appear in their own metaboxes below or beside the main content area. But what if you want to see field values directly within the block editor canvas, alongside your other content blocks?

Two methods let you surface custom field data inside the editing interface: dedicated block plugins and native block bindings. Both display field values as part of your block layout while you work

Method 1: Using dedicated block plugins

Blocks for ACF Fields is a third-party plugin – it’s developed independently and is not affiliated with ACF or WP Engine – that adds blocks for displaying ACF field values directly in the editor canvas. The plugin provides a dropdown interface for selecting which field to surface.

To display a field using Blocks for ACF Fields:

  1. Install and activate the plugin.
  2. Open a post or page that has ACF fields attached. Fill in the fields with values if they’re still blank.
  3. Add a new block and search for “ACF Field.”

The ACF Field block from the Blocks for ACF Fields plugin

  1. Insert the block where you want the field value to appear in your layout.
  2. Select your target field from the dropdown in the block settings panel.

Selecting a target field for Blocks for ACF Fields

The field value appears inline with your other blocks, updating as you edit. Detailed configuration options are documented on the plugin’s directory listing.

Displaying a custom field with Blocks for ACF Fields

Method 2: Using native block bindings

Block bindings connect post meta directly to core block attributes. Instead of adding a dedicated field block, you bind an existing block, like a paragraph or image, to a custom field value. The bound block renders the field’s stored data on the frontend.

WordPress introduced block bindings to support dynamic, data-driven content editing. The feature lets you build layouts where blocks pull their content from metadata rather than manual entry.

To bind an ACF field to a core block:

  1. Add a supported block (paragraph, heading, image, or button) to your content.
  2. Open the Code Editor view for the block.
  3. Add a metadata attribute specifying the bindings source and target field name. Here’s an example for a paragraph bound to a field called achievements:
<!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"acf/field","args":{"key":"achievements"}}}}} -->
<p></p>
<!-- /wp:paragraph -->
  1. Switch back to the Visual Editor. You’ll see a generic “ACF Fields” label rather than your actual field value. To verify the binding works, preview or view the published post.

Block bindings suit single-value text fields in straightforward layouts. A few practical limitations you should note:

  • The editor shows a placeholder instead of the field value, so you lose the visual context that makes the block editor useful.
  • Bindings require hand-editing JSON rather than clicking through a settings panel.
  • Repeaters, Groups, WYSIWYG, and relational fields don’t work.
  • When bindings fail, there’s no error message indicating why.

💡 For editor-visible field values, ACF Blocks may be more practical.

Supercharge Your Website With Premium Features Using ACF PRO

Speed up your workflow and unlock features to better develop websites using ACF Blocks and Options Pages, with the Flexible Content, Repeater, Clone, Gallery Fields & More.

Explore Features View Pricing

PRO Features
ACF Blocks
Options Pages
PRO Fields
Repeater
Flexible Content
Gallery
Clone

Meet ACF Blocks: The scalable path for complex custom fields

Block bindings and Blocks for ACF Fields handle most field types without code, including Repeaters and nested structures for the latter. But you’re working within their boundaries. When you need specific HTML output or conditional logic based on field values, these methods reach hard limits.

ACF Blocks solve this gap. Available as part of ACF PRO, this feature lets you build custom blocks using PHP instead of React. You get full control over output markup while avoiding the JavaScript complexity that makes native block development inaccessible to many WordPress developers.

Unlike block bindings, ACF Blocks let you render your field values live in the editor.

ACF Blocks showing live field data

If your project needs markup that doesn’t fit standard block patterns, or you’d rather not add another plugin dependency, ACF Blocks keep everything within the familiar ACF ecosystem.

When do I need ACF Blocks?

ACF Blocks make sense where your requirements exceed what dropdown selectors and attribute bindings can deliver, like when:

  • Repeater or Flexible Content fields need loops to output variable numbers of items.
  • Custom markup requirements demand precise HTML structure that core blocks can’t produce.
  • Query Loop integration requires fields to work dynamically across multiple posts.
  • Design specifications call for wrapper elements, conditional classes, or nested HTML that no-code tools can’t generate.

How ACF Blocks work

We’ve created an in-depth, beginner-friendly guide to building an ACF Block, covering everything from initial registration to advanced rendering techniques.

In a nutshell, though, the development process combines familiar WordPress patterns with ACF’s field system:

  1. Define block metadata in a block.json file to register the block with the editor.
  2. Create a Field Group with the location rule set to “Block” and target your specific block—this scopes fields to appear only when editing that block.
  3. Render output using a PHP template with standard ACF functions like get_field() and have_rows().

Use custom fields in the block editor with ACF Blocks

Custom fields and the block editor work together without friction once you understand the moving parts.

Enable the native custom fields panel through Preferences when you need direct access to raw metadata. Use dedicated block plugins or native block bindings to surface simple field values within the editor canvas.

When your content model outgrows these approaches, with layouts demanding precise markup and fields that must work inside query loops, ACF Blocks provide the scalable path forward. You write PHP instead of React, using functions you already know.

ACF PRO unlocks Blocks alongside:

  • Repeater fields
  • Flexible Content
  • Options Pages
  • and the Gallery field.

Upgrade to ACF PRO to build custom blocks that match your exact requirements.

The post How to Use ACF Custom Fields in the Block Editor Without Coding appeared first on ACF.

]]>
https://www.advancedcustomfields.com/blog/use-custom-fields-in-block-editor/feed/ 0
How to Add WordPress Custom Post Type Fields https://www.advancedcustomfields.com/blog/wordpress-custom-post-type-fields/ https://www.advancedcustomfields.com/blog/wordpress-custom-post-type-fields/#respond Thu, 18 Dec 2025 12:04:57 +0000 https://www.advancedcustomfields.com/?post_type=blog&p=701244 Key points: Adding custom fields to your custom post types (CPTs) is a great way to organize and manage data in WordPress. But while the data gets saved in the database, you can’t do much with it unless everything is properly set up. To unlock the full potential here, you’ll need to handle a few […]

The post How to Add WordPress Custom Post Type Fields appeared first on ACF.

]]>
Key points:

  • Custom post types store structured content, while their fields hold the actual data you display or filter.
  • Coding fields manually means registering meta, building UI, validating input, querying, and rendering values yourself.
  • That workflow is powerful but fragile; small mistakes lead to missing data or broken templates.
  • Advanced Custom Fields (ACF®) replaces all that wiring with a UI, automatic saving, and simple template helpers.

Adding custom fields to your custom post types (CPTs) is a great way to organize and manage data in WordPress.

But while the data gets saved in the database, you can’t do much with it unless everything is properly set up.

To unlock the full potential here, you’ll need to handle a few key steps on the backend first: 

  • Registering the fields
  • Creating a simple interface for adding data
  • Ensuring everything is saved properly
  • Then displaying it on the frontend

Next steps are to learn the manual process for handling WordPress custom post type fields, or go with a more automated way using Advanced Custom Fields (ACF®).

Let’s get started.

How custom post types and their fields work

Custom post types are WordPress content containers you create when posts and pages don’t fit the job. They hold structured data like products, events, portfolio items, or property listings.

If you’ve seen the term “custom content type,” it’s simply another name for the same thing – WordPress’s actual implementation calls them custom post types.

Custom fields are the individual data points stored inside those posts – things like price, date, number of bedrooms, or square footage.

On a real estate site, for instance, you might register a Properties post type to separate listings from your blog.

Each property needs a price, number of bedrooms, square footage, and maybe a map location. Those values don’t belong in the title or main editor field. They need their own fields, which WordPress stores separately in post meta.

WordPress custom fields for a real estate property showing input fields for Property price, Bedrooms, Square footage, and Current status in the post editor.

Understand this separation, and the workflow makes more sense: the post type defines the content category, while custom fields hold the specific facts you want to display or filter by.

How to register a custom post type

Registering a custom post type is likely familiar territory, but we’ll still do a quick pass before we move into field handling.

If you prefer a more straightforward UI approach, ACF includes CPT creation – our dedicated guide to creating a custom post type walks through that in detail.

In short, though: go to ACF > Post Types > Add New, set a name, choose labels, and decide which features it supports (title, editor, thumbnail, etc.).

Creating a custom post type using ACF

Publish it, and WordPress adds it to the admin menu automatically.

If you want instead to build CPTs in code, we also have a more in-depth guide to WordPress custom post types. In a nutshell:

  1. Call register_post_type() inside a must-use plugin or a custom code snippet. 
  2. Set labels to define the admin UI text.
  3. Use supports to determine available editing features.
  4. Configure has_archive to control whether an archive page exists. 
  5. If you want WordPress’s built-in Custom Fields box to show up, add 'supports' => ['custom-fields'] – it appears in the classic editor and Gutenberg’s screen options.

That said, many modern setups skip the legacy metabox and rely instead on explicitly registering fields using register_post_meta(). It gives better control, REST visibility, and block editor integration.

Either way, the important point is: registering a CPT just creates a container. It doesn’t give you field storage, editing screens, or display logic. That’s what we’re covering next.

How to add WordPress custom post type fields using code

We’ll cover for adding usable fields to custom post types: register the field, show it in the editor, save the value, and output it in your template. 

If you prefer a UI-based workflow, you can let ACF handle most of this. Skip the manual approach and jump ahead.

Registering custom fields

To register a custom field properly, you define it with register_post_meta(). This tells WordPress what the field is, how it should behave, and how it should be stored:

add_action( 'init', function () {
    register_post_meta( 'property', 'price', [
        'type'              => 'number',
        'single'            => true,
        'sanitize_callback' => 'floatval',
        'show_in_rest'      => true,
    ] );
} );

Here, property is the post type and price is the field name. Setting the type helps WordPress validate and cast values correctly. The single parameter tells it to store one value instead of multiple entries. A sanitized callback ensures bad or unexpected data doesn’t end up in your database.

Finally, show_in_rest makes the field available in the block editor and via the API, which matters if you are using Gutenberg or building a headless frontend.

Without this step, WordPress would just treat a field as unstructured meta with no rules attached.

Creating an admin interface for custom fields

If you need a custom interface for entering field values, add a metabox.

WordPress doesn’t create one for register_post_meta(), so you build it yourself:

add_action( 'add_meta_boxes', function () {
    add_meta_box( 'property_price', 'Property Price', 'property_price_box', 'property' );
} );

function property_price_box( $post ) {
    wp_nonce_field( 'save_price', 'price_nonce' );
    $value = get_post_meta( $post->ID, 'price', true );
    echo '<input type="number" name="price" value="' . esc_attr( $value ) . '" />';
}

This attaches a box to the Property CPT editor screen.

Adding a metabox for a CPT custom field

Inside the callback, you load the stored value with get_post_meta() so editors can update it, output a nonce for security, and render the input field.

You only add metaboxes when the default UI isn’t enough or when you want a controlled layout. This complements the registration step by giving editors a clear place to enter data.

Saving field values securely

To store the value, hook into save_post and make sure the request is legitimate:

add_action( 'save_post_property', function ( $post_id ) {
    if ( ! isset( $_POST['price_nonce'] ) || ! wp_verify_nonce( $_POST['price_nonce'], 'save_price' ) ) {
        return;
    }
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        return;
    }
    if ( ! current_user_can( 'edit_post', $post_id ) ) {
        return;
    }

    $value = isset( $_POST['price'] ) ? floatval( $_POST['price'] ) : null;
    update_post_meta( $post_id, 'price', $value );
} );

This checks the nonce, skips autosaves, and verifies user permissions before doing anything. The input is sanitized based on the field’s expected type, then stored with update_post_meta().

If you registered the field with a sanitize callback, WordPress will also enforce cleanup automatically.

Displaying custom field values on the frontend

To show your field on the frontend, call get_post_meta() inside your template:

$price = get_post_meta( get_the_ID(), 'price', true );
if ( $price ) {
    echo '<p>Price: ' . esc_html( number_format( $price ) ) . '</p>';
}

This reads the stored value for the current post. You handle formatting yourself. Maybe add a currency symbol or wrap it in markup. Always escape output so untrusted data doesn’t leak into the page; esc_html() works for text, esc_attr() for attributes, and wp_kses() for controlled HTML.

If you enabled show_in_rest when registering the field, the value also appears in the block editor sidebar and in REST API responses. That makes it usable for Gutenberg blocks, headless frontends, or external integrations.

Querying posts by custom field value

You can filter posts by field values using WP_Query and a meta_query. For example, to list properties priced under $500,000:

$query = new WP_Query([
    'post_type'  => 'property',
    'meta_query' => [
        [
            'key'     => 'price',
            'value'   => 500000,
            'compare' => '<',
            'type'    => 'NUMERIC',
        ],
    ],
]);

meta_query supports comparisons like =, !=, <, >, BETWEEN, and LIKE, so you can match ranges, search text, or filter content by category. This works with fields created via register_post_meta() or normal post meta.

You’ll use this pattern anytime you need dynamic listings, e.g., showing events after today or powering custom search pages.

Managing custom post type fields with ACF (the faster way)

Writing meta logic yourself works, but it’s fragile. One missed capability check or sanitize step can create bugs you don’t notice until something in your workflow fails.

ACF exists to eliminate that risk.

It gives you a UI, builds the metaboxes, saves values correctly, and keeps things consistent across projects. That’s why most agencies default to it once they’ve had enough of debugging their own field code.

Supercharge Your Website With Premium Features Using ACF PRO

Speed up your workflow and unlock features to better develop websites using ACF Blocks and Options Pages, with the Flexible Content, Repeater, Clone, Gallery Fields & More.

Explore Features View Pricing

PRO Features
ACF Blocks
Options Pages
PRO Fields
Repeater
Flexible Content
Gallery
Clone

Adding fields for a CPT in ACF takes a handful of actions:

  1. Open ACF > Field Groups > Add New.
  2. Create your fields from 30+ field types with the correct types, labels, and names.
  3. Set a location rule so the group appears only on your CPT. You can see the location rules at the bottom of the page here:

ACF location rules for property CPT

  1. Save the group.

That’s it.

The editor screen will now show usable inputs without requiring you to wire anything up.

ACF-created CPT custom fields in WordPress block editor

ACF writes the meta, validates it, and stores it.

For a complete walkthrough of creating custom post types and fields with ACF, including how to display them in your theme, you can watch this tutorial:

If you’re using a major page builder such as WPBakery, Bricks, or Beaver Builder, you can display these fields on the frontend without touching any code.

If you build themes manually instead, ACF gives you get_field() to fetch values and the_field() to output them, so you don’t have to write the retrieval and display logic yourself.

When you’re managing sites for repeat clients, reliability like this goes a long way.

Troubleshooting issues with fields not displaying

Building custom fields by hand invites breakage. ACF sidesteps most of these problems, but if you’re going the DIY route, here’s what to watch for, and what to do:

  • Field group location rules misconfigured means your fields don’t appear because WordPress doesn’t think they belong to that post type. Fix it by correcting the location rules so they target the right CPT.
  • Template file not loading happens when you edit a parent theme file while a child theme actually controls output. Move your changes into the active child theme template.
  • Code outside the loop occurs when retrieval runs before WordPress knows which post is being displayed. Wrap your calls inside the Loop or pass the correct post ID manually.
  • Caching masking updates means stored values exist, but the frontend or editor shows stale data due to object or page cache. Clear all caches after registering fields or saving meta.
  • Hidden UI panels occur when the Screen Options toggle disables field visibility. Enable the panel at the top of the editor.
  • Permalinks not refreshed lead to CPT routing issues and missing fields. Visit Settings > Permalinks and click Save.
  • Data exists but isn’t showing typically means your logic fails silently because you’re referencing the wrong field name or context. Dump values with var_dump( get_post_meta( $post->ID ) ) or var_dump( get_field( 'field_name' ) ) to verify before debugging templates.

Let ACF handle your custom post type fields

Custom fields turn generic post types into structured, queryable content.

You can build the system yourself – register meta, create metaboxes, handle sanitization, and write template logic – but every step is another place for things to break. ACF handles all of that for you.

ACF handles the repetitive, error-prone parts of custom fields – the sanitization, validation, and security checks – so developers can focus on building the features that make their projects stand out. It’s about freeing you up to do your best work.

Liam Gladdy, Senior Software Engineer at ACF and WP Engine.

Define fields visually, attach them to any post type, retrieve values with clean functions, and skip the fragile wiring entirely. You avoid nonce juggling, capability checks you might miss, sanitization errors, and site-breaking failures from referencing the wrong key.

If you’re building a single site or managing dozens for clients, ACF gives you a workflow that scales reliably.

When you’re ready to simplify your custom field workflow, download ACF and start building more fine-tuned WordPress sites.

The post How to Add WordPress Custom Post Type Fields appeared first on ACF.

]]>
https://www.advancedcustomfields.com/blog/wordpress-custom-post-type-fields/feed/ 0
Troubleshoot Admin AJAX PHP WordPress Issues https://www.advancedcustomfields.com/blog/admin-ajax-php-wordpress/ https://www.advancedcustomfields.com/blog/admin-ajax-php-wordpress/#respond Tue, 16 Sep 2025 12:00:00 +0000 https://www.advancedcustomfields.com/?post_type=blog&p=664267 Key points: When admin-ajax.php is consuming massive resources on your WordPress site, it’s frustrating. The deeper you dig, the more it seems like core WordPress code is at fault, but the real issue can be more elusive. Imagine a busy restaurant kitchen with a single door through which all the waiters pass to reach the […]

The post Troubleshoot Admin AJAX PHP WordPress Issues appeared first on ACF.

]]>
Key points:

  • admin-ajax.php bottlenecks because every request loads WordPress, hides plugin origins, and strains under high-frequency calls.
  • Trace problems with Network tab, Query Monitor’s Caller column, and error logs to pinpoint the exact action and cause.
  • Optimize at the action level with caching, pagination, throttling, REST migration, and nonce validation, then validate gains with before/after metrics.

When admin-ajax.php is consuming massive resources on your WordPress site, it’s frustrating. The deeper you dig, the more it seems like core WordPress code is at fault, but the real issue can be more elusive.

Imagine a busy restaurant kitchen with a single door through which all the waiters pass to reach the seating area. When service slows down, focusing on the door doesn’t tell you which waiter is causing the holdup. Similarly, admin-ajax.php processes requests for many different features, so when performance suffers, it’s not always clear which request or plugin is the problem.

Join us as we break down how admin-ajax.php works, common performance issues it causes, and how to troubleshoot and optimize it effectively for your WordPress site.

Why admin-ajax.php becomes your WordPress bottleneck

admin-ajax.php handles asynchronous requests in WordPress, but it can quickly become a performance bottleneck if not optimized.

Each AJAX call triggers the entire WordPress environment – core files, active plugins, and the theme. This means that PHP must execute heavy bootstrap logic for every request, which can be resource-intensive. On top of that, database queries are often run repeatedly without built-in caching, causing unnecessary load on the server.

High-frequency requests, such as polling or auto-refreshing, amplify the problem by increasing the strain on the server.

Additionally, while AJAX requests are asynchronous from the browser’s perspective, admin-ajax.php handles them sequentially on the server, which can create bottlenecks during high traffic periods.

This can lead to delays, especially when multiple requests are made simultaneously. As a result, poorly optimized AJAX calls can slow down your site and overwhelm your server.

Find exactly which plugin hammers admin-ajax.php

When admin-ajax.php is causing performance issues, pinpointing the exact plugin responsible can be tricky. Here’s a step-by-step guide to help you identify the culprit:

  1. Open your browser’s developer tools and navigate to the Network tab. Filter the results by admin-ajax.php to focus solely on AJAX requests.

Admin ajax php network requests

  1. Look at the frequency of requests and their payloads. Frequent calls or large payloads can give you clues about which action is causing the load.
  2. Each AJAX request includes an action parameter (e.g., action=plugin_hook_name). This identifies the hook or function being triggered. Take note of this value.
  3. Once you’ve identified the action parameter, look it up in the plugin’s documentation or code to determine which plugin is responsible.
  4. If the plugin is unclear, disable your plugins one by one and monitor the Network tab until you see a reduction in admin-ajax.php traffic.

For a more detailed approach, use the Query Monitor plugin. The Queries by Caller column will show you which hook or function triggered the AJAX request.

Query Monitor queries by caller

For example, with the relationship field available in Advanced Custom Fields (ACF®), you might see something like this:

  • Action: acf/fields/relationship/query
  • File: advanced-custom-fields-pro/includes/fields/class-acf-field-relationship.php:585

This tells you exactly which file and line in the plugin is executing the query, making it easier to identify and optimize the problem area.

Supercharge Your Website With Premium Features Using ACF PRO

Speed up your workflow and unlock features to better develop websites using ACF Blocks and Options Pages, with the Flexible Content, Repeater, Clone, Gallery Fields & More.

Explore Features View Pricing

PRO Features
ACF Blocks
Options Pages
PRO Fields
Repeater
Flexible Content
Gallery
Clone

Decode your specific admin-ajax.php error messages

When you encounter issues with admin-ajax.php, deciphering the error messages can help you quickly pinpoint the root cause. Here’s how to locate said error messages for troubleshooting:

  1. Click a request and open its Response tab in your browser’s developer tools to view the raw error output. This will show you the server’s response to the AJAX request, including any error messages.
  2. Look for these common error codes:
    • 0 (Generic Failure) is a vague error indicating something went wrong without specific details.
    • -1 (Unauthorized) typically indicates a permission or nonce issue.
    • PHP warnings/notices can point to issues in the PHP code like undefined variables, function issues, or deprecated functions.
  3. In the request payload, locate the action parameter (e.g., action=plugin_hook_name). Trace this to the specific function hooked to that action in the theme or plugin code for a clearer idea of where the issue originates.
  4. Enable WP_DEBUG in your wp-config.php file and check the error logs for more detailed information, such as stack traces. These logs will show the exact point of failure.

Here are a few clues you might spot in the logs and what they mean:

  • Memory exhausted (e.g., acf-field-relationship.php:585) could indicate that the query is too large and exceeds the available memory. Solutions include paginating the query or implementing caching to reduce the load.
  • Max execution time (e.g., class-wpdb.php) suggests slow database joins or inefficient queries. Consider optimizing your queries or adding indexes to speed up database operations.
  • Undefined function (e.g., ajax-handlers.php) may indicate a missing include or incorrect file path. Ensure that all necessary files are loaded correctly and included at the right places in your code.
  • Nginx upstream timed out happens when the PHP worker is stuck on a slow action. It could be caused by a resource-intensive operation in the plugin or theme. Review your PHP logic or optimize slow actions.

Once you’ve identified the specific error, cross-reference it with the plugin or theme code. Common issues include faulty logic, missing or incorrect nonces, or poorly optimized database queries.

Optimize admin-ajax.php for your actual bottleneck

Most performance issues stem from specific bottlenecks that you can address if you:

  • Identify the slow action by opening your browser’s Network tab and locating the admin-ajax.php request with the longest response time. Check the action parameter in the request payload to pinpoint exactly which handler needs optimization.
  • Reduce database query load by adding indexes to frequently searched columns, implementing result caching with transients, and limiting row counts. Large datasets should use pagination instead of loading thousands of records in a single request.
  • Cut WordPress bootstrap overhead by moving non-urgent operations to wp-cron jobs or background processing queues. Heavy initialization logic doesn’t belong in AJAX handlers that need to respond quickly to user interactions.
  • Control request frequency through client-side throttling, extended Heartbeat intervals, and input debouncing. Rapid-fire requests from users or polling scripts can overwhelm your server even with optimized handlers.
  • Cache repeated results using WordPress transients for database queries, object caching for expensive computations, or static JSON files for predictable responses. Aggressive caching transforms slow dynamic requests into fast static responses.
  • Offload work by migrating high-frequency actions to REST API endpoints or custom handlers that bypass full WordPress initialization. admin-ajax.php should handle admin-specific functionality, not public-facing features.

When to migrate from admin-ajax.php to REST API

The WordPress REST API can be used as an alternative to admin-ajax.php because it provides a more flexible, modern, and scalable way to handle asynchronous requests with JSON responses, making it easier to integrate with frontend JavaScript and third-party applications.

That said, migration isn’t always necessary or beneficial. Evaluate based on your use case, since high request volume with small payloads favors REST API, while complex authentication or large data transfers may not.

Looking at performance benchmarks by experts, you’ll see REST API deliver moderately faster response times than admin-ajax.php on vanilla WordPress installations, with improvements becoming less pronounced on plugin-heavy sites. Custom must-use endpoints can achieve significantly faster response times than either option, but require more development effort.

Consider that performance gains vary significantly across different WordPress environments and plugin loads. Sites with many active plugins see smaller performance improvements when switching to REST API, while custom endpoints consistently deliver the fastest response times across all configurations.

Choose REST API when you have high request volume, small payloads, and need modern HTTP standards support. The clearer URL structure and built-in caching headers make REST ideal for public-facing functionality and mobile applications.

Maintain admin-ajax.php in parallel if you need legacy browser compatibility or have existing integrations that can’t be immediately updated. Running both endpoints during migration allows gradual rollout without breaking existing functionality.

Consider custom must-use endpoints for extreme performance requirements where neither admin-ajax.php nor REST API meets your speed needs. These bypass most WordPress initialization overhead but require more development effort and careful security implementation.

Convert existing admin-ajax handlers to REST endpoints by registering routes with register_rest_route() and updating client-side calls. For ACF relationship fields, for example, replace your admin-ajax handler:

add_action('rest_api_init', function() {

    register_rest_route('my/v1', 'acf-rel', [

        'methods' => 'GET',

        'permission_callback' => '__return_true',

        'callback' => 'my_acf_rel_rest'

    ]);

});

function my_acf_rel_rest(WP_REST_Request $request) {

    $search = sanitize_text_field($request['search']);

    $results = my_acf_relationship_query($search);

    return rest_ensure_response($results);

}

Then update your JavaScript from jQuery.post() to wp.apiFetch({path: '/my/v1/acf-rel?search=foo'}).

Plan for refactoring complexity since you’ll need to replace nonce verification with REST permissions, handle potential CORS issues, and update all client-side code. Maintaining backward compatibility during rollout often means running duplicate endpoints temporarily.

Secure your admin-ajax.php endpoints without breaking functionality

Focus your security efforts on the endpoints that actually need protection rather than applying blanket restrictions:

  • Target only high-risk actions that process sensitive data or perform destructive operations. Low-risk functionality like search suggestions or content filtering doesn’t require the same protection level as user registration or payment processing.
  • Add nonces to forms using wp_create_nonce('my_action') in your HTML and verify with check_ajax_referer('my_action') in your handler. This prevents cross-site request forgery attacks while maintaining smooth functionality for legitimate users.
  • Implement nonce fields as hidden form inputs or data attributes, then validate them before processing any requests. For contact forms, add data-nonce="<?php echo wp_create_nonce('contact_form'); ?>" to your form element and verify with check_ajax_referer('contact_form') in your PHP callback.
  • Balance security with usability by implementing nonce refresh mechanisms for logged-out users instead of hard failures. Expired nonces should trigger JavaScript to fetch a fresh nonce rather than completely blocking the user’s action.
  • Preserve anonymous access for public-facing features while still validating request legitimacy through nonces or capability checks. Contact forms and newsletter signups should remain accessible to visitors, but always verify intent before processing their data.

Your admin-ajax.php action plan for tomorrow

Admin-ajax.php can quickly become a performance bottleneck due to inefficient queries and excessive API calls. Apply our targeted optimizations to address query handling, server strain, and overall site responsiveness:

  • Optimize queries to cut slow requests, achieving up to an 80% improvement in speed. This reduces bottlenecks and ensures faster response times for both users and administrators.
  • Limit WordPress heartbeat API calls from over 30 per second down to 10–15 per second. This adjustment lowers unnecessary server chatter while maintaining real-time functionality.
  • Throttle requests to reduce simultaneous admin-ajax.php calls. This decreases server strain, stabilizes performance, and improves site reliability under traffic spikes.
  • Shift from reactive troubleshooting to a proactive, metrics-based optimization strategy. Monitoring performance trends allows you to prevent issues before they escalate and maintain consistent site health.

To get you started, here’s a phased approach that outlines a structured workflow for diagnosing, resolving, and validating admin-ajax.php performance issues, ensuring each optimization is measurable and results are clearly communicated:

PhaseAction itemDetails
Identify critical issuesCheck slow ACF queriesUse Query Monitor to identify queries >1000ms
Review Heartbeat APIMonitor for calls exceeding 30 requests per second
Analyze admin-ajax.php requestsLook for excessive requests overloading server
Identify slow database queriesFind queries that could benefit from optimization
Implement fixesOptimize ACF queriesImplement lazy loading or pagination to reduce query time
Fix Heartbeat API issuesExtend interval between requests or unhook unnecessary callbacks
Reduce high-frequency requestsThrottle or debounce requests to reduce server strain
Optimize database queriesAdd indexes or implement caching
Record metricsTrack query time improvementsMonitor reductions (e.g., 1200ms to 220ms after caching)
Monitor Heartbeat frequencyRecord before/after adjustments (e.g., >30/sec to 10-15/sec)
Communicate resultsStakeholder reportingProvide: Problem > Evidence > Fix > Time > Expected Gain

Admin-ajax.php doesn’t have to be a mystery bottleneck – if you trace requests, optimize queries, throttle frequency, and validate gains with metrics, you’ll eventually turn hidden slowdowns into clear wins. Apply our recommendations consistently, and your WordPress site will run faster, leaner, and more reliably under load.

The post Troubleshoot Admin AJAX PHP WordPress Issues appeared first on ACF.

]]>
https://www.advancedcustomfields.com/blog/admin-ajax-php-wordpress/feed/ 0
Boost Navigation with Custom WordPress Menus https://www.advancedcustomfields.com/blog/custom-menu-wordpress/ https://www.advancedcustomfields.com/blog/custom-menu-wordpress/#respond Mon, 15 Sep 2025 11:27:44 +0000 https://www.advancedcustomfields.com/?post_type=blog&p=664247 Key points: If you’ve been managing WordPress sites since before the Gutenberg editor arrived, you’ve likely noticed that menu creation isn’t as straightforward as it used to be. The familiar Appearance > Menus path now competes with block-based navigation, and finding the right approach for your specific setup can be frustrating. In this article, you’ll […]

The post Boost Navigation with Custom WordPress Menus appeared first on ACF.

]]>
Key points:

  • Build frontend navigation menus using WordPress’s built-in Site Editor/Customizer, mega menu plugins, or custom PHP code for any theme type.
  • Create custom backend menu items using PHP functions to organize admin tools and resources for logged-in users.
  • Use ACF PRO’s Options Pages to build centralized admin pages for managing global site content like contact info across all templates.

If you’ve been managing WordPress sites since before the Gutenberg editor arrived, you’ve likely noticed that menu creation isn’t as straightforward as it used to be. The familiar Appearance > Menus path now competes with block-based navigation, and finding the right approach for your specific setup can be frustrating.

In this article, you’ll learn exactly how to create and manage menus effectively across classic themes, block themes, and hybrid setups. We’ll cover both frontend navigation menus for your site visitors and backend administrative menus for logged-in users and admins.

How WordPress menus work

Let’s start by clearing up the distinction between WordPress menus and headers.

A menu is simply a custom navigation list you create – it’s pure data, a barebones collection of links with no visual formatting. The header, however, is where you assign that menu to your theme’s header area, typically at the top of your site. This assignment layer handles the visual presentation, including mobile responsiveness and styling.

WordPress supports multiple menu types across two main categories:

  • Frontend menus handle site navigation and include the header menu (your primary navigation), footer menus for bottom-of-page links, sidebar menus placed in widget areas, mobile menus optimized for smaller screens, social links menus for social media profiles, and secondary menus like top bars or category navigation that some themes provide.
  • Backend menus serve a different purpose entirely – they customize the WordPress admin dashboard interface for different user roles and administrative needs. These allow you to control what logged-in users see in their dashboard experience.

How to create WordPress navigation menus

Now that you understand how WordPress menus function, here are step-by-step walkthroughs for creating them across every setup you’ll encounter. Classic themes with traditional menu interfaces, block themes using navigation blocks, plugin-based solutions, and manual coding.

Method 1: Using WordPress’s built-in tools

The Site Editor introduced a new process for creating menus in WordPress, fundamentally changing how block themes handle navigation. Classic themes still use the familiar Customizer interface. We’ll cover both approaches so you can work effectively with any theme type.

Creating custom menus for WordPress block themes

Block themes handle menus through the Site Editor’s navigation system, i.e., the header.

Navigate to Appearance > Editor > Templates or Patterns, then add a Navigation block. This creates a reusable block that you can deploy across multiple areas of your site.

Alternatively, you can edit the existing Navigation block in your theme via the Site Editor.

How to edit navigation menus in the WordPress Site Editor

The block-based approach offers significant advantages over traditional menus. Since it operates within the Gutenberg editor, you can integrate custom blocks created with ACF Blocks directly into your navigation. This means displaying custom field values, dynamic content, or complex layouts right within your menu structure.

Create your navigation once and reuse it throughout your site. The Navigation block automatically adapts to different contexts while maintaining consistent styling and functionality across all implementations.

Creating menus for classic WordPress themes

Classic themes offer two primary methods for menu creation. The traditional Appearance > Menus interface provides comprehensive control over menu structure, allowing you to add pages, posts, custom links, and categories with drag-and-drop functionality.

Creating a custom menu in WordPress dashboard

Alternatively, use Appearance > Customize > Menus for real-time preview capabilities. This approach lets you see changes immediately as you build your menu structure.

Creating a custom menu in WordPress classic themes

Classic themes excel at displaying custom post type entries in menus. Just create a custom post type using Advanced Custom Fields (ACF®), then expand the Screen Options when creating your menu, check the box for your custom post type, and it becomes available in the dropdown selector.

Supercharge Your Website With Premium Features Using ACF PRO

Speed up your workflow and unlock features to better develop websites using ACF Blocks and Options Pages, with the Flexible Content, Repeater, Clone, Gallery Fields & More.

Explore Features View Pricing

PRO Features
ACF Blocks
Options Pages
PRO Fields
Repeater
Flexible Content
Gallery
Clone

Method 2: Using WordPress menu plugins

Plugin-based solutions should expand WordPress’s built-in functionality significantly rather than simply replicating existing features. Mega menu plugins like Max Mega Menu deliver this enhanced capability by creating sophisticated navigation experiences.

A mega menu is an expanded navigation menu that displays multiple columns of links, images, or widgets in a large dropdown panel. They accommodate complex multi-level site structures while maintaining organized navigation.

They’re popular on eCommerce sites, though you may never have known they had an official name. Here’s one on eBay’s homepage:

eBay homepage mega menu

Interested? Let’s build a mega menu for your WordPress block theme with max Mega Menu:

  1. With the plugin installed and activated, go to Mega Menu > Menu Locations from your dashboard.
  2. Add a new menu location called “Header” and save it.
  3. Go to Appearance > Menus from your dashboard. The plugin adds this section to your dashboard, so it should be available even with a block theme.
  4. Create a new menu, and make sure to check Enable on the Max Mega Menu Settings section on the left. Here’s what our structure looks like:

A custom menu structure for Max Mega Menu

  1. Go to Appearance > Editor to open the block editor and delete the navigation block from the top of the page.
  2. Open the block inserter and search for the new Max Mega Menu block, then add it to the position where the old navigation block was.
  3. From the Select a location dropdown, choose the one you’d created in step 2, which should have your menu from step 4 assigned to it.

The Max Mega Menu block

  1. Load up a page on your site’s frontend, where you should see the basic mega menu show up in the header:

A mega menu created using Max Mega Menu

And that’s it – you have a fully functional mega menu in your WordPress block theme. To style it, go to Mega Menus > Menu Themes, where you can tweak everything from colors, layout, and typography, to adding widgets for banners.

Method 3: Using custom code

Custom code provides complete control over menu functionality and appearance. The approach below offers unlimited flexibility for unique navigation requirements in classic themes that plugins cannot address.

  1. In your theme’s functions.php, create a custom function to register menu locations:
function register_my_menus() {

    register_nav_menus(

        array(

            'primary' => __('Primary Menu'),

        )

    );

}

add_action('init', 'register_my_menus');
  1. Save the functions.php file.
  2. Navigate to Appearance > Menus in your WordPress dashboard.
  3. Create your menu and assign it to your registered location.
  4. Open the template file where you want to display the menu.
  5. Add the wp_nav_menu() function with your registered location:
wp_nav_menu(array('theme_location' => 'primary'));
  1. Save your template file.

This function outputs the complete menu HTML structure, which you can then style with CSS to match your design requirements.

How to create custom WordPress admin dashboard menus

Custom admin dashboard menus are visible only to administrators and logged-in users, making them ideal for account management, custom plugin controls, and internal resource organization.

This walkthrough creates a custom admin menu for storing important resources like notes, links, and reference materials that administrators can access quickly:

  1. Open your theme’s functions.php file or create a custom plugin
  2. Add the admin_menu action hook to register your custom menu:
function add_custom_admin_menu() {

    add_menu_page(

        'Admin Resources',     // Page title

        'Resources',           // Menu title

        'manage_options',      // Capability required

        'admin-resources',     // Menu slug

        'display_admin_resources', // Callback function

        'dashicons-clipboard-list', // Icon

        30                     // Position

    );

}

add_action('admin_menu', 'add_custom_admin_menu');
  1. Create the callback function that displays your menu content:
function display_admin_resources() {

    echo '<div class="wrap"><h1>Admin Resources</h1>';

    echo '<p>Important links and notes for site management.</p></div>';

}
  1. Save your file and check the WordPress admin dashboard. Here’s a menu that conveniently displays entries from the ACF docs:

A custom menu of ACF resources

Build custom menus for managing custom data with ACF’s Options Pages

An ACF Options Page, part of ACF PRO, is a custom admin menu page in WordPress that lets you create global site-wide settings and content fields that can be accessed from any template, separate from individual posts or pages. These pages centralize reusable content management, eliminating the need to update information across multiple locations.

Creating an Options Page for business information demonstrates this powerful functionality perfectly:

  1. Navigate to ACF > Options Pages in your WordPress dashboard.
  2. Click Add New to create your Options Page.
  3. Give it a name, and ACF will give it a corresponding unique menu slug. Add a parent if you’d prefer it to show up under an existing dashboard menu item.

Creating an ACF Options Page for business info

  1. Save the options page.
  2. Navigate to ACF > Field Groups and create a new field group.
  3. Add fields for phone number, email address, and physical address.

Creating an ACF field group for business information

  1. Set the location rule to Options Page is equal to Business Information:

Location rules for business information field group

  1. Publish your field group.

Your new Business Info menu appears in the WordPress dashboard. Update these fields once, and the information becomes available globally across headers, footers, sidebars, and any template you’ve set it to display on.

Viewing business information custom fields in an Options Page

Page builders like Elementor and Divi support this dynamic content natively, displaying your centralized business information without manual template editing.

Streamline your WordPress site’s user experience with custom menus and ACF

Custom menus transform basic navigation into professional user experiences that guide visitors exactly where they need to go. You can create them using WordPress’s built-in tools, specialized plugins, or custom code – choose the approach that matches your technical comfort level and project requirements.

Backend admin menus put essential tools directly at administrators’ fingertips, reducing clicks and improving workflow efficiency. ACF PRO’s Options Pages centralize reusable content like contact information, social media links, and company details. Global ACF fields ensure this data remains consistent across all your templates and pages.

The combination of custom menus and ACF creates scalable content management solutions that grow with your site’s needs. Take your WordPress menu development to the next level with ACF PRO’s advanced features.

The post Boost Navigation with Custom WordPress Menus appeared first on ACF.

]]>
https://www.advancedcustomfields.com/blog/custom-menu-wordpress/feed/ 0
Create WordPress Custom User Roles With or Without Code https://www.advancedcustomfields.com/blog/wordpress-custom-user-roles/ https://www.advancedcustomfields.com/blog/wordpress-custom-user-roles/#respond Tue, 09 Sep 2025 12:00:00 +0000 https://www.advancedcustomfields.com/?post_type=blog&p=660614 Key points: WordPress ships with six built-in user roles: These roles work well for most sites, but unique requirements often demand more granular control. Consider handing off a completed site to a non-technical client – they might need content management access without the risk of breaking functionality through the admin dashboard. The problem isn’t creating […]

The post Create WordPress Custom User Roles With or Without Code appeared first on ACF.

]]>
Key points:

  • WordPress has six built-in user roles, but custom roles are often needed for specific workflows like client handoffs or editorial teams.
  • Custom roles can be created using plugins like User Role Editor or through custom code with the add_role() function.
  • Advanced Custom Fields (ACF®) allows you to set field visibility and Options Pages access based on user roles.

WordPress ships with six built-in user roles:

  • Super Admin
  • Administrator
  • Editor
  • Author
  • Contributor
  • Subscriber

These roles work well for most sites, but unique requirements often demand more granular control. Consider handing off a completed site to a non-technical client – they might need content management access without the risk of breaking functionality through the admin dashboard.

The problem isn’t creating custom roles. WordPress provides the tools for that. The real challenge is managing what users with those roles actually see and experience. Default WordPress permissions are binary – you either have access or you don’t. There’s no middle ground for contextual restrictions or simplified interfaces.

Unless you create it.

We’re going to explain how WordPress handles user roles and capabilities under the hood, then show you how to add and implement custom user roles both with and without plugins.

Understanding WordPress user roles

WordPress operates on a hierarchy where each role builds upon the previous one’s capabilities, with clear boundaries that prevent role overlap and confusion.

Basically, Administrators control the site itself, Editors control all content, Authors control their own content, Contributors create but can’t publish, and Subscribers consume. Here’s a table to help you out:

RoleCanCan’t
Super Admin (multisite only)• Control entire multisite network
• Manage all sites, network users, and themes, everything an Administrator can do
Function on single-site installations
Administrator• Control full site
• Manage usersInstall plugins/themes
• Change all settings
Manage multisite network (if applicable)
Editor• Manage all content (posts, pages, comments)
• Edit others’ work
• Moderate comments
Access plugins, themes, or site settings
Author• Write, edit, and publish own posts
• Upload media files
• Manage own profile
Edit others’ content or access administrative areas
Contributor• Write and edit own posts
• Manage own profile
Publish posts, upload media, or edit others’ content
Subscriber• Read content
• Manage own profile and comments
Create, edit, or manage any content

What can WordPress users do with their roles?

The built-in WordPress roles we covered above bundle specific capabilities together, but you can create custom roles with any combination of capabilities you want. These capabilities are the granular permissions that actually control what users can do on your site:

CategoryCapabilities
Network and site management• Create or delete entire sites
• Set up or configure a network
• Manage network-wide settings, users, plugins, and themes
• Upgrade the network
• Delete a site
Content creation and management• Write and edit posts or pages
• Publish or unpublish content
• Edit or delete other users’ content
• Work with private content
• Upload mediaUse unfiltered HTML
• Import/export content
Design and customization• Switch, install, or delete themes
• Customize the site appearance
• Edit theme files
Plugin and feature management• Install, activate, update, or delete plugins
• Edit plugin code
• Manage plugins network-wide
User and permission control• Add, remove, or edit users
• Promote users to new roles
• View user lists
• Manage user permissions (including network-level)
Settings and configuration• Change site settings
• Manage categories or tags
• Moderate comments
• Manage external links
• Customize dashboard settings
• Edit internal files

Always start with minimal capabilities and expand gradually – removing permissions from frustrated users is harder than adding them later. But capabilities alone don’t solve the real problem: users still face a cluttered admin dashboard full of irrelevant options.

Field-level control gets you over this hurdle by transforming technical permissions into focused user experiences.

What can you do with WordPress user roles?

Custom WordPress roles solve real business problems.

During client handoffs, you can create roles that let clients edit content without accessing plugins or breaking site functionality. For editorial workflows, you might need writers who can draft posts, editors who can publish them, and content managers who control categories and tags – each with different permission levels.

Advanced Custom Fields (ACF®) takes user roles further by controlling field visibility. When creating a custom field group, set location rules to User Role is equal to… and choose your target role. Only users with that role will see those specific fields.

ACF location rules by user role

ACF PRO’s Options Pages extend this control to site-wide settings. Create custom admin pages for contact information, social media links, or branding elements, then restrict access by role. A client might manage contact details through an Options Page while administrators handle technical settings elsewhere.

This combination of role-based capabilities and field-level visibility creates focused, clutter-free admin experiences tailored to each user’s actual responsibilities.

Supercharge Your Website With Premium Features Using ACF PRO

Speed up your workflow and unlock features to better develop websites using ACF Blocks and Options Pages, with the Flexible Content, Repeater, Clone, Gallery Fields & More.

Explore Features View Pricing

PRO Features
ACF Blocks
Options Pages
PRO Fields
Repeater
Flexible Content
Gallery
Clone

How to create custom WordPress user roles

Creating custom roles requires either a plugin or custom code – both approaches achieve the same result with different trade-offs in convenience and control.

We’ll build a Customer Support Agent role designed for team members who help users but shouldn’t access core content management.

This role needs specific capabilities:

  • Dashboard access (read)
  • Viewing all users (list_users)
  • Editing user profiles, including passwords and emails (edit_users)
  • Moderating comments (moderate_comments)
  • Accessing private posts and pages for internal documentation (read_private_posts, read_private_pages)

This combination lets support agents assist users with account issues, moderate community discussions, and reference internal knowledge bases without touching published content or site settings.

The plugin method offers a user-friendly interface and ongoing management tools. Custom code provides more control and doesn’t add plugin overhead, but requires comfort with PHP.

Both methods create identical functionality – your choice depends on your technical preference and long-term maintenance approach.

Method 1: Custom WordPress user roles using plugins

User Role Editor is a free plugin that lets you create and modify WordPress user roles through a visual interface. Instead of manually coding the capabilities, you get checkboxes for each permission, role cloning, and bulk management tools.

Here’s how to use it to create a custom WordPress user role:

  1. With the plugin installed and activated, go to your admin dashboard and open Users > User Role Editor.
  2. From the menu on the right, click Add Role.

Adding a new user role in WordPress

  1. Add the new role’s details. Keep the ID simple, save the descriptiveness for the display name.

Creating a new user role for WordPress

  1. Click Add Role when you’re done.
  2. The new role will now be ready for editing. Check the capabilities from the list as needed. Use the Quick filter text box to find capabilities faster.

Adding capabilities to a new WordPress user role

  1. Click Update from the menu on the right when you’re done and confirm the action when you get the dialog box.

Saving a new custom user role

💡Use the Delete Role option to get rid of a custom role when you no longer need it.

  1. From the dashboard, go to Users > Add User. Expand the Role dropdown, and you should see it ready for assigning.

Confirming a new user role

Choose this over custom code when you need frequent role adjustments, work with non-technical team members, or want ongoing management without the threat of syntax errors taking your site offline.

Method 2: Custom WordPress user roles without using plugins

If you’re comfortable with PHP and want granular control over things, custom code might be the way to go. You define roles exactly once, and they persist until you remove the code. You don’t worry about plugin updates breaking functionality, interface overhead, or database bloat from unused plugin features.

This approach works best when you know exactly what capabilities you need and don’t plan frequent role modifications. The code is also portable – drop it into any WordPress site and your custom roles work immediately.

Instead of editing functions.php, we’ll create a custom plugin instead, so your work isn’t erased by theme changes.

We’re going to use WordPress’s built-in add_role() and remove_role() functions to create the Customer Support Agent role with the same capabilities we defined earlier.

Let’s get into it:

  1. Start by setting up the plugin structure. Create a new folder called custom-user-roles in your /wp-content/plugins/ directory.
  2. Inside this folder, create a file named custom-user-roles.php.
  3. Open the file and add the plugin header that tells WordPress this is a valid plugin:
<?php
/**
 * Plugin Name: Customer Support Agent role
 * Description: Adds custom user role for Customer Support Agents
 * Version: 1.0
 * Author: Your Name
 */
  1. Add security protection to prevent direct file access outside of WordPress:
if (!defined('ABSPATH')) {
    exit;
}
  1. Create the function that builds your Customer Support Agent role with the required capabilities:
function create_customer_support_role() {
    if (!get_role('customer_support')) {
        add_role(
            'customer_support',
            'Customer Support Agent',
            array(
                'read' => true,
                'list_users' => true,
                'edit_users' => true,
                'moderate_comments' => true,
                'read_private_posts' => true,
                'read_private_pages' => true,
            )
        );
    }
}
  1. Hook the function to run automatically when the plugin activates:
register_activation_hook(__FILE__, 'create_customer_support_role');
  1. Add cleanup functionality to remove the role when the plugin deactivates:
function remove_customer_support_role() {
    remove_role('customer_support');
}
register_deactivation_hook(__FILE__, 'remove_customer_support_role');
?>
  1. Save the file and activate the plugin through your WordPress admin dashboard under Plugins > Installed Plugins.

Adding a WordPress user role as a plugin

  1. Test it wherever you expect to see user roles listed. Here it is under ACF’s location rules:

Custom user role in ACF location rules

Unlock advanced user management with custom roles and ACF

Custom WordPress user roles move you from chaotic permission management and into precise control systems. Instead of forcing users into ill-fitting default roles, you can craft exact permission sets that match your workflow and security requirements.

Use plugins for convenience or custom code for control, but the result is the same: team members and clients get exactly the access they need without compromising your site’s integrity. No more administrators who only need to edit content, or clients accidentally breaking functionality they shouldn’t touch.

ACF elevates this approach by adding visual control layers. Role-based field visibility and custom Options Pages create focused admin experiences that feel purpose-built rather than generic. Users see only what’s relevant to their role, reducing confusion and support requests.

When you’re ready to build truly custom admin experiences, check out ACF PRO for its advanced user role features and the tools to create professional-grade user management systems.

The post Create WordPress Custom User Roles With or Without Code appeared first on ACF.

]]>
https://www.advancedcustomfields.com/blog/wordpress-custom-user-roles/feed/ 0
Step-by-Step WordPress Plugin Development Tutorial https://www.advancedcustomfields.com/blog/wordpress-plugin-development-tutorial/ https://www.advancedcustomfields.com/blog/wordpress-plugin-development-tutorial/#respond Mon, 08 Sep 2025 12:00:00 +0000 https://www.advancedcustomfields.com/?post_type=blog&p=660574 Key points: When you need to extend a WordPress site, creating a custom plugin is often the safest and most flexible option. Unlike editing your theme’s functions.php, a plugin keeps your code separate, reducing the risk of breaking your site and ensuring your customizations survive theme updates or changes. Plugins also give you full control […]

The post Step-by-Step WordPress Plugin Development Tutorial appeared first on ACF.

]]>
Key points:

  • Decide if a plugin is truly needed, or if alternatives like ACF Blocks can deliver the same functionality more simply.
  • Build your plugin step by step, from basic structure to enqueuing assets, adding admin options, and handling dynamic data.
  • Distribute it properly by packaging, documenting, following security/versioning best practices, and sharing via the WordPress plugin directory or your own site.

When you need to extend a WordPress site, creating a custom plugin is often the safest and most flexible option. Unlike editing your theme’s functions.php, a plugin keeps your code separate, reducing the risk of breaking your site and ensuring your customizations survive theme updates or changes.

Plugins also give you full control – turn them on or off as needed – and can even be shared with others who face the same challenges.

We’ll help you decide whether building a plugin is the right solution, explore practical alternatives, and then walk through the process of creating one. You’ll see how to approach plugin development in a structured way that makes your WordPress site easier to maintain and extend.

Is a custom plugin the right choice for you?

Custom plugins are great for offering control and keeping your customizations safe from theme updates. They’re especially useful when you want functionality that can be toggled on and off or when you plan to distribute your solution.

However, they aren’t always the best choice, particularly if the task can be solved more simply. Sometimes, building a plugin can be overkill or require more technical knowledge than necessary.

For instance, a common use case for custom plugins is adding dynamic or reactive content to the frontend, often relying on React on the frontend and PHP on the backend. While this offers flexibility, it also requires expertise in both PHP and React, with the latter demanding a significant amount of setup and integration within WordPress.

A smarter, more practical alternative here involves using ACF Blocks from Advanced Custom Fields (ACF®). ACF Blocks allow you to create dynamic, reactive content using just PHP, all accessible through the Gutenberg editor.

For example, you can configure queries directly in block fields – selecting post types, categories, or sorting orders – while PHP handles the backend logic and markup. This approach gives you a lightweight solution that’s both easy to maintain and extend.

Other use cases for ACF Blocks include powering reusable sections, like FAQ sections, where PHP handles everything from storing questions and answers in repeater fields to automatically outputting semantic HTML and JSON-LD for SEO.

Here’s a handy table to help you decide whether or not a custom plugin is the right path:

A custom plugin makes sense whenA custom plugin doesn’t make sense when
You need functionality that no existing tool or plugin providesA reliable plugin or built-in WordPress feature already solves it
You want features that stay safe through theme changes and updatesA quick tweak is all that’s needed
You need control – the ability to switch features on/off easilyIt’s just a one-time change you won’t revisit
You plan to share or distribute your solution with othersThe feature is only for your own site and won’t be reused
Your project requires dynamic or complex behaviorSimpler methods (like custom fields, blocks, or settings) can handle it
You can commit to maintaining and updating itYou don’t have time to support, patch, or secure it long-term

Build your first working plugin

If you’ve found that a custom plugin is the best way to solve your problem, here’s where you learn how to build one from scratch.

We’ll start with basic functionality and move on to advanced features like accessing files and creating an admin dashboard entry.

💡 For best results, we recommend using LocalWP as your local WordPress development tool. It provides a safe testing environment and lets you access your setup directly through your IDE, streamlining the development and debugging process.

Create the plugin’s basic structure and functionality

The first step involves setting up the core files and folders, then adding the basic functionality to make your plugin work.

We’re going to create a simple plugin that changes the background color of the homepage to a predefined value.

In wp-content/plugins, create a new folder with your plugin name. Inside this folder, add a .php file, ideally with the same name as the folder.

Open the .php file and add a header that contains your plugin’s details, including its name, version, and author.

Here’s a guide to help you build the perfect header:

FieldInclusionDescriptionExample
Plugin nameMandatoryThe only truly required field. Without this, WordPress won’t recognize your file as a plugin.Plugin Name: My Custom Plugin
DescriptionShould IncludeBrief explanation of what your plugin does. Shows up in the admin area.Description: Does bespoke things for your WordPress site.
VersionRecommendedCritical for updates and compatibility tracking.Version: 1.0.0
AuthorRecommendedYour name or organization. Builds credibility and allows users to find your other work.Author: Your Name
Plugin URIOptionalLink to your plugin’s homepage or repositoryPlugin URI: https://example.com/my-plugin
Author URIOptionalYour website or profileAuthor URI: https://yourwebsite.com
Text domainOptionalFor internationalization (should match your plugin folder name)Text Domain: my-custom-plugin
Domain pathOptionalWhere translation files are storedDomain Path: /languages
Requires at leastOptionalMinimum WordPress versionRequires at least: 5.0
Tested up toOptionalLatest WordPress version you’ve testedTested up to: 6.3
Requires PHPOptionalMinimum PHP versionRequires PHP: 7.4
LicenseOptionalLegal stuff (GPL v2+ is standard for WordPress)License: GPL v2 or later
NetworkOptionalSet to true if it’s a multisite pluginNetwork: false

And here’s the header we’re using for the custom plugin we’re building:

<?php
/**
 * Plugin Name: Homepage Background Color Changer 
 * Description: A simple plugin that changes the background color of the homepage.
 * Version: 1.0
 * Author: ACF Content Team
 * License: GPL2
 */

⚠ Keep the header comment at the very top of your main plugin file – WordPress only reads the first 8 kilobytes when scanning for plugin headers.

Finally, add the functionality for changing the homepage color to a predefined value:

// Hook into the 'wp_head' action to inject custom styles
function hbcc_change_homepage_background() {
    // Check if we're on the homepage
    if ( is_front_page() ) {
        echo '<style>body { background-color: #0077b6; }</style>';
    }
}
add_action( 'wp_head', 'hbcc_change_homepage_background' );

Save the changes to the .php file, then verify that the plugin is available from your admin dashboard via Plugins > Installed Plugins.

Checking that a custom plugin is ready

Activate it, then load up your homepage and here’s what you should see:

A WordPress homepage recolored using a custom plugin

Enqueue external scripts and styles

Adding functionality to the .php file is just the beginning. The next step in mastering custom WordPress plugins is learning how to enqueue external files.

Enqueuing external styles

If all the changes you need to make are purely stylistic/visual – colors, font sizes, spacing, animations, etc. – you can place them into a CSS stylesheet that you reference within the main PHP file:

  1. Deactivate the plugin in the admin dashboard.
  2. Create a CSS file in your plugin folder and give it a clear name like style.css.
  3. Add your styles to the file. For this walkthrough, we’ll make it an animation that changes the color between predefined values:
@keyframes backgroundColorChange {
    0% {
        background-color: #57cc99;
    }
    50% {
        background-color: #9d4edd;
    }
    100% {
        background-color: #57cc99;
    }
}

body {
    animation: backgroundColorChange 3s infinite;
}
  1. Update your PHP file so it enforces the custom stylesheet on the homepage:
function hbcc_enqueue_styles() {
    // Check if we're on the homepage
    if ( is_front_page() ) {
        wp_enqueue_style( 'homepage-background-animation', plugin_dir_url( __FILE__ ) . 'style.css' );
    }
}
add_action( 'wp_enqueue_scripts', 'hbcc_enqueue_styles' );
  1. Save your changes, activate the plugin, and load up your homepage.

A custom plugin using an external custom stylesheet

Enqueuing external scripts

Enqueuing an external JavaScript file adds interactivity to your plugin by enabling it to respond to user input and focus events.

Here’s how to make the plugin cycle between predefined homepage background colors when a user clicks:

  1. Deactivate your plugin.
  2. In the plugin’s root folder, add a JS file – we’ll call ours script.js – with the logic for the interactivity:
document.addEventListener('DOMContentLoaded', function () {
    const colors = ["#820263", "#d90368", "#eadeda", "#2e294e", "#ffd400"];
    let currentColorIndex = 0;

    // Function to change background color
    function changeBackgroundColor() {
        currentColorIndex = (currentColorIndex + 1) % colors.length;
        document.body.style.backgroundColor = colors[currentColorIndex];
    }

    // Attach click event to body
    document.body.addEventListener('click', changeBackgroundColor);
});
  1. Update your PHP file to locate and execute the JS file on the homepage:
function hbcc_enqueue_scripts() {
    // Check if we're on the homepage
    if ( is_front_page() ) {
        wp_enqueue_script( 'homepage-background-color-click', plugin_dir_url( __FILE__ ) . 'script.js', array(), '1.0', true );
    }
}
add_action( 'wp_enqueue_scripts', 'hbcc_enqueue_scripts' );
  1. Save your changes, load up your homepage, and click away:

Using JavaScript with a custom plugin

Add an admin dashboard menu for advanced controls and options

For even more control, let’s create an admin menu to allow users to manage and configure your plugin’s settings.

In this case, we’ll let users pick the homepage background color from a list of predefined values. Here’s what you need in your PHP file after the header:

  1. Add a new menu item in the admin dashboard:
function hbc_selector_menu() {
    add_menu_page(
        'Background Color Selector',  // Page title
        'Background Color',           // Menu title
        'manage_options',             // Capability
        'background_color_selector',  // Menu slug
        'hbc_selector_page',          // Function to display the settings page
        'dashicons-admin-appearance'  // Icon
    );
}
add_action('admin_menu', 'hbc_selector_menu');
  1. Create and display the settings page in the admin panel with radios for color selection. This section uses HTML tags, which might look complex at first glance, but the logic is straightforward and should be easy to follow, especially in an IDE:
function hbc_selector_page() {
    ?>
    <div class="wrap">
        <h1>Homepage Background Color Selector</h1>
        <form method="post" action="options.php">
            <?php
            settings_fields('hbc_selector_options_group');
            do_settings_sections('background_color_selector');
            ?>
            <table class="form-table">
                <tr valign="top">
                    <th scope="row">Select Background Color</th>
                    <td>
                        <ul>
                            <li>
                                <label>
                                    <input type="radio" name="hbc_background_color" value="#820263" <?php checked(get_option('hbc_background_color'), '#820263'); ?>>
                                    <span style="background-color: #820263; width: 20px; height: 20px; display: inline-block; margin-right: 10px;"></span>
                                    Color 1
                                </label>
                            </li>
                            <li>
                                <label>
                                    <input type="radio" name="hbc_background_color" value="#d90368" <?php checked(get_option('hbc_background_color'), '#d90368'); ?>>
                                    <span style="background-color: #d90368; width: 20px; height: 20px; display: inline-block; margin-right: 10px;"></span>
                                    Color 2
                                </label>
                            </li>
                            <li>
                                <label>
                                    <input type="radio" name="hbc_background_color" value="#eadeda" <?php checked(get_option('hbc_background_color'), '#eadeda'); ?>>
                                    <span style="background-color: #eadeda; width: 20px; height: 20px; display: inline-block; margin-right: 10px;"></span>
                                    Color 3
                                </label>
                            </li>
                            <li>
                                <label>
                                    <input type="radio" name="hbc_background_color" value="#2e294e" <?php checked(get_option('hbc_background_color'), '#2e294e'); ?>>
                                    <span style="background-color: #2e294e; width: 20px; height: 20px; display: inline-block; margin-right: 10px;"></span>
                                    Color 4
                                </label>
                            </li>
                            <li>
                                <label>
                                    <input type="radio" name="hbc_background_color" value="#ffd400" <?php checked(get_option('hbc_background_color'), '#ffd400'); ?>>
                                    <span style="background-color: #ffd400; width: 20px; height: 20px; display: inline-block; margin-right: 10px;"></span>
                                    Color 5
                                </label>
                            </li>
                        </ul>
                    </td>
                </tr>
            </table>
            <?php submit_button(); ?>
        </form>
    </div>
    <?php
}
  1. Register the setting to save the selected color:
function hbc_selector_register_settings() {
    register_setting('hbc_selector_options_group', 'hbc_background_color');
}
add_action('admin_init', 'hbc_selector_register_settings');
  1. Retrieve the saved color and apply it to the homepage background. Include a fallback value just in case:
function hbc_apply_background_color() {
    $color = get_option('hbc_background_color', '#ffffff'); // Default to white if no color is selected
    if (is_front_page()) {
        echo "<style>body { background-color: $color; }</style>";
    }
}
add_action('wp_head', 'hbc_apply_background_color');
  1. Activate the plugin and check your admin menu for a new item.

An admin menu item for a custom plugin

  1. Click it, choose a color from the list, and save your changes.

A custom WordPress plugin admin menu section

  1. Load up your homepage and check out its new look.

Changing background color with custom plugin menu

How to work with custom data for dynamic plugins

Many dynamic plugins need to handle constantly evolving data, like user-generated content, settings, or media files.

For such plugins, ACF provides an efficient, scalable solution that avoids adding unnecessary complexity to your site. ACF simplifies the process of managing custom data by allowing you to define custom fields for posts, pages, or custom post types.

With ACF, you can manage various data types, such as text, images, files, and relationships between different content elements. The plugin’s built-in functions make it easy to retrieve and manipulate this data wherever needed in your plugin.

For example, you can use get_field() to retrieve data from a custom field or the_field() to display it within templates.

ACF lets you integrate custom data management into your plugin without manually building complex database structures. It also helps maintain good performance and compatibility with WordPress updates.

Supercharge Your Website With Premium Features Using ACF PRO

Speed up your workflow and unlock features to better develop websites using ACF Blocks and Options Pages, with the Flexible Content, Repeater, Clone, Gallery Fields & More.

Explore Features View Pricing

PRO Features
ACF Blocks
Options Pages
PRO Fields
Repeater
Flexible Content
Gallery
Clone

How to use ACF for custom data without the complexity

ACF gives you several ways of getting custom field data into your site, including entering it into posts, capturing input from frontend forms, and importing it in formats like XML and JSON.

For this walkthrough, though, we’re going to introduce you to ACF’s Options Pages, one of its most convenient data management features.

Options Pages, available in ACF PRO, let you create a dedicated area for managing/updating/editing custom field values that you can then reuse across your site.

Let’s demonstrate how you can use one to supercharge your site’s functionality by passing custom field values into your plugin and using them there. In this final section, we’re using ACF’s color picker field to choose a color then use that in the plugin to restyle the homepage.

Step 1: Create the Options Page

We’ll start by creating a dedicated page where we can manage custom fields:

  1. From your admin dashboard, go to ACF > Options Pages.
  2. Click Add New.
  3. Give your Options Page a name and slug. The page determines how it appears in the admin menu on the left. Give it a parent if you want it to appear as an option in an existing menu item. We’re going with Appearance for the parent here.

Creating a new Options Page for custom colors

  1. Save the Options Page and check that it shows up where you expect it to in the menu. Ours should appear when hovering over Appearance.

Testing an ACF Options Page for custom colors

Step 2: Create your custom field group

Next, create the custom field group that you’ll manage using the Options Page:

  1. From the dashboard, go to ACF > Field Groups > Add New.
  2. Add a color picker field and fill in all the necessary details.

Creating a color picker field for homepage color

  1. Scroll down to the Settings section and, under Location Rules, set it to show when the Options Page is equal to the one you created above.

Connecting an Options Page to a color picker field

  1. Save your changes and go back to the Options Page to verify that the color picker field shows up.

Viewing a color picker field in an Options Page

Step 3: Create the plugin and link it to ACF

All that’s left is updating your plugin to grab the color value using ACF’s get_field() function:

function hbc_acf_background_color() {
    // Check if we're on the homepage
    if (is_front_page()) {
        // Get the value of the ACF color picker field
        $background_color = get_field('homepage_color');

        // If the field has a value, apply it as background color
        if ($background_color) {
            echo "<style>body { background-color: $background_color; }</style>";
        }
    }
}
add_action('wp_head', 'hbc_acf_background_color');

Open your Options Page and choose a new color – we just closed our eyes and clicked at random.

Selecting a custom color from a color picker field Options Page

Now load up your homepage and you should see the color applied:

Using an ACF color picker field to change homepage background color

Distribute your plugin to the world

Once your plugin is complete, it’s time to share it with the world. Proper distribution ensures that others can use and benefit from your work. Follow these tips before putting your plugin out there:

  • Bundle everything into a zip archive to make it easy for users to download, install, and activate your plugin. A zip file is the standard format for WordPress plugin installations.
  • Add at least one clear screenshot that showcases how the plugin works or what it changes. Screenshots help users understand your plugin’s functionality and attract more downloads.
  • Use semantic versioning in the header with version numbers in the format “major.minor.patch” in the plugin header. This allows users to easily track updates and manage compatibility.
  • Keep a human-readable changelog to provide transparency and help users stay informed about updates.
  • Follow security basics like nonces, capability checks, input sanitization, output escaping, and prepared SQL queries. These practices protect users from potential vulnerabilities.
  • Clearly specify the minimum required versions for both WordPress and PHP. This ensures that users are aware of compatibility issues before installation.

You have several avenues for distributing the plugin:

  • Submit it to the WordPress plugin directory, where it can reach a large audience.
  • Create a dedicated website or web page for your plugin to provide detailed information and updates.
  • Share the zip file directly with others, allowing them to install it manually.

Take full control of your WordPress website with ACF

ACF gives you the flexibility to add custom fields and options, allowing your site to function exactly how you need it, rather than relying on WordPress’s default setup.

You can easily replace many small “helper plugins” by creating your own fields, blocks, and layouts tailored to your workflow. With simple functions like get_field() and PHP templates, you maintain control over your data, design, and performance while keeping coding overhead minimal.

ACF empowers you to customize your site without the need for complex coding or bloated plugins.

For even more advanced features and support, consider upgrading to ACF PRO, which offers additional functionality like repeater fields, flexible content, and more, helping you unlock the full potential of your WordPress projects.

The post Step-by-Step WordPress Plugin Development Tutorial appeared first on ACF.

]]>
https://www.advancedcustomfields.com/blog/wordpress-plugin-development-tutorial/feed/ 0
Transform Chaotic WordPress Sites into Streamlined Workflows https://www.advancedcustomfields.com/blog/wordpress-workflow/ https://www.advancedcustomfields.com/blog/wordpress-workflow/#respond Fri, 05 Sep 2025 12:00:00 +0000 https://www.advancedcustomfields.com/?post_type=blog&p=659329 Key points: WordPress deployments present unique challenges that standard web applications avoid. The platform stores configuration data, content, and settings in a database that must stay synchronized with the codebase. Plugin dependencies create compatibility matrices where a single version mismatch can break entire sites. File system changes happen across multiple directories – uploads, themes, plugins, […]

The post Transform Chaotic WordPress Sites into Streamlined Workflows appeared first on ACF.

]]>
Key points:

  • WordPress deployments fail due to database coupling, plugin version mismatches, and configuration drift between environments.
  • Four-stage CI/CD pipeline transforms chaotic WordPress releases into predictable, automated workflows with proper testing.
  • Advanced Custom Field (ACF®)’s Local JSON separates structure from content by storing field definitions as trackable files, solving WordPress’s database versioning challenge.

WordPress deployments present unique challenges that standard web applications avoid.

The platform stores configuration data, content, and settings in a database that must stay synchronized with the codebase. Plugin dependencies create compatibility matrices where a single version mismatch can break entire sites. File system changes happen across multiple directories – uploads, themes, plugins, and core files – making deployments unpredictable.

Manual deployment processes compound these issues, while version mismatches between local development and production environments cause the “works on my machine” problem.

Well-designed CI/CD pipelines solve these issues through automation and standardization. We’re going to show you how the greatest WordPress development teams deploy multiple times daily without fear of breaking production sites.

Why your WordPress deployments keep falling apart

WordPress development workflows lack the simplicity of editorial workflows, where automation tools like Oasis Workflow provide straightforward solutions.

The complexity stems from fundamental architectural decisions that create deployment friction:

  • Version control issues stem from WordPress storing critical configuration in database tables that Git cannot track. Custom field definitions, menu structures, and widget settings exist only in MySQL, causing features to break when code deploys without the supporting database state.
  • Plugin and theme incompatibilities occur when environments run different versions of the same components. A plugin update on local development can introduce database schema changes or new dependencies that break functionality on staging or production servers running older versions.
  • Configuration drift happens when server environments differ in PHP versions, caching systems, or file permissions. Identical WordPress codebases behave unpredictably across environments because underlying infrastructure variations affect how plugins execute and features function.

These problems require systematic solutions that address each failure point through automation and standardization.

How to create a solid WordPress development workflow

This complete guide walks through creating a full CI/CD workflow for WordPress development. Pair it with our tips for advanced WordPress development, and you’ll be on your way to hassle-free deployment.

Phase 1: Local development environment

Standardize development environments across your team using Docker or LocalWP to match production specifications exactly. This eliminates the “works on my machine” problem by ensuring every developer runs identical PHP versions, MySQL configurations, and server settings.

If you’re working with custom data, use Advanced Custom Fields (ACF®) instead of trying to DIY a solution from scratch. Enable its Local JSON to store custom field definitions as version-controlled files rather than database entries, allowing field structure changes to flow through Git like regular code.

Configure pre-commit hooks that run PHP_CodeSniffer and ESLint to catch syntax errors before they reach shared repositories.

Mirror production’s plugin versions, caching configurations, and file permissions locally to surface compatibility issues during development rather than deployment.

Enable WP_DEBUG and error logging to catch warnings that might become fatal errors in production environments with stricter PHP configurations.

Supercharge Your Website With Premium Features Using ACF PRO

Speed up your workflow and unlock features to better develop websites using ACF Blocks and Options Pages, with the Flexible Content, Repeater, Clone, Gallery Fields & More.

Explore Features View Pricing

PRO Features
ACF Blocks
Options Pages
PRO Fields
Repeater
Flexible Content
Gallery
Clone

Phase 2: Automated testing

Run automated tests to spot issues that you might miss before pushing your work to version control.

Start on unit tests with PHPUnit for custom functions and Jest for JavaScript components, targeting 70% code coverage on business logic to catch regressions early.

Browser testing with Playwright or Cypress should cover critical user flows like checkout processes, form submissions, and admin functionality that manual testing often misses.

Lock plugin and theme versions using Composer to ensure identical dependencies across all environments, preventing version drift that causes unexpected behavior.

Automated compatibility testing runs on every code change, verifying that plugin updates don’t break existing functionality before reaching staging environments.

Phase 3: Version control

Structure your Git workflow with main, staging, and feature branches where main branch requires pull request reviews and passing status checks before merges.

Track composer.lock and package-lock.json files to ensure dependency versions remain consistent, while excluding uploads/, cache/, and node_modules/ directories that contain generated or temporary files.

Commit database migration scripts or WP-CLI export commands alongside code changes to version control database structure modifications.

💡 ACF Local JSON automatically converts database-stored field groups into trackable JSON files, making custom field changes visible in diffs and deployable through standard Git workflows rather than manual database imports.

Phase 4: Deployment

Auto-deploy feature branches to isolated staging environments for testing, then require manual approval for production promotion to maintain deployment control.

Implement blue-green or atomic deployments using symlink switching to achieve zero-downtime releases with instant rollback capabilities if issues arise.

Configure post-deployment health checks that verify critical functionality, scan for broken links, and run smoke tests with Slack or email notifications for immediate failure alerts.

GitHub Actions provides the foundation for building custom workflows, but WP Engine users can take advantage of their official Action for direct deployment integration with automated database synchronization and file management.

Build smooth WordPress development workflows with ACF

Our four-stage pipeline makes every release predictable and reversible.

With local environment standardization and ACF Local JSON as your foundation, you can gradually layer in automated testing and deployment automation as your team’s confidence grows.

ACF’s Local JSON converts database-stored field groups into trackable files that flow through your Git workflow exactly like theme code or custom functions. Field structure changes become visible in pull requests, deployable through automation, and reversible through version control.

If you’re ready to transform your WordPress workflow, get started with ACF.

The post Transform Chaotic WordPress Sites into Streamlined Workflows appeared first on ACF.

]]>
https://www.advancedcustomfields.com/blog/wordpress-workflow/feed/ 0
Building a WordPress Product Catalog Without WooCommerce https://www.advancedcustomfields.com/blog/wordpress-product-catalog-without-woocommerce/ https://www.advancedcustomfields.com/blog/wordpress-product-catalog-without-woocommerce/#replybox Thu, 04 Sep 2025 12:00:00 +0000 https://www.advancedcustomfields.com/?post_type=blog&p=658371 Key points: Not every business needs a full eCommerce store. A product catalog works when your priority is lead generation rather than direct sales, when you’re targeting wholesale or B2B clients who prefer offline negotiations, or when you simply need to showcase products without the friction of checkout processes. WooCommerce, while powerful, introduces unnecessary overhead […]

The post Building a WordPress Product Catalog Without WooCommerce appeared first on ACF.

]]>
Key points:

  • A product catalog simplifies presentation, reduces complexity, and is ideal for lead generation or targeting B2B and/or wholesale customers.
  • WooCommerce can be adapted as a catalog by removing cart and checkout functionalities, but it requires more work for those wanting to avoid its overhead.
  • Advanced Custom Fields (ACF®) offers more control and flexibility for creating product catalogs, allowing you to build custom post types, fields, and taxonomies without the limitations of plugins like Ultimate Product Catalog.

Not every business needs a full eCommerce store.

A product catalog works when your priority is lead generation rather than direct sales, when you’re targeting wholesale or B2B clients who prefer offline negotiations, or when you simply need to showcase products without the friction of checkout processes.

WooCommerce, while powerful, introduces unnecessary overhead for catalog-only sites. It creates additional database tables, adds unused functionality, and increases your site’s resource footprint. When your goal is just product presentation without transaction processing, this extra weight becomes counterproductive.

We’re going to cover two scenarios for setting up a product catalog: transitioning from an existing WooCommerce setup to a catalog-only approach, and building a product catalog from scratch without WooCommerce dependencies.

Weighing the decision to ditch WooCommerce

Before we walk you through how to completely abandon WooCommerce, you should know that you can also scale it back to work as a simple catalog.

Extensions like YITH WooCommerce Catalog Mode or simple custom code can disable cart functionality, remove pricing, and eliminate checkout processes while preserving the product structure.

This approach has merit: WooCommerce handles the heavy lifting you’d otherwise manage manually – it provides dedicated product post types, taxonomy systems for categories and attributes, built-in template hierarchy, image galleries, product variations, and search functionality. These features require significant development work to replicate from scratch.

Removing WooCommerce means building these systems yourself or finding alternative solutions. You’ll need to create custom post types, design product templates, implement filtering systems, and handle product relationships manually. The time investment is substantial.

However, if you’re committed to avoiding WooCommerce’s database overhead, unused features, and potential performance impact, the manual route offers complete control. You eliminate plugin dependencies, reduce server load, and create exactly the catalog structure your business requires.

The remainder of this guide assumes you’ve weighed these trade-offs and chosen the manual path despite its complexity.

How to create WordPress product catalogs without WooCommerce

If you’ve decided WooCommerce’s overhead isn’t worth the convenience, you have two practical paths forward.

The first method involves using dedicated product catalog plugins that provide catalog-specific functionality without eCommerce bloat. The second uses Advanced Custom Fields (ACF®) to build a completely custom solution tailored to your exact requirements.

Method 1: Using WordPress product catalog plugins

Ultimate Product Catalog stands out as one of the few dedicated WordPress catalog plugins that work standalone, without requiring WooCommerce.

Here’s how to use it to create a simple product catalog:

  1. With the plugin installed and activated, go to Product Catalog > Products from your admin dashboard.
  2. Click Add New Product to start adding items for your catalog. Since the aim here is to keep things simple, we’ll only provide the product’s name (post title), price (entered into the fields below the editor, pictured below), and one photo (post featured image).

Adding a new product in Ultimate Product Catalog

  1. Publish each product after entering its details. Here’s what one should look like:

A product created using Ultimate Product Catalog

  1. With your products ready, go to Product Catalog > Catalogs and click Add New Catalog.
  2. Give your catalog a name by entering it into the post title.
  3. In the Catalog Details section right below the editor, click Add to bring up a list of available items.
  4. Check the products you want to display in the catalog, then click Add Products.

Adding products to a catalog in Ultimate Product Catalog

  1. Publish the catalog, then go back to your admin dashboard.
  2. In Product Catalog > Catalogs, locate the one you just created and copy the shortcode from the table.

How to get a catalog shortcode in Ultimate Product Catalog

  1. Use this shortcode on any page or post where you want to display the catalog – it’s as easy as pasting the shortcode into a shortcode block. Here’s what you should see when you load up the catalog on the frontend:

A catalog created using Ultimate Product Catalog

A few additional tweaks you can make include:

  • Adding product categories via Product Catalog > Categories.
  • Adding tags for each product using the Tags section to the right of the editor when creating or editing them.
  • Adding a currency sign for the price via Product Catalog > Settings > General.
  • Hide the price filtering option via Product Catalog > Settings > Catalog Page Functionality.

As useful as Ultimate Product Catalog is, though, it comes with significant limitations that impact its practicality.

The free version restricts core functionality – you can’t add custom fields, limiting product information to basic details like name, description, and price. Even basic styling is completely unavailable, as you can see from the sample above.

Even with the premium lifetime license, you’ll pay an additional $48 annually for support, making the total cost higher than initially apparent.

While functional, these limitations make Ultimate Product Catalog suitable primarily for barebones catalogs with minimal customization requirements.

Method 2: Creating WordPress product catalogs using ACF

ACF transforms WordPress into a flexible content management system by letting you create custom post types, field groups, and taxonomies without writing code.

This mirrors exactly what WooCommerce does behind the scenes – creating product post types and associated data structures – but puts you in complete control.

With ACF, you define only the fields your catalog actually needs. Instead of WooCommerce’s dozens of product-related database tables storing shipping weights, tax classes, and inventory data you’ll never use, you create a lean structure containing just your essential product information.

This targeted approach significantly reduces database overhead and improves site performance.

The flexibility extends to data management. ACF’s export and import functionality means you can easily migrate existing product data between sites or restructure your catalog without losing information.

If you’re transitioning from a WooCommerce store with, say, 10,000 SKUs, you can export that product data and reimport it into your streamlined catalog structure, preserving your investment in product information while eliminating unnecessary eCommerce complexity.

Let’s run through two approaches you could take.

Supercharge Your Website With Premium Features Using ACF PRO

Speed up your workflow and unlock features to better develop websites using ACF Blocks and Options Pages, with the Flexible Content, Repeater, Clone, Gallery Fields & More.

Explore Features View Pricing

PRO Features
ACF Blocks
Options Pages
PRO Fields
Repeater
Flexible Content
Gallery
Clone

Option 1: Creating WordPress product catalogs as ACF custom post types

This method treats each product as an individual post, with your custom post type archive functioning as the main catalog page. It’s ideal for larger inventories requiring detailed product pages.

Here’s how to do it:

  1. From your admin dashboard, go to ACF > Post Types and add a new one. We’re going to create a custom post type called Products.

Creating a new custom post type for products with ACF

  1. Toggle the Advanced Configuration option on, then check the Excerpt box.

Enabling excerpts for an ACF custom post type

  1. Switch to the URLs tab of the Advanced Settings, toggle Archive on, and add a slug for the URL. This way, you’ll be able to access an archive of your products as posts.

Enabling archives for an ACF custom post type

  1. From your admin dashboard, go to Products > Add New Product to start creating items for your catalog. Enter the product name as the title, the photo as the featured image, and the price as an excerpt. The product details go into the body, but these will only be visible on the product page, not the catalog.
  2. From the admin dashboard, go to Appearance > Editor to open the Site Editor.
  3. Go to Templates and, in the All templates section, click All Archives.

Accessing the archive template in the WordPress Site Editor

  1. This will open the block editor, where you can customize archive pages for all posts, including custom post types. For this walkthrough, we’ll increase the number of columns to five, hide the archive title, and get rid of the dates under each post.
  2. Save the template and visit the product archive. You can find it by adding the slug set in step 3 to your site’s URL. Here’s what you should see:

Using the WordPress post archive as a product catalog

You can click on each item to open it as a post, which will act as the product page. A few other things you can do to spruce things up include:

  • Creating the archive page with a page builder for more styling options than are available with the Gutenberg editor.
  • Use ACF Blocks to output custom field data right within the Gutenberg editor.
  • Use ACF to create custom taxonomies for more filtering options on larger catalogs.
Supercharge Your Website With Premium Features Using ACF PRO

Speed up your workflow and unlock features to better develop websites using ACF Blocks and Options Pages, with the Flexible Content, Repeater, Clone, Gallery Fields & More.

Explore Features View Pricing

PRO Features
ACF Blocks
Options Pages
PRO Fields
Repeater
Flexible Content
Gallery
Clone

Option 2: Creating a single-page WordPress catalog with ACF

The single-page approach consolidates your entire catalog onto one page using ACF PRO’s repeater field functionality. This method suits B2B scenarios where an overview is more important than individual product detail pages.

Here’s how to do it:

  1. From the dashboard, go to ACF > Field Groups and create a repeater field with sub-fields for the product photo, name, and price.

An ACF product details repeater field for product catalogs

  1. Under the field group’s Location Rules, which you can find in the Settings section, set where you want the repeater field to appear. You can connect it to custom post types, forms, or pages. To keep things simple, you can create a dedicated page for the catalog then connect the field to it.

Location rules for a product catalog info repeater field

  1. From your dashboard, open the page – or wherever you’d set – where the repeater field should appear and fill in the sub-fields with your product details.

Entering product details into an ACF repeater field

When you save the page, the product details will be saved to it.

To output the data on the frontend, you can use your page builder of choice. We’ve already done in-depth guides for displaying ACF repeater field content using Elementor, Beaver Builder, Bricks Builder, and WPBakery.

If you want to do it yourself with custom code, all you need to do is loop through each row of the repeater and display the values from its subfields.

Whichever route you choose to go, here’s what the output could look like with some styling:

Using ACF repeater fields to create a product catalog

When using this method for building your product catalogs, here are some tips to help you really elevate things:

  • Combine this with the custom post type method above to give each item in the catalog its own product page. You can do this by having a link as a repeater sub-field, and using its value as the target for a button underneath each item in the catalog.
  • Add more sub-fields that you can use for conditional filtering based on user info, e.g., show items based on whether a user is designated wholesale, retail, or enterprise.

Take charge of your WordPress eCommerce platform with ACF PRO

Building a WordPress product catalog doesn’t require full eCommerce functionality. WooCommerce can function as a catalog by disabling cart and checkout features, preserving its robust product management while eliminating transaction overhead.

However, if you want to avoid WooCommerce entirely, dedicated catalog plugins exist but often prove underpowered and costly considering their limitations.

ACF provides a more flexible solution, letting you build catalogs using custom post types for individual products or use repeater fields on single pages for smaller inventories. Custom fields and taxonomies enable sophisticated organization and filtering capabilities that scale with massive product databases.

ACF’s free version provides substantial functionality for basic catalogs, but ACF PRO unlocks advanced features like repeater fields, flexible content layouts, and conditional logic starting at just $49 annually – a fraction of most catalog plugin costs and significantly less than hiring developers for custom solutions.

Beyond product catalogs, ACF transforms your entire WordPress site into a flexible content management system. You can create custom layouts for team pages, build complex forms, design portfolio galleries, or structure any content type your business requires.

If you’re ready to build a custom product catalog with complete control, get ACF PRO today.

The post Building a WordPress Product Catalog Without WooCommerce appeared first on ACF.

]]>
https://www.advancedcustomfields.com/blog/wordpress-product-catalog-without-woocommerce/feed/ 2
Beaver Builder ACF Integration Guide for WordPress https://www.advancedcustomfields.com/blog/beaver-builder-acf/ https://www.advancedcustomfields.com/blog/beaver-builder-acf/#respond Tue, 02 Sep 2025 11:29:10 +0000 https://www.advancedcustomfields.com/?post_type=blog&p=655006 Key points: If you’re using Advanced Custom Fields (ACF®), you already know what it takes to manually code field displays. And if you’re building with Beaver Builder, you want neater data workflows without touching PHP. The good news is that these tools integrate smoothly when you know what you’re doing. This integration lets ACF users […]

The post Beaver Builder ACF Integration Guide for WordPress appeared first on ACF.

]]>
Key points:

  • Beaver Builder and Advanced Custom Fields (ACF®) integrate smoothly, allowing you to design dynamic layouts without risking your custom field data.
  • You can display everything from basic text fields to complex repeaters and custom post types using modules that support dynamic content.
  • With support for ACF Blocks and advanced features like the Loop module, the setup is scalable and flexible for a wide range of projects.

If you’re using Advanced Custom Fields (ACF®), you already know what it takes to manually code field displays. And if you’re building with Beaver Builder, you want neater data workflows without touching PHP.

The good news is that these tools integrate smoothly when you know what you’re doing.

This integration lets ACF users drag and drop custom field values directly into their layouts while giving Beaver Builder users proper data structure and flexibility. But combining them isn’t always straightforward, especially if you’re worried about breaking existing designs or losing data.

We’ll cover exactly how the ACF-Beaver integration functions, walk through real-world applications that actually matter, and tackle the common issues that trip people up.

Understanding how Beaver Builder and ACF work together

The integration between these tools is intentional, not accidental.

ACF is designed to work with any page builder, while Beaver Builder is specifically built with ACF compatibility in mind. This means you can introduce either tool to an existing workflow without data loss or compatibility headaches.

The magic happens through Beaver Builder’s dynamic data system. Any module displaying a + icon in its settings supports dynamic content, including all your ACF fields. You’re not limited to basic text fields either – Beaver Builder natively recognizes 29 different ACF field types, from simple text and images to complex relationship fields and repeaters.

This integration works whether you’re using the standard Beaver Builder plugin or have upgraded to Beaver Themer. It extends beyond custom fields, too, supporting ACF-powered custom post types and taxonomies.

As developer @JimmyK1995 puts it: “I found that Beaver Builder integrates well with Advanced Custom Fields – and we’ll prove it.

Using Beaver Builder with ACF

Now let’s get practical. We’ll start with basic field connections that take minutes to set up, then move into advanced techniques for complex data structures and custom workflows.

Supercharge Your Website With Premium Features Using ACF PRO

Speed up your workflow and unlock features to better develop websites using ACF Blocks and Options Pages, with the Flexible Content, Repeater, Clone, Gallery Fields & More.

Explore Features View Pricing

PRO Features
ACF Blocks
Options Pages
PRO Fields
Repeater
Flexible Content
Gallery
Clone

Displaying simple ACF fields using Beaver Builder

The simplest integration involves outputting basic ACF data through Beaver Builder’s dynamic content modules. We’ll use a text field as our starting point since it demonstrates the core connection process without complications.

Before getting started, make sure you have an ACF text field created and assigned to your target content type. If you’re working with posts rather than pages, verify that posts are enabled for Beaver Builder editing under Settings > Beaver Builder > Post Types. This foundational setup ensures your fields are accessible when you start building.

When you’re ready, just follow these steps:

  1. Create a new post/page and fill in the ACF meta box with your custom field data.
  2. Save the draft, then launch Beaver Builder.
  3. Add a Text Editor module by dragging it onto the canvas.
  4. Switch to the module’s General tab and look for a + icon.

Adding dynamic data to a Beaver Builder module

  1. Scroll down to the Advanced Custom Fields section, hover over ACF Post Field, then click on Connect.

Connecting a Beaver Builder module to an ACF field

  1. From the Detected Fields dropdown, select your field and the rest of the details should auto-populate.

Getting a Beaver Builder module to display ACF data

  1. Save the settings, and you should see your custom field data appear on the canvas.

ACF data displayed in a Beaver Builder module

  1. Switch to the module’s Style tab to customize its look further. Here’s what it’d look like with some tweaks to the typography (font, color, alignment):

Styling ACF data in a Beaver Builder module

Displaying advanced ACF data with Beaver Builder

Complex field types require more sophisticated handling.

For this section, we’ll go over repeater fields (part of ACF PRO), Beaver Builder’s Loop module for iterating through data sets, and integration with custom post types.

We’ll build a team member directory using an ACF repeater field containing name, profile photo, and bio subfields. This should demonstrate how to handle nested data structures and multiple field types simultaneously.

Set up your ACF repeater field with the three subfields mentioned above. Under location rules, assign it to your target content type – in our case, show if post type equals Team Member. Don’t forget to enable Beaver Builder for your custom post type via Settings > Beaver Builder > Post Types and check the appropriate box.

Enabling Beaver Builder for an ACF custom post type

When you’ve set everything up, here’s what you need to do:

  1. Create a new collection of team members in a post via Team Members > Add New Team Member.
  2. Create new rows and add the repeater data as needed.

Entering ACF repeater field data for a custom post type

  1. Save the draft, then launch Beaver Builder.
  2. Add a Loop module to the canvas. You can find it at the bottom of the list of modules, in the Posts section.

Selecting the Beaver Builder Loop module

  1. Select the blank layout for the loop.

Selecting a layout for a Beaver Builder Loop module

  1. In the module’s settings box, switch to the Content tab.

Switching to the Beaver Builder Loop module content tab

  1. Click the Source dropdown and select ACF Repeater, then enter your repeater field’s name as the Key.

Selecting an ACF repeater field for use with a Loop module in Beaver Builder

  1. Drag a module that supports dynamic content into the loop so you can use it to display the repeater’s sub-fields. We’ll start with a Photo module for the team members’ profile pictures.
  2. Click the + icon next to Photo, then scroll down to the Advanced Custom Fields section and hover over ACF Post Field – Photo, then click Connect.
  3. Fill in the field’s details. You can select it from the Detected Fields dropdown rather than trying to do everything yourself.

Using an ACF field for a photo module in Beaver Builder

  1. Save the module’s settings and you should see the first round of fields looped through and displayed.

Displaying some ACF repeater photos in Beaver Builder

  1. Repeat this process with each of the remaining fields, i.e., adding a Loop module and nesting the relevant modules inside it. Here’s what that should look like, along with the structure on the right:

Displaying ACF repeater data in Beaver Builder

  1. For styling, whatever you apply to one looped module will apply to all others, making it as scalable as you need it to be. Take this example below, where styling the Jay Doe column (alignment, typography, rounding image borders) replicates the styles across all other columns:

Styling ACF repeater field data with Beaver Builder

Displaying ACF Blocks using Beaver Builder

Beaver Builder supports Gutenberg-ready blocks, including ACF Blocks from ACF PRO. This gives you another way to integrate custom field data while maintaining block-based workflows.

Start by creating your ACF Block as you normally would. Just make sure you add "jsx": false to the supports section in your block registration. Without this, your block won’t appear in Beaver Builder’s module list.

Open Beaver Builder and click the + icon to add a new module. Navigate to the Modules tab and scroll down to the ACF Blocks section. Your custom block will be listed here – drag it onto the canvas where you want it to appear.

Adding an ACF Block to Beaver Builder

Fill in the custom fields for your block through Beaver Builder’s interface. The data should render immediately on the canvas, giving you real-time feedback as you build.

Using a custom ACF Block in Beaver Builder

Troubleshooting issues when integrating Beaver Builder with ACF

Even with a solid setup, you might hit roadblocks when combining these tools. Here are the most frequent problems and their solutions:

  • ACF Block fields not showing up happens when your field group location rules aren’t properly configured. Set your location rule to Block is equal to… and select your specific block name.
  • ACF Blocks not appearing in Beaver Builder’s module list occurs when JSX support is enabled in your block configuration. Add "jsx": false to your block’s block.json file to make it visible in Beaver Builder.
  • ACF Block settings displaying in Gutenberg but missing in Beaver Builder results from Beaver’s limited support for extended block.json features. Beaver currently doesn’t recognize most additional block configuration options beyond basic field definitions.
  • Loop module layout issues typically stem from insufficient container structure around your dynamic content. Nest your Loop module inside a Box module to provide proper spacing and alignment controls.
  • ACF data not displaying when using Beaver Builder shortcodes occurs because shortcodes don’t integrate with Beaver’s dynamic data system. Use modules that natively support dynamic data instead of relying on shortcode outputs.

Unlock advanced ACF PRO features in Beaver Builder

The ACF and Beaver Builder combination delivers exactly what both technical and non-technical user bases want: powerful custom field functionality without coding complexity. These tools integrate natively by design, so introducing one to an existing workflow with the other won’t threaten your data or break your designs.

The integration centers around Beaver Builder’s dynamic data system. Any module displaying the + icon can pull ACF field values directly, covering everything from simple text fields to complex data structures. Beaver’s Loop module takes this further, letting you iterate through advanced ACF field types like repeaters without custom PHP.

Don’t overlook ACF Blocks support either. This feature bridges the gap between block-based editing and Beaver Builder’s visual interface, giving you access to more of ACF PRO’s toolkit within your builder workflow.

Ready to unlock these advanced field types and block functionality? Upgrade to ACF PRO to access repeaters, flexible content fields, and the complete ACF Blocks system.

The post Beaver Builder ACF Integration Guide for WordPress appeared first on ACF.

]]>
https://www.advancedcustomfields.com/blog/beaver-builder-acf/feed/ 0