WordPress Integration
Segment membership
Create the list in the dashboard and attach it to a Targeting filter. Sync members with a Backend application key. Evaluation uses the published list after the next definitions refresh. Flow · HTTP API
Use the PHP core client from a plugin, cron job, or admin-ajax handler. Do not put a Backend key in public theme JavaScript. See the PHP SDK.
Requires a Backend application key. Do not call this from a browser, mobile app, or other public client.
use Toggly\FeatureManagement\SegmentMembershipClient;
$segments = new SegmentMembershipClient(
$httpClient,
$requestFactory,
$streamFactory,
getenv('TOGGLY_APP_KEY')
);
$segments->addSegmentMembers('Beta Testers', ['user-123']);
Use toggly/wordpress to
choose theme content with a PHP helper or shortcode. It includes the PHP core
package. Keep your existing theme content as the disabled branch.
WordPress cheat sheet · Download PDF
Requirements
Composer and a PHP host are required. The examples use PHP 8 syntax. The
package retains a PHP 7.4 declared floor and supports PHP through 8.5. PHP 8.5
is the current tested runtime. The plugin retains WordPress 5.0+ support and
is currently validated on WordPress 7.1 with PHP 8.5. Validate your installed
combination with composer check-platform-reqs. A declared floor does not by
itself prove every earlier host version still runs.
Installation
From the WordPress root (the directory containing wp-load.php), install:
composer require toggly/wordpress
mkdir -p wp-content/plugins wp-content/mu-plugins
ln -s ../../vendor/toggly/wordpress wp-content/plugins/toggly
Use the symlink only if that destination does not already exist. You may instead
deploy the package directory there. WordPress must find the entry point at
wp-content/plugins/toggly/toggly.php, and the host must load the root Composer
autoloader. Prepare the MU plugin below before activation.
Host bootstrap
Create wp-content/mu-plugins/toggly-host.php. This file loads before normal
plugins and provides the cron intervals before the SDK schedules its events.
The path assumes the root Composer layout shown above; adjust it for your
actual deployment.
<?php
require_once ABSPATH . 'vendor/autoload.php';
add_filter('cron_schedules', static function (array $schedules): array {
$schedules['toggly_refresh_interval'] = [
'interval' => 300,
'display' => 'Every 5 Minutes',
];
$schedules['toggly_send_interval'] = [
'interval' => 60,
'display' => 'Every Minute',
];
return $schedules;
});
// Select a host configuration with no optional transient snapshot adapter.
add_filter('pre_option_toggly_snapshot_provider', static fn () => 'none');
// The plugin initializes on plugins_loaded; refresh after initialization.
add_action('plugins_loaded', static function (): void {
$options = get_option('toggly_settings', []);
if (!empty($options['app_key'])) {
do_action('toggly_refresh_features');
}
}, 20);
In Plugins, activate Toggly Feature Management, then open
Settings → Toggly. Set the App Key, exact Environment name and
https://definitions.toggly.io/ as Base URL. Select signed definitions to match
your app's configuration, then save. Make a new page request so initialization
reads those settings. Do not call TogglyPlugin::init() a second time.
Snapshot choice
The recipe chooses none, which bypasses optional transient caching and works
with PSR Simple Cache 3 dependency resolutions. It does not persist
snapshots: each new PHP request must refresh before evaluating, and an API
outage leaves a new process without saved definitions. The explicit refresh
above implements that choice and adds a network request to startup.
The plugin's default selection is transient, backed by
WordPressCacheAdapter. Check compatibility with your installed PSR cache
interface before choosing it. Do not assume the no-snapshot recipe provides
offline persistence. Core applications can explicitly inject other
snapshot providers; this plugin does not expose
that constructor injection through its settings page.
First flag in a template
Create new-header in the configured Toggly app and environment. Set an
AlwaysOn rule, then place this in a theme template that runs after
plugins_loaded:
<?php if (toggly_is_enabled('new-header')): ?>
<p>New header</p>
<?php else: ?>
<p>Original header</p>
<?php endif; ?>
The page should show New header. Change the rule to AlwaysOff and reload;
after the startup refresh it should show Original header. Unknown flags are
disabled by default. Keep this fallback useful when definitions are unavailable.
Authenticated request context
The helper is the global function toggly_is_enabled. The plugin loads it
during initialization from a file that declares no namespace. Its signature is
(string $featureKey, ?array $context = null): bool. Build identity from the
authenticated server-side user before the first targeted check:
<?php
$user = wp_get_current_user();
$context = [
'identity' => $user->exists() ? (string) $user->ID : null,
'groups' => $user->exists() ? array_values($user->roles) : [],
];
$enabled = toggly_is_enabled('premium-content', $context);
?>
<?php if ($enabled): ?>
<p>Premium content</p>
<?php else: ?>
<p>Standard content</p>
<?php endif; ?>
Configure Targeting with the same ID convention. The SDK's ambient
WordPressFeatureContextProvider supplies an identifier to telemetry; it does
not inject the logged-in user into evaluation. Pass identity, groups,
server-derived claims and mapped request data explicitly when rules need
them. A top-level email is not a targeting identity. Feature flags do not
replace WordPress capability checks for protected data or actions.
Shortcodes and programmatic checks
Use a shortcode for a flag that does not need authenticated request context:
[toggly_feature name="new-banner"]
<p>Shown when enabled.</p>
[/toggly_feature]
name is required; missing or disabled flags render nothing. Optional context
is a JSON object that is passed to evaluation. Static shortcode JSON describes
literal context, not the current viewer. Do not treat author-supplied identity
or claims as authenticated user data; use the server-side helper above for
user-specific decisions.
The plugin object forwards the same explicit evaluation context:
$plugin = \Toggly\WordPress\TogglyPlugin::getInstance();
$enabled = $plugin->isEnabled('premium-content', $context);
PHP does not implement ContextProperty or entity registration. Adding Order properties to the context does not activate an entity rule. See PHP context.
WP-Cron and lifecycle
The early interval filter in host bootstrap lets the plugin register these recurring events on a fresh installation:
| Hook | Schedule | Behavior |
|---|---|---|
toggly_refresh_features | toggly_refresh_interval, 300 seconds | Refresh definitions in this process |
toggly_send_stats | toggly_send_interval, 60 seconds | Send usage statistics and metrics from this process |
Verify schedules with wp cron event list and configure normal WordPress cron
execution on your host. WP-Cron does not initialize definitions in the current
page response, and a separate cron process cannot flush another request's
in-memory telemetry. The SDK's usage and metrics shutdown handlers flush the
owning request; long-lived hosts must manage their own lifecycle.
After initialization, these are the supported operational actions:
do_action('toggly_refresh_features');
do_action('toggly_send_stats');
Do not use WordPress state-action names as automatic flag-change notifications. Use ordinary evaluations for theme decisions. Core integrations expose state-service subscriptions.