A free, open-source, lightweight alternative to ACF for WordPress. Build powerful custom fields with a beautiful visual builder β no bloat, no paywalls.
Features Β· Field Types Β· Installation Β· Usage Β· Export Β· Contributing
- π¨ Visual Drag & Drop Builder β Build field groups with an intuitive interface
- β‘ Live PHP Code Preview β See generated PHP code update in real time as you build
- π¦ Export as PHP Code β Export field groups to use in your theme or plugin without OneMeta installed
- π Repeater Fields β Create repeatable sub-field groups for complex data structures
- π Conditional Logic β Show or hide fields based on the value of other fields
- π REST API Support β Access your field data via the WordPress REST API
- πͺΆ Zero Dependencies β No jQuery, no bloat β built with vanilla JS and modern tooling (Vite)
- π― 14 Field Types β Everything you need, nothing you don't
- π Modern UI β Clean, polished admin interface that feels native to WordPress
| Category | Fields |
|---|---|
| Basic | Text, Textarea, URL, Email, Date |
| Choice | Toggle, Select, Radio, Button Group |
| Multiple | Checkbox |
| Media | Image, File, Gallery |
| Advanced | Repeater |
| Requirement | Version |
|---|---|
| WordPress | 6.8 or higher |
| PHP | 8.2 or higher |
- Go to Releases
- Download the latest
onemeta.zip - In your WordPress admin go to Plugins β Add New β Upload Plugin
- Upload the ZIP and click Activate
cd wp-content/plugins
git clone https://github.com/fronttheme/onemeta.gitThen activate the plugin from Plugins in your WordPress admin.
OneMeta will be available in the official WordPress plugin directory soon.
Go to OneMeta β Add New in your WordPress admin. Give your field group a key and title, then select whether it applies to Post/Page Meta or User Meta.
Click Add Field or drag a field type from the sidebar. Configure each field's label, key, description, placeholder, and any advanced options (choices, conditional logic, repeater sub-fields).
Use the built-in helper functions to retrieve field values:
// Get a post/page meta value
$value = onemeta_get_meta( get_the_ID(), 'field_key' );
// Get a user meta value
$value = onemeta_get_user_meta( $user_id, 'field_key' );
// With a default fallback
$value = onemeta_get_meta( get_the_ID(), 'field_key', 'Default Value' );Note: Do not include the
onemeta_prefix in your field key β it is added automatically.
// Get
$value = onemeta_get_meta( $post_id, 'field_key', 'default' );
// Update
onemeta_update_meta( $post_id, 'field_key', $value );
// Delete
onemeta_delete_meta( $post_id, 'field_key' );// Get
$value = onemeta_get_user_meta( $user_id, 'field_key', 'default' );
// Update
onemeta_update_user_meta( $user_id, 'field_key', $value );
// Delete
onemeta_delete_user_meta( $user_id, 'field_key' );| Field Type | Returns | Example |
|---|---|---|
| Text, Textarea, URL, Email, Date | string |
"Hello World" |
| Toggle | string |
"0" or "1" |
| Select, Radio, Button Group | string |
"option_value" |
| Checkbox | array |
["val1", "val2"] |
| Image, File | int |
123 (attachment ID) |
| Gallery | array |
[123, 456, 789] |
| Repeater | array |
[["title" => "Item 1"], ...] |
$text = onemeta_get_meta( get_the_ID(), 'custom_title' );
echo '<h2>' . esc_html( $text ) . '</h2>';$content = onemeta_get_meta( get_the_ID(), 'field_description' );
// Preserve line breaks and escape
echo wp_kses_post( wpautop( $content ) );$url = onemeta_get_meta( get_the_ID(), 'field_website' );
if ( $url ) {
echo '<a href="' . esc_url( $url ) . '" target="_blank" rel="noopener">Visit Website</a>';
}$email = onemeta_get_meta( get_the_ID(), 'field_email' );
if ( $email ) {
echo '<a href="mailto:' . esc_attr( $email ) . '">' . esc_html( $email ) . '</a>';
}$date = onemeta_get_meta( get_the_ID(), 'field_event_date' );
if ( $date ) {
// Returns Y-m-d format β convert to any display format
echo '<time datetime="' . esc_attr( $date ) . '">';
echo date_i18n( get_option( 'date_format' ), strtotime( $date ) );
echo '</time>';
}// Returns "1" for on, empty string for off β not boolean
$is_featured = onemeta_get_meta( get_the_ID(), 'is_featured' );
if ( $is_featured === '1' ) {
echo '<span class="badge">β Featured</span>';
}// All return the selected value as a string
$layout = onemeta_get_meta( get_the_ID(), 'field_layout' );
echo '<div class="layout-' . esc_attr( $layout ) . '">';
// Map values to labels
$choices = [ 'grid' => 'Grid View', 'list' => 'List View' ];
echo esc_html( $choices[ $layout ] ?? $layout );// Returns array of selected values
$features = onemeta_get_meta( get_the_ID(), 'field_features' );
if ( is_array( $features ) && ! empty( $features ) ) {
foreach ( $features as $feature ) {
echo '<span class="badge">' . esc_html( $feature ) . '</span>';
}
}
// Check if a specific value is selected
if ( in_array( 'wifi', $features, true ) ) {
echo 'πΆ WiFi Available';
}// Returns attachment ID (integer)
$image_id = onemeta_get_meta( get_the_ID(), 'featured_image' );
if ( $image_id ) {
// Recommended: use wp_get_attachment_image() for srcset, lazy loading, etc.
echo wp_get_attachment_image( $image_id, 'large', false, [
'class' => 'featured-image',
'alt' => get_the_title(),
] );
}// Returns attachment ID (integer)
$file_id = onemeta_get_meta( get_the_ID(), 'field_document' );
if ( $file_id ) {
$file_url = wp_get_attachment_url( $file_id );
$file_name = basename( get_attached_file( $file_id ) );
$file_size = size_format( filesize( get_attached_file( $file_id ) ) );
echo '<a href="' . esc_url( $file_url ) . '" download>';
echo esc_html( $file_name ) . ' (' . $file_size . ')';
echo '</a>';
}// Returns array of attachment IDs
$gallery = onemeta_get_meta( get_the_ID(), 'field_gallery' );
if ( is_array( $gallery ) && ! empty( $gallery ) ) {
echo '<div class="gallery">';
foreach ( $gallery as $image_id ) {
echo wp_get_attachment_image( $image_id, 'medium', false, [
'class' => 'gallery-item',
] );
}
echo '</div>';
}// Returns array of row arrays β each row contains your sub-field values
$team = onemeta_get_meta( get_the_ID(), 'field_team_members' );
if ( is_array( $team ) && ! empty( $team ) ) {
echo '<div class="team-grid">';
foreach ( $team as $member ) {
echo '<div class="team-member">';
if ( ! empty( $member['member_avatar'] ) ) {
echo wp_get_attachment_image( $member['member_avatar'], 'thumbnail', false, [
'alt' => esc_attr( $member['member_name'] ?? '' ),
] );
}
echo '<h3>' . esc_html( $member['member_name'] ?? '' ) . '</h3>';
echo wp_kses_post( wpautop( $member['member_bio'] ?? '' ) );
echo '</div>';
}
echo '</div>';
}Show or hide fields dynamically based on the value of another field:
'my_field' => [
'type' => 'text',
'label' => 'My Text Field',
'conditional' => [
'field' => 'my_other_field',
'operator' => '!=',
'value' => '',
],
],Supported operators:
| Operator | Description |
|---|---|
== |
Equal to |
!= |
Not equal to |
contains |
Contains text (case-insensitive) |
!contains |
Does not contain text (case-insensitive) |
OneMeta lets you export any field group as clean PHP code. This means you can:
- Bundle field groups into your theme or plugin without requiring OneMeta to be installed
- Version control your field configurations alongside your code
- Share field structures with other developers
Click Export PHP in the builder or visit OneMeta β Documentation β Export Field Groups.
OneMeta field data is accessible via the WordPress REST API. Field values are exposed on their respective post or user endpoints.
- Node.js 18+
- npm
- Local WordPress install (e.g. LocalWP, Laragon, MAMP)
cd wp-content/plugins
git clone https://github.com/fronttheme/onemeta.git
cd onemeta
npm installOneMeta includes a dev mode that loads JS and CSS directly from the Vite dev server (localhost:3000) with Hot Module Replacement (HMR). To enable it, add the following constants to your wp-config.php:
define( 'WP_DEBUG', true );
define( 'ONEMETA_DEV_MODE', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
define( 'WP_ENVIRONMENT_TYPE', 'local' );Important:
ONEMETA_DEV_MODEmust be the booleantrueβ not the string"true".
How dev mode works per context:
| Context | Condition to activate dev mode |
|---|---|
| Admin builder (JS + CSS) | ONEMETA_DEV_MODE === true |
| Frontend field assets (JS + CSS) | WP_DEBUG === true and ONEMETA_DEV_MODE === true |
Then start the Vite dev server:
npm run devChanges to any file in src/js/ or src/scss/ will now hot-reload instantly in the browser.
To test the production build locally, comment out ONEMETA_DEV_MODE:
// define( 'ONEMETA_DEV_MODE', true );Then run a production build:
npm run buildThe plugin will now load compiled assets from assets/js/ and assets/css/ β exactly as it does for end users.
# Start Vite dev server with HMR (requires ONEMETA_DEV_MODE)
npm run dev
# Production build
npm run build
# Watch mode β rebuilds on change, no HMR
npm run watch
# Generate translation .pot file
npm run pot
# Build and package release ZIP
npm run package- Build Tool: Vite 5
- CSS: SCSS (modular 7-1 architecture)
- JS: Vanilla ES Modules (no jQuery)
- PHP: PSR-4 autoloaded, singleton pattern
- Database: Custom
wp_onemeta_field_groupstable
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature - Commit your changes:
git commit -m 'Add your feature' - Push to the branch:
git push origin feature/your-feature - Open a Pull Request
Please follow WordPress coding standards for PHP and keep JS changes consistent with the existing modular architecture.
For a full contribution guide including how to add new field types, see CONTRIBUTING.md.
OneMeta is licensed under the GPL-2.0-or-later license β the same license as WordPress itself. You are free to use, modify, and distribute this plugin.
Faruk Ahmed
- Website: farukdesign.com
- Brand: fronttheme.com
- GitHub: @fronttheme
Made with β€οΈ for the WordPress community Β· fronttheme.com