Quick reference for understanding the codebase. Last updated: December 2024.
📖 See Also: Documentation Index | Developer Guide | Plugin Structure | Admin System
| Column | Type | Notes |
|---|---|---|
| id | bigint | Primary key |
| title | varchar | Display name |
| field_key | varchar | Unique slug |
| description | text | Optional |
| status | varchar | 'active' or 'inactive' |
| settings | longtext | JSON: { position, priority } |
| menu_order | int | Sort order |
| Column | Type | Notes |
|---|---|---|
| id | bigint | Primary key |
| fieldset_id | bigint | FK to fieldsets |
| parent_id | bigint | For repeater sub-fields |
| label | varchar | Display name |
| name | varchar | Meta key (no prefix stored) |
| type | varchar | text, select, switch, etc. |
| field_config | longtext | JSON: type-specific settings |
| wrapper_config | longtext | JSON: { width, class, id } |
| conditional_logic | longtext | JSON: [[{field, operator, value}]] |
| menu_order | int | Sort order |
| Column | Type | Notes |
|---|---|---|
| id | bigint | Primary key |
| fieldset_id | bigint | FK to fieldsets |
| param | varchar | post_type, taxonomy, user_role |
| operator | varchar | == or != |
| value | varchar | The value to match |
| group_id | int | Same group = AND, diff group = OR |
META_PREFIX = '' (empty)
Fields save directly to meta tables without prefix:
- Posts:
wp_postmeta→field_name(notof_field_name) - Terms:
wp_termmeta→field_name - Users:
wp_usermeta→field_name
This provides ACF compatibility for migrations.
Renders fields on:
- Posts/Pages:
add_meta_boxeshook - Taxonomy Terms:
{taxonomy}_add_form_fields,{taxonomy}_edit_form_fieldshooks - Users:
show_user_profile,edit_user_profile,user_new_formhooks
Key methods:
render_meta_box($post, $meta_box)- Post edit screenrender_taxonomy_add_fields($taxonomy)- Term add formrender_taxonomy_edit_fields($term, $taxonomy)- Term edit formrender_user_fields($user)- User profilerender_input($field, $value, ...)- Field type switch
Determines which fieldsets show where.
Key methods:
get_fieldsets_for_context($context)- Returns matching fieldsetsmatch($location_rules, $context)- Evaluates rulesmatch_post_type(),match_taxonomy(),match_user_role()- Individual matchers
Context structure:
$context = [
'post_type' => 'page',
'taxonomy' => 'category', // For term screens
'user_roles' => ['administrator'], // For user screens
];All admin CRUD operations via REST.
Endpoints:
GET/POST /fieldsets- List/createGET/PUT/DELETE /fieldsets/{id}- Single fieldsetGET/POST /fieldsets/{id}/fields- Fields for fieldsetPUT/DELETE /fields/{id}- Single field
stores/
├── fieldset-store.ts # Fieldsets, fields, pending changes
└── ui-store.ts # Toasts, modals
Key pattern: Local staging before save
addFieldLocal()- Stage new fieldupdateFieldLocal()- Stage changesdeleteFieldLocal()- Stage deletionsaveAllChanges()- Batch API call
Defines available field types with:
type- Unique identifierlabel- Display namecategory- For grouping in selectorhasSubFields- For repeater/group typesSettingsComponent- React component for config
Each field type has a settings component:
TextFieldSettings.tsxSelectFieldSettings.tsxSwitchFieldSettings.tsx- etc.
// Outer array = OR groups
// Inner array = AND rules within group
[
[{ field: "field_1", operator: "==", value: "yes" }], // Group 1
[{ field: "field_2", operator: "!=", value: "" }] // OR Group 2
]==- Equals!=- Not equalscontains- String containsempty- Is empty/falsynot_empty- Has value
initConditionalLogic()- Setup listenersevaluateAllConditions()- Check all fieldsevaluateRuleGroup(rules)- Single group (AND)compareValues(current, operator, expected)- Single comparison
plugin/
├── openfields.php # Entry point
├── includes/
│ ├── admin/
│ │ ├── class-openfields-meta-box.php # Field rendering
│ │ └── field-renderers/ # Complex field types
│ │ ├── repeater.php
│ │ ├── image.php
│ │ ├── gallery.php
│ │ └── ...
│ ├── locations/
│ │ └── class-openfields-location-manager.php
│ └── class-openfields-rest-api.php
└── assets/admin/
├── css/fields.css # Field styling
└── js/fields.js # Field interactions
admin/
├── src/
│ ├── pages/
│ │ ├── FieldsetList.tsx
│ │ └── FieldsetEditor/
│ │ └── components/
│ │ ├── FieldItem.tsx
│ │ ├── LocationsSection.tsx
│ │ └── ConditionalLogicPanel.tsx
│ ├── stores/
│ │ └── fieldset-store.ts
│ ├── fields/ # Field settings components
│ └── lib/
│ └── field-registry.ts
└── package.json
- Database column names: Use
status = 'active', notis_active = 1 - Field order column: Use
menu_order, notsort_order - Meta prefix: Empty string - fields save directly as
field_name - Conditional logic structure:
[[rules]]- outer OR, inner AND - Field selectors in JS: Use
field_name, notopenfields_field_name
| Location Type | Where to Test |
|---|---|
post_type == post |
Posts → Add New |
post_type == page |
Pages → Add New |
taxonomy == category |
Posts → Categories → Add/Edit |
taxonomy == post_tag |
Posts → Tags → Add/Edit |
user_role == administrator |
Users → Your Profile |