Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Option Tree Laravel Package

valendesigns/option-tree

OptionTree is a WordPress options framework for adding custom settings pages and meta boxes to themes and plugins. It provides an intuitive admin UI for theme options, custom fields, and settings import/export without extensive coding.

View on GitHub
Deep Wiki
Context7

Getting Started

This is not a Composer/Laravel package — it is a WordPress theme options framework. There is no service provider, no facade, no config file. A Laravel developer only reaches for it when WordPress is the CMS behind or beside a Laravel app: a headless WP install you read via Corcel, a legacy theme you're maintaining, or a client site where WP admin is the settings UI and Laravel is the app. If you are storing app settings in pure Laravel, this is the wrong tool — use spatie/laravel-settings or an options table.

Minimum steps to get a running options page:

  1. Place the library in the theme: wp-content/themes/my-theme/option-tree/ (or install it as a plugin — but never both).
  2. Require the loader from functions.php:
if ( file_exists( get_template_directory() . '/option-tree/ot-loader.php' ) ) {
    require_once get_template_directory() . '/option-tree/ot-loader.php';
}
  1. Register settings on after_setup_theme (or on init — it must run before the admin menu is built), then read values in templates.
add_filter( 'option_tree_settings', function ( $settings ) {
    $settings['sections'][] = [ 'id' => 'contact', 'title' => 'Contact' ];
    $settings['settings'][] = [
        'id'      => 'phone',
        'label'   => 'Phone',
        'type'    => 'text',
        'section' => 'contact',
    ];
    return $settings;
} );
$phone = ot_get_option( 'phone', '' );

Where to look first: ot-loader.php (bootstrap and theme/plugin mode detection), includes/ot-functions.php (the public ot_* helpers you call from templates), includes/ot-functions-admin.php (registration functions), includes/ot-functions-settings.php (the options page itself).

First use case: a single "Theme Options" page holding logo, phone, social links, and a footer copyright — registered with option_tree_settings, read anywhere with ot_get_option().

Implementation Patterns

Register via filter, not ot_register_settings(). The imperative function works, but the option_tree_settings filter lets a child theme append or override fields without touching the parent. Same for meta boxes with option_tree_meta_boxes instead of ot_register_meta_boxes().

Share defaults between UI and template reads. Keep one PHP array of field definitions with a default on each, and one accessor that both the registration and your templates consume:

function app_option( $key, $fallback = null ) {
    $defaults = app_option_defaults();
    $value    = ot_get_option( $key, $defaults[ $key ] ?? $fallback );
    return $value;
}

This also gives you a single place to cast types (see gotchas).

Meta boxes read differently. Options pages write to one option row; meta boxes write to post meta. Read meta boxes with get_post_meta( $post->ID, 'your_key', true ) — ot_get_option() will not see them.

Conditional fields are declarative. 'condition' => 'field_id:is(some_value)' (syntax varies by version — check ot-functions-admin.php) keeps a large settings page usable without custom JS. Prefer splitting into sections over building one giant panel.

Child theme workflow. Parent registers everything; child overrides via the same filters — change a label, remove a field by ID, add a new section. Never re-register a field ID that already exists; OptionTree keeps the first definition and you get silent mismatches.

Laravel-side integration. Treat WP as an editing surface only. Two clean options:

  • Corcel: Corcel\Model\Option::where('option_name', 'option_tree')->first() and hydrate into a DTO, then cache in Laravel.
  • REST: add a small route in WP that returns a whitelisted subset of option_tree values, and cache that response in Laravel with a short TTL and a purge hook on save.

Workflow that avoids rework: define fields → register → seed defaults → read through your accessor in templates → verify the admin UI renders and saves → only then wire up the Laravel consumer.

Gotchas and Tips

Last release was 2019. There is no guarantee of PHP 8.1+ compatibility; expect dynamic-property deprecations and possible fatals on 8.2/8.3. Pin a specific tag, test on your target PHP, and prefer a maintained fork if you're starting fresh. Budget for replacing it if the site has a long life.

Theme mode vs plugin mode. Bundling in the theme and activating the plugin loads two copies of the same global functions and produces fatals or duplicate admin pages. Pick one, and guard the require_once with file_exists plus a function_exists( 'ot_get_option' ) check.

Global namespace. ot_get_option(), ot_register_settings(), etc. are global functions defined exactly once. Two themes or a plugin-plus-theme combo will collide. Anything you write should be wrapped in function_exists guards.

One serialized row. All theme options live in a single wp_options row named option_tree. That's convenient for reads (autoloaded once) but painful for migrations: you cannot diff individual keys, partial rollbacks are manual array surgery, and large image/JSON blobs bloat the row. Version the schema yourself with an app_options_version key and a migration routine.

ot_get_option() will not coerce types. A checkbox returns 'on' or '', not a boolean; multi-select and upload fields can be arrays or serialized strings depending on field type and version. Always cast in your accessor, and always pass the second $default argument — the function can return false/null when a key has never been saved.

Capability defaults. The options page defaults to edit_theme_options; meta boxes to edit_posts/edit_pages. Filter these if editors need access — but be aware the save path is an admin-ajax round trip, so capability checks happen server-side on that action, not in the form.

Debugging. Turn on WP_DEBUG and WP_DEBUG_LOG. Saves go through admin-ajax.php; watch the Network tab for the option action, check for nonce failures (usually a stale admin page after a deploy), and inspect the option_tree row directly with wp option get option_tree --format=json when the UI saves but templates read stale values.

Caching. option_tree is autoloaded, so it's fast on every request — but if you cache pages or cache in Laravel, remember to bust that cache on save. Hook the package's post-validate filter or add a WP update_option_option_tree action listener that pings your Laravel cache store.

Extension points worth knowing: option_tree_settings, option_tree_meta_boxes, the ot_theme_options_* and ot_meta_boxes_* filter family for menus/slugs/priority, and ot_validate_setting for custom field validation on save. Prefer these over editing the library — the moment you patch core you've made upgrades impossible, and this package needs every upgrade you can get.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core