Skip to content

Conversation

@arifulhoque7
Copy link
Contributor

@arifulhoque7 arifulhoque7 commented Nov 24, 2025

fix: correctly detect ACF taxonomies by checking post_content

The wpuf_is_acf_taxonomy() function was incorrectly checking the post_name
field when querying for ACF-registered taxonomies. ACF stores the actual
taxonomy slug in the serialized post_content under the 'taxonomy' key,
while post_name contains ACF's internal identifier (e.g., 'taxonomy_69242380c35d7').

Changes:

  • Modified database query to fetch all acf-taxonomy posts
  • Added loop to unserialize post_content and check taxonomy key
  • ACF taxonomies now properly detected as free fields
  • Removed PRO badge from ACF taxonomy fields in form builder

This ensures ACF custom taxonomies are available in the free version
without requiring PRO upgrade, as they are user-created content.

Close #1672

Summary by CodeRabbit

  • New Features

    • ACF and other non-built-in taxonomies are now treated as part of the free taxonomy set and will render/select without Pro.
    • Taxonomy visibility and filtering for non‑Pro users updated to preserve ACF taxonomies when listing or filtering fields.
    • Added utilities to build and expose the free-taxonomy list used by the UI.
  • Chores

    • Minor array/format refactors for consistency.

✏️ Tip: You can customize this high-level summary in your review settings.

@arifulhoque7 arifulhoque7 requested a review from sapayth November 24, 2025 09:54
@arifulhoque7 arifulhoque7 self-assigned this Nov 24, 2025
@arifulhoque7 arifulhoque7 added needs: testing needs: dev review This PR needs review by a developer labels Nov 24, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 24, 2025

Walkthrough

Replaces static built-in taxonomy checks with a dynamic free-taxonomy set (built-ins + eligible custom/ACF taxonomies) and adds helpers to build that set; updated admin, field, and render logic to consult the dynamic set when Pro is inactive.

Changes

Cohort / File(s) Summary
Helper functions
wpuf-functions.php
Added wpuf_get_taxonomy_post_types($taxonomy_name) and wpuf_get_free_taxonomies(); minor array syntax refactors in related helper functions.
Admin form builder updates
includes/Admin/Forms/Admin_Form_Builder.php
Replaced static built-in taxonomy list with wpuf_get_free_taxonomies() in filter_pro_taxonomy_fields(), has_filtered_taxonomies(), and get_hidden_taxonomy_ids() to determine free vs. gated taxonomies when Pro is inactive.
Field and render updates
includes/Fields/Form_Field_Post_Taxonomy.php, includes/Render_Form.php
Updated is_pro() checks and taxonomy rendering/gating to consult wpuf_get_free_taxonomies() (so eligible custom/ACF taxonomies are treated as free) instead of the static built-in list.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Inspect wpuf_get_free_taxonomies() for correct inclusion rules (built-ins + eligible custom taxonomies) and object_type filtering.
  • Verify no remaining hard-coded built-in-list checks elsewhere and that gating behavior matches intent across admin and front-end rendering.
  • Check added helpers for edge cases when taxonomies have no object_type or unexpected registrations.

Possibly related PRs

Suggested labels

bug, needs: developer feedback

Suggested reviewers

  • sapayth

Poem

🐰 I nudged the taxonomies free and light,

Built-ins and ACF now sit polite.
Fields wake up and whisper, "come play,"
Pro’s gate shifts, but blooms stay. 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR addresses ACF taxonomy detection but the linked issue #1672 requires fixing taxonomy field filtering logic (Selection Type options: Exclude, Include, Child of) which is not addressed in the code changes. The PR fixes ACF taxonomy detection but does not implement the Selection Type filtering requirements from issue #1672. Address the missing filtering logic for Exclude, Include, and Child of options.
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Out of Scope Changes check ❓ Inconclusive The changes appropriately focus on detecting ACF taxonomies and treating them as free fields; however, the PR scope appears narrower than the linked issue requirements which also demand Selection Type filtering logic. Clarify whether the PR is intended to address only ACF taxonomy detection or also the Selection Type filtering requirements from issue #1672, as the linked issue covers both concerns.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'fix: correctly detect ACF taxonomies by checking post_content' accurately reflects the main change: fixing ACF taxonomy detection by checking the post_content field instead of post_name.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a95e20f and 9fb0e06.

📒 Files selected for processing (1)
  • wpuf-functions.php (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • wpuf-functions.php

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
includes/Admin/Forms/Admin_Form_Builder.php (2)

173-176: Optimize repeated calls to wpuf_get_free_taxonomies().

The function wpuf_get_free_taxonomies() is called three times in quick succession (once per method call on lines 174, 175, and 176). According to the PR description, this function queries the database to detect ACF taxonomies by checking post_content, and it also calls get_taxonomies() to retrieve all non-built-in taxonomies.

Consider caching the result to avoid redundant database queries.

Apply this diff to cache the result:

 // Filter pro taxonomy fields and check if any were removed
 $original_fields = wpuf_get_form_fields( $post->ID );
-$filtered_fields = $this->filter_pro_taxonomy_fields( $original_fields );
-$has_hidden_taxonomies = $this->has_filtered_taxonomies( $original_fields, $filtered_fields );
-$hidden_taxonomy_ids = $this->get_hidden_taxonomy_ids( $original_fields, $filtered_fields );
+$free_taxonomies = wpuf_get_free_taxonomies(); // Cache the result
+$filtered_fields = $this->filter_pro_taxonomy_fields( $original_fields, $free_taxonomies );
+$has_hidden_taxonomies = $this->has_filtered_taxonomies( $original_fields, $filtered_fields, $free_taxonomies );
+$hidden_taxonomy_ids = $this->get_hidden_taxonomy_ids( $original_fields, $filtered_fields, $free_taxonomies );

Then update the three method signatures to accept an optional $free_taxonomies parameter:

protected function filter_pro_taxonomy_fields( $form_fields, $free_taxonomies = null ) {
    // If pro is active, return all fields
    if ( wpuf_is_pro_active() ) {
        return $form_fields;
    }

    // Get free taxonomies (built-in + ACF taxonomies)
    if ( null === $free_taxonomies ) {
        $free_taxonomies = wpuf_get_free_taxonomies();
    }
    
    // ... rest of the method
}

Apply the same pattern to has_filtered_taxonomies and get_hidden_taxonomy_ids.


173-176: Add caching to wpuf_is_acf_taxonomy() to prevent redundant database queries.

The implementation at lines 5720-5770 in wpuf-functions.php executes a full database query on every call to fetch all ACF taxonomy posts without caching. Combined with wpuf_get_free_taxonomies() calling this function once per non-builtin taxonomy (line 5804), and Admin_Form_Builder.php calling wpuf_get_free_taxonomies() at least three times (lines 521, 553, 595), this creates redundant queries for identical data in a single admin page load.

Consider implementing either:

  • Static variable memoization within wpuf_is_acf_taxonomy() to cache results during execution
  • Transient caching (similar to the PRO_FIELD_ASSETS pattern at lines 485-496) to cache ACF taxonomy mappings across requests
🧹 Nitpick comments (1)
wpuf-functions.php (1)

5708-5781: ACF taxonomy detection works but could use caching and a simpler fallback

The new wpuf_is_acf_taxonomy() and wpuf_get_free_taxonomies() look functionally correct and match the PR intent (treat built‑ins + ACF taxonomies as free). Two improvement points:

  1. Avoid repeated full‑table scans for ACF taxonomies

wpuf_get_free_taxonomies() iterates over every non‑builtin taxonomy and calls wpuf_is_acf_taxonomy(), which in turn runs the same SELECT post_content FROM {$wpdb->posts} WHERE post_type = 'acf-taxonomy' ... on every call. On sites with many custom taxonomies or ACF taxonomy definitions this can become unnecessarily expensive per request.

You can cache the discovered ACF taxonomy slugs once per request and reuse them:

-if ( ! function_exists( 'wpuf_is_acf_taxonomy' ) ) {
-    function wpuf_is_acf_taxonomy( $taxonomy_name ) {
-        // If taxonomy doesn't exist, it can't be an ACF taxonomy
-        if ( ! taxonomy_exists( $taxonomy_name ) ) {
-            return false;
-        }
-
-        // Get the taxonomy object
-        $taxonomy = get_taxonomy( $taxonomy_name );
-        
-        if ( ! $taxonomy ) {
-            return false;
-        }
-
-        // Check if ACF is active
-        if ( ! class_exists( 'acf' ) ) {
-            return false;
-        }
-
-        global $wpdb;
-
-        $acf_taxonomies = $wpdb->get_results(
-            "SELECT post_content FROM {$wpdb->posts}
-            WHERE post_type = 'acf-taxonomy'
-            AND post_status = 'publish'"
-        );
-
-        if ( ! empty( $acf_taxonomies ) ) {
-            foreach ( $acf_taxonomies as $acf_tax ) {
-                $config = maybe_unserialize( $acf_tax->post_content );
-
-                if ( is_array( $config ) && isset( $config['taxonomy'] ) && $config['taxonomy'] === $taxonomy_name ) {
-                    return true;
-                }
-            }
-        }
-
-        // Additional check block…
-        if ( isset( $taxonomy->acf ) || isset( $taxonomy->_builtin ) && ! $taxonomy->_builtin ) {
-            if ( function_exists( 'acf_get_internal_post_type' ) ) {
-                $internal_types = acf_get_internal_post_type( 'acf-taxonomy', 'names' );
-                if ( is_array( $internal_types ) && in_array( $taxonomy_name, $internal_types, true ) ) {
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-}
+if ( ! function_exists( 'wpuf_is_acf_taxonomy' ) ) {
+    function wpuf_is_acf_taxonomy( $taxonomy_name ) {
+        static $acf_taxonomy_slugs = null;
+
+        if ( ! taxonomy_exists( $taxonomy_name ) || ! class_exists( 'acf' ) ) {
+            return false;
+        }
+
+        if ( null === $acf_taxonomy_slugs ) {
+            global $wpdb;
+
+            $acf_taxonomy_slugs = [];
+
+            $acf_posts = $wpdb->get_results(
+                "SELECT post_content FROM {$wpdb->posts}
+                 WHERE post_type = 'acf-taxonomy'
+                 AND post_status = 'publish'"
+            );
+
+            foreach ( (array) $acf_posts as $acf_post ) {
+                $config = maybe_unserialize( $acf_post->post_content );
+
+                if ( is_array( $config ) && ! empty( $config['taxonomy'] ) ) {
+                    $acf_taxonomy_slugs[] = $config['taxonomy'];
+                }
+            }
+
+            $acf_taxonomy_slugs = array_unique( $acf_taxonomy_slugs );
+        }
+
+        return in_array( $taxonomy_name, $acf_taxonomy_slugs, true );
+    }
+}

You can similarly cache the result of wpuf_get_free_taxonomies() if you expect it to be called multiple times in a single request:

-if ( ! function_exists( 'wpuf_get_free_taxonomies' ) ) {
-    function wpuf_get_free_taxonomies() {
+if ( ! function_exists( 'wpuf_get_free_taxonomies' ) ) {
+    function wpuf_get_free_taxonomies() {
+        static $cached = null;
+
+        if ( null !== $cached ) {
+            return $cached;
+        }
@@
-        // Allow filtering to add more free taxonomies
-        $free_taxonomies = apply_filters( 'wpuf_free_taxonomies', $free_taxonomies );
+        // Allow filtering to add more free taxonomies
+        $free_taxonomies = apply_filters( 'wpuf_free_taxonomies', $free_taxonomies );
@@
-        return $free_taxonomies;
+        $cached = $free_taxonomies;
+
+        return $cached;
     }
 }
  1. Questionable fallback using acf_get_internal_post_type

The current fallback compares $taxonomy_name against $internal_types returned by acf_get_internal_post_type( 'acf-taxonomy', 'names' ). Since $taxonomy_name is a taxonomy slug (e.g., genre), and acf_get_internal_post_type returns internal post type identifiers, this condition is unlikely ever to be true. With the serialized‑config check in place, you can safely drop this branch, or at least document a concrete scenario where taxonomy slugs are expected to match those internal identifiers.

  1. Minor docblock nit

Both new docblocks use @since WPUF_SINCE; consider replacing that placeholder with the actual version string before release to keep API docs accurate.

Also applies to: 5792-5811

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 47b6597 and bb1fc6b.

📒 Files selected for processing (4)
  • includes/Admin/Forms/Admin_Form_Builder.php (5 hunks)
  • includes/Fields/Form_Field_Post_Taxonomy.php (2 hunks)
  • includes/Render_Form.php (2 hunks)
  • wpuf-functions.php (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
includes/Admin/Forms/Admin_Form_Builder.php (1)
wpuf-functions.php (1)
  • wpuf_get_free_taxonomies (5793-5811)
wpuf-functions.php (1)
includes/Render_Form.php (1)
  • taxonomy (1354-1518)
includes/Fields/Form_Field_Post_Taxonomy.php (1)
wpuf-functions.php (2)
  • wpuf_get_free_taxonomies (5793-5811)
  • wpuf_is_pro_active (4988-4990)
includes/Render_Form.php (1)
wpuf-functions.php (2)
  • wpuf_get_free_taxonomies (5793-5811)
  • wpuf_is_pro_active (4988-4990)
🔇 Additional comments (4)
includes/Render_Form.php (1)

1332-1346: Gating logic now correctly uses the shared free-taxonomy helper

Using wpuf_get_free_taxonomies() in both is_taxonomy_field_gated() and taxonomy() aligns frontend gating with the new central helper (built‑in + ACF taxonomies) and with the form‑field class, so ACF taxonomies won’t be blocked in the free version while still respecting Pro checks. No issues spotted in the control flow.

Also applies to: 1355-1359

includes/Fields/Form_Field_Post_Taxonomy.php (1)

49-59: Post‑taxonomy field now shares a single source of truth for free vs pro gating

is_pro() and render() both delegate to wpuf_get_free_taxonomies() plus wpuf_is_pro_active(), so the builder/field class and frontend renderer gate taxonomies the same way (built‑ins + ACF allowed in free; other custom taxonomies hidden when Pro is inactive). This matches the PR’s goal and looks logically sound.

Also applies to: 71-79

includes/Admin/Forms/Admin_Form_Builder.php (2)

514-538: Logic looks correct for filtering taxonomy fields.

The dynamic taxonomy detection properly handles built-in and ACF taxonomies by using wpuf_get_free_taxonomies(). The filtering logic correctly retains free taxonomies while excluding custom non-ACF taxonomies when PRO is inactive.


587-617: Logic correctly identifies hidden taxonomy field IDs.

The method properly extracts IDs of custom taxonomy fields that were filtered out, enabling client-side preservation of these fields when PRO is activated later.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

Verify the fallback to taxonomy key is necessary.

Line 571 extracts the taxonomy slug with $f['name'] ?? ($f['taxonomy'] ?? null), falling back to the taxonomy key. However, the other methods (filter_pro_taxonomy_fields and get_hidden_taxonomy_ids) only check $field['name'].

Ensure this fallback is intentional and that taxonomy fields can indeed have the slug under either key, or consider aligning the extraction logic across all three methods for consistency.


🏁 Script executed:

#!/bin/bash
# Description: Search for taxonomy field structures to verify which keys are used for the taxonomy slug

# Search for where taxonomy fields are created/structured
rg -n -C3 'input_type.*taxonomy|taxonomy.*input_type' --type=php

# Look for assignments to taxonomy field 'name' or 'taxonomy' keys
ast-grep --pattern $'$field[\'name\'] = $_'
ast-grep --pattern $'$field[\'taxonomy\'] = $_'

Length of output: 16231



🏁 Script executed:

#!/bin/bash
# Search for where 'taxonomy' key is actually assigned to fields
rg -n -C2 "\['taxonomy'\]\s*=" --type=php | head -50

# Also search for field definitions that might have taxonomy key
rg -n "taxonomy.*=>|'taxonomy'" --type=php -C2 | grep -E "\['taxonomy'\]|'taxonomy'\s*=>" | head -30

Length of output: 4029



🏁 Script executed:

#!/bin/bash
# Search for how nested/column fields are constructed to see which keys they preserve
rg -n -B5 -A5 "column_field|inner.*field" includes/Admin/Forms/Admin_Form_Builder.php | head -60

# Also check the actual field structure in the stack-based traversal
rg -n -B10 -A10 "has_filtered_taxonomies" includes/Admin/Forms/Admin_Form_Builder.php

Length of output: 3215


Align the taxonomy slug extraction with other methods for consistency.

Line 571 extracts the slug with a fallback to $f['taxonomy'], but filter_pro_taxonomy_fields (line 528) and get_hidden_taxonomy_ids (line 607) only check $field['name']. Since all observed field definitions consistently populate the name key, the fallback appears unnecessary. Either document why the taxonomy key fallback is needed for nested fields, or remove it to align with the other methods.

🤖 Prompt for AI Agents
In includes/Admin/Forms/Admin_Form_Builder.php around lines 570 to 572, the code
falls back to $f['taxonomy'] when extracting the slug but other methods
(filter_pro_taxonomy_fields at line 528 and get_hidden_taxonomy_ids at line 607)
only use $field['name']; remove the unnecessary fallback and read the slug
strictly from $f['name'] (e.g., $slug = $f['name'] ?? null), update the
conditional accordingly, and add a brief inline comment if you believe nested
fields require a different key so future readers know why only 'name' is used.

@Rubaiyat-E-Mohammad Rubaiyat-E-Mohammad added QA Approved This PR is approved by the QA team and removed needs: testing labels Nov 25, 2025
Introduced wpuf_get_taxonomy_post_types() to retrieve post types associated with a taxonomy. Updated wpuf_get_free_taxonomies() to include taxonomies linked to 'post' or 'page' post types in the free list, improving extensibility and compatibility with custom and ACF taxonomies.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
wpuf-functions.php (1)

5816-5866: wpuf_get_free_taxonomies broadens “free” scope; confirm intent and consider filter + naming tweaks

A few points on this helper:

  1. Scope of “free” taxonomies is broader than just ACF
    The docblock says this “includes built-in taxonomies and ACF-registered taxonomies,” but the logic adds any taxonomy whose object_type includes post or page:

    $all_taxonomies   = get_taxonomies( array(), 'names' );
    ...
    $post_types       = wpuf_get_taxonomy_post_types( $taxonomy_name );
    $allowed_post_types = array( 'post', 'page' );
    ...
    if ( in_array( $post_type, $allowed_post_types, true ) ) {
        $free_taxonomies[] = $taxonomy_name;
    }

    That means all non‑ACF custom taxonomies registered for post or page also become “free”, not just those created via ACF. If your Pro gating model is “only built‑ins + ACF taxonomies are free,” this implementation relaxes it further.

    If the broader behavior is intentional, I’d update the comment to say so explicitly. If not, you likely want to either:

    • Use wpuf_is_acf_taxonomy( $taxonomy_name ) in this loop to selectively add only ACF‑managed taxonomies, or
    • Restrict by a more precise rule (e.g., a dedicated allow‑list filter just for ACF taxonomies).
  2. Commented-out filter removes an extension point
    The commented line:

    // $free_taxonomies = apply_filters( 'wpuf_free_taxonomies', $free_taxonomies );

    suggests this was meant to be pluggable. If Pro gating is not considered a hard security boundary, re-enabling this filter (and documenting that it controls free/Pro taxonomy availability) would make the behavior easier to customize without patching core.

  3. Minor consistency / naming nit
    $has_allowed_type could be renamed to $has_allowed_post_type for clarity, but that’s purely cosmetic.

If the goal is exactly “built‑in + ACF taxonomies are free, everything else stays Pro‑only”, I’d expect something closer to:

-        foreach ( $all_taxonomies as $taxonomy_name ) {
+        foreach ( $all_taxonomies as $taxonomy_name ) {
             if ( in_array( $taxonomy_name, $free_taxonomies, true ) ) {
                 continue;
             }

-            $post_types = wpuf_get_taxonomy_post_types( $taxonomy_name );
-
-            if ( ! empty( $post_types ) ) {
-                $allowed_post_types = array( 'post', 'page' );
-                $has_allowed_type = false;
-
-                foreach ( $post_types as $post_type ) {
-                    if ( in_array( $post_type, $allowed_post_types, true ) ) {
-                        $has_allowed_type = true;
-                        break;
-                    }
-                }
-
-                if ( $has_allowed_type ) {
-                    $free_taxonomies[] = $taxonomy_name;
-                }
-            }
+            // Only treat ACF-managed taxonomies as free in addition to built-ins.
+            if ( wpuf_is_acf_taxonomy( $taxonomy_name ) ) {
+                $free_taxonomies[] = $taxonomy_name;
+            }
         }

Then, if you still want to include all post/page taxonomies, you could do that via a filter:

return apply_filters( 'wpuf_free_taxonomies', array_unique( $free_taxonomies ) );

Given this function directly controls free vs Pro availability, please confirm with product/PM whether the expanded behavior (all post/page taxonomies being free) is intentional before shipping.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb1fc6b and 62bdbec.

📒 Files selected for processing (1)
  • wpuf-functions.php (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
wpuf-functions.php (3)
includes/Render_Form.php (1)
  • taxonomy (1354-1518)
admin/template-post.php (1)
  • taxonomy (122-237)
includes/Admin/Forms/Template_Post.php (1)
  • taxonomy (130-280)
🔇 Additional comments (1)
wpuf-functions.php (1)

5783-5814: Helper wpuf_get_taxonomy_post_types looks correct and safe

This helper cleanly wraps get_taxonomy()->object_type, returning an empty array when the taxonomy doesn’t exist or the object is missing. That defensive behavior is appropriate for use in feature‑gating logic.

No changes needed here.

Comment on lines 5708 to 5781
/**
* Check if a taxonomy is registered by Advanced Custom Fields (ACF)
*
* ACF taxonomies should be available in the free version as they are user-created
* via ACF, not plugin-specific custom taxonomies.
*
* @since WPUF_SINCE
*
* @param string $taxonomy_name The taxonomy name to check
* @return bool True if taxonomy is registered by ACF, false otherwise
*/
if ( ! function_exists( 'wpuf_is_acf_taxonomy' ) ) {
function wpuf_is_acf_taxonomy( $taxonomy_name ) {
// If taxonomy doesn't exist, it can't be an ACF taxonomy
if ( ! taxonomy_exists( $taxonomy_name ) ) {
return false;
}

// Get the taxonomy object
$taxonomy = get_taxonomy( $taxonomy_name );

if ( ! $taxonomy ) {
return false;
}

// ACF taxonomies typically have these characteristics:
// 1. They are not built-in (_builtin = false)
// 2. They are registered by ACF (check for ACF-specific properties)

// Check if ACF is active
if ( ! class_exists( 'acf' ) ) {
return false;
}

// ACF stores taxonomy configuration in the database
// Check if there's an ACF post type that registered this taxonomy
global $wpdb;

// ACF saves custom taxonomies as posts of type 'acf-taxonomy'
// The taxonomy slug is stored in the serialized post_content, not post_name
// post_name is ACF's internal key like 'taxonomy_69242380c35d7'
$acf_taxonomies = $wpdb->get_results(
"SELECT post_content FROM {$wpdb->posts}
WHERE post_type = 'acf-taxonomy'
AND post_status = 'publish'"
);

if ( ! empty( $acf_taxonomies ) ) {
foreach ( $acf_taxonomies as $acf_tax ) {
// ACF stores the taxonomy configuration as serialized data
$config = maybe_unserialize( $acf_tax->post_content );

// Check if the taxonomy key matches our taxonomy name
if ( is_array( $config ) && isset( $config['taxonomy'] ) && $config['taxonomy'] === $taxonomy_name ) {
return true;
}
}
}

// Additional check: ACF taxonomies often have 'acf' in their labels or registration
// Check if the taxonomy object has ACF-specific metadata
if ( isset( $taxonomy->acf ) || isset( $taxonomy->_builtin ) && ! $taxonomy->_builtin ) {
// Check if registered via ACF by looking for ACF functions
if ( function_exists( 'acf_get_internal_post_type' ) ) {
$internal_types = acf_get_internal_post_type( 'acf-taxonomy', 'names' );
if ( is_array( $internal_types ) && in_array( $taxonomy_name, $internal_types, true ) ) {
return true;
}
}
}

return false;
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

ACF Advanced Custom Fields class bootstrap activation check

💡 Result:

Short answer — use plugin checks first, and fall back to class/function checks. Example (best practice per ACF docs):

  • In admin or after including plugin.php:
    if ( is_plugin_active( 'advanced-custom-fields-pro/acf.php' ) || is_plugin_active( 'advanced-custom-fields/acf.php' ) ) {
    // ACF (or ACF Pro) is active — do nothing / prefer site plugin.
    }

  • If you need to detect at runtime (front-end or bundled ACF fallback), use class_exists() / function_exists():
    if ( class_exists( 'acf' ) || class_exists( 'acf_pro' ) || function_exists( 'acf' ) ) {
    // ACF is available.
    } else {
    // Include/bundle ACF safely (define path, include acf.php, set acf/settings/url, hide admin UI, etc.).
    }

References:

  • ACF official guide: including/bundling and plugin detection. [1]
  • Community guidance (class_exists / is_plugin_active usage). [2]

Sources:
[1] Advanced Custom Fields — How to Include ACF PRO in a Plugin or Theme.
[2] WordPress StackExchange / ACF inclusion examples.


🌐 Web query:

acf_get_internal_post_type ACF function signature documentation

💡 Result:

Signature (ACF ≥6.1):

acf_get_internal_post_type( int|string $id, string $post_type ) : array|false

  • Description: Returns an ACF internal post type as an array, or false on failure. [1]

Source: ACF Internal Post Type functions reference. [1]


🏁 Script executed:

# Search the codebase for calls to wpuf_is_acf_taxonomy to assess call frequency
rg "wpuf_is_acf_taxonomy" --type php -B 2 -A 2

Repository: weDevsOfficial/wp-user-frontend

Length of output: 206


Tighten ACF detection and remove the broken fallback heuristic

The core DB-based detection of ACF taxonomies is correct, but two issues need fixing:

  1. ACF detection should use a fallback chain
    The current check class_exists( 'acf' ) is insufficient. Per ACF best practice, use a fallback chain to handle different ACF versions and loading contexts:
-        if ( ! class_exists( 'acf' ) ) {
+        if ( ! class_exists( 'acf' ) && ! class_exists( 'acf_pro' ) && ! function_exists( 'acf' ) ) {
             return false;
         }
  1. Remove the broken acf_get_internal_post_type() fallback block
    The fallback block calling acf_get_internal_post_type( 'acf-taxonomy', 'names' ) is incorrect. Per ACF docs, acf_get_internal_post_type( int|string $id, string $post_type ) : array|false accepts an $id and $post_type parameter and returns a single post type object (or false), not a list of taxonomy slugs. The current call won't return what the code expects, and the in_array() check will always fail.

Since the preceding DB query already correctly identifies ACF taxonomies, remove the broken heuristic entirely:

-        // Additional check: ACF taxonomies often have 'acf' in their labels or registration
-        // Check if the taxonomy object has ACF-specific metadata
-        if ( isset( $taxonomy->acf ) || isset( $taxonomy->_builtin ) && ! $taxonomy->_builtin ) {
-            // Check if registered via ACF by looking for ACF functions
-            if ( function_exists( 'acf_get_internal_post_type' ) ) {
-                $internal_types = acf_get_internal_post_type( 'acf-taxonomy', 'names' );
-                if ( is_array( $internal_types ) && in_array( $taxonomy_name, $internal_types, true ) ) {
-                    return true;
-                }
-            }
-        }
  1. Performance: cache ACF taxonomy slugs across calls (optional)
    Every call runs a full DB query and unserializes all ACF taxonomy configs. For repeated calls within a request, a static cache improves performance with minimal overhead:
-        $acf_taxonomies = $wpdb->get_results(
-            "SELECT post_content FROM {$wpdb->posts}
-            WHERE post_type = 'acf-taxonomy'
-            AND post_status = 'publish'"
-        );
-
-        if ( ! empty( $acf_taxonomies ) ) {
-            foreach ( $acf_taxonomies as $acf_tax ) {
-                // ACF stores the taxonomy configuration as serialized data
-                $config = maybe_unserialize( $acf_tax->post_content );
-
-                // Check if the taxonomy key matches our taxonomy name
-                if ( is_array( $config ) && isset( $config['taxonomy'] ) && $config['taxonomy'] === $taxonomy_name ) {
-                    return true;
-                }
-            }
-        }
+        static $acf_taxonomy_slugs = null;
+
+        if ( null === $acf_taxonomy_slugs ) {
+            $acf_taxonomy_slugs = [];
+
+            $acf_posts = $wpdb->get_results(
+                "SELECT post_content FROM {$wpdb->posts}
+                 WHERE post_type = 'acf-taxonomy'
+                 AND post_status = 'publish'"
+            );
+
+            foreach ( $acf_posts as $acf_post ) {
+                $config = maybe_unserialize( $acf_post->post_content );
+
+                if ( is_array( $config ) && ! empty( $config['taxonomy'] ) ) {
+                    $acf_taxonomy_slugs[] = $config['taxonomy'];
+                }
+            }
+        }
+
+        if ( in_array( $taxonomy_name, $acf_taxonomy_slugs, true ) ) {
+            return true;
+        }
🤖 Prompt for AI Agents
In wpuf-functions.php around lines 5708 to 5781, tighten ACF detection by
replacing the simple class_exists('acf') check with a fallback chain that checks
for acf(), function_exists('acf_get_instance'), and class_exists('ACF'), then
remove the broken acf_get_internal_post_type() fallback block entirely (it
returns a single post object or false, not an array of taxonomy slugs), and
implement a static cache for the DB-driven discovery of ACF taxonomies so the
query + maybe_unserialize work only once per request; ensure the DB loop remains
the primary detector and short-circuits true when a matching config['taxonomy']
=== $taxonomy_name is found, otherwise return false.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
wpuf-functions.php (2)

5821-5831: Remove the broken acf_get_internal_post_type() fallback block.

The fallback block calling acf_get_internal_post_type( 'acf-taxonomy', 'names' ) is incorrect. Per ACF docs, acf_get_internal_post_type( int|string $id, string $post_type ) accepts an $id and $post_type parameter and returns a single post type object (or false), not a list of taxonomy slugs. The current call won't return what the code expects, and the in_array() check will always fail.

Since the preceding DB query (lines 5803-5819) already correctly identifies ACF taxonomies, remove this broken heuristic entirely:

-        // Additional check: ACF taxonomies often have 'acf' in their labels or registration
-        // Check if the taxonomy object has ACF-specific metadata
-        if ( isset( $taxonomy->acf ) || isset( $taxonomy->_builtin ) && ! $taxonomy->_builtin ) {
-            // Check if registered via ACF by looking for ACF functions
-            if ( function_exists( 'acf_get_internal_post_type' ) ) {
-                $internal_types = acf_get_internal_post_type( 'acf-taxonomy', 'names' );
-                if ( is_array( $internal_types ) && in_array( $taxonomy_name, $internal_types, true ) ) {
-                    return true;
-                }
-            }
-        }
-
         return false;
     }
 }

Based on past review comments and ACF function signature documentation.


5792-5792: Strengthen ACF detection with fallback chain.

The current check class_exists( 'acf' ) is insufficient. Per ACF best practice, use a fallback chain to handle different ACF versions and loading contexts:

-        if ( ! class_exists( 'acf' ) ) {
+        if ( ! class_exists( 'acf' ) && ! class_exists( 'acf_pro' ) && ! function_exists( 'acf' ) ) {
             return false;
         }

Based on past review comments and ACF documentation.

🧹 Nitpick comments (2)
wpuf-functions.php (2)

5803-5819: Consider caching ACF taxonomy slugs across calls (optional).

Every call runs a full DB query and unserializes all ACF taxonomy configs. For repeated calls within a request, a static cache improves performance with minimal overhead:

+        static $acf_taxonomy_slugs = null;
+
+        if ( null === $acf_taxonomy_slugs ) {
+            $acf_taxonomy_slugs = [];
+
-        $acf_taxonomies = $wpdb->get_results(
-            "SELECT post_content FROM {$wpdb->posts}
-            WHERE post_type = 'acf-taxonomy'
-            AND post_status = 'publish'"
-        );
-
-        if ( ! empty( $acf_taxonomies ) ) {
-            foreach ( $acf_taxonomies as $acf_tax ) {
-                // ACF stores the taxonomy configuration as serialized data
-                $config = maybe_unserialize( $acf_tax->post_content );
-
-                // Check if the taxonomy key matches our taxonomy name
-                if ( is_array( $config ) && isset( $config['taxonomy'] ) && $config['taxonomy'] === $taxonomy_name ) {
-                    return true;
-                }
-            }
+            $acf_posts = $wpdb->get_results(
+                "SELECT post_content FROM {$wpdb->posts}
+                 WHERE post_type = 'acf-taxonomy'
+                 AND post_status = 'publish'"
+            );
+
+            foreach ( $acf_posts as $acf_post ) {
+                $config = maybe_unserialize( $acf_post->post_content );
+
+                if ( is_array( $config ) && ! empty( $config['taxonomy'] ) ) {
+                    $acf_taxonomy_slugs[] = $config['taxonomy'];
+                }
+            }
+        }
+
+        if ( in_array( $taxonomy_name, $acf_taxonomy_slugs, true ) ) {
+            return true;
         }

Based on past review comments.


5885-5885: Clarify or remove commented filter.

The filter wpuf_free_taxonomies is commented out. If this filter is intentionally disabled, add a comment explaining why. If it should be enabled, uncomment it:

-        // Allow filtering to add more free taxonomies
-        //$free_taxonomies = apply_filters( 'wpuf_free_taxonomies', $free_taxonomies );
+        // Allow filtering to add more free taxonomies
+        $free_taxonomies = apply_filters( 'wpuf_free_taxonomies', $free_taxonomies );

Or if intentionally disabled:

-        // Allow filtering to add more free taxonomies
-        //$free_taxonomies = apply_filters( 'wpuf_free_taxonomies', $free_taxonomies );
+        // Filter intentionally disabled to prevent manual addition of premium taxonomies
+        // $free_taxonomies = apply_filters( 'wpuf_free_taxonomies', $free_taxonomies );
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 62bdbec and a95e20f.

📒 Files selected for processing (2)
  • includes/Render_Form.php (2 hunks)
  • wpuf-functions.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • includes/Render_Form.php
🧰 Additional context used
🧬 Code graph analysis (1)
wpuf-functions.php (1)
includes/Render_Form.php (1)
  • taxonomy (1354-1518)
🔇 Additional comments (1)
wpuf-functions.php (1)

5847-5868: LGTM!

The function correctly retrieves post types associated with a taxonomy, with proper validation and fallback handling.

Deleted the wpuf_is_acf_taxonomy() function and related logic for identifying ACF-registered taxonomies. Also updated array syntax to short arrays in several places for consistency.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs: dev review This PR needs review by a developer QA Approved This PR is approved by the QA team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unexpected Behavior in Taxonomy Input Field on Post Form v4.1.8

2 participants