Usage

Creating a Plugin Context

Every WPZylos plugin starts by defining its identity through a PluginContext:

use WPZylos\Framework\Core\PluginContext;

$context = PluginContext::create([
    'file'       => __FILE__,
    'slug'       => 'my-plugin',
    'prefix'     => 'myplugin_',
    'textDomain' => 'my-plugin',
    'version'    => '1.0.0',
    'namespace'  => 'MyPlugin',
]);

All six keys (file, slug, prefix, textDomain, version, namespace) are required. An InvalidArgumentException is thrown if any are missing.


Using the Context

Identity Properties

$context->slug();        // 'my-plugin'
$context->prefix();      // 'myplugin_'
$context->textDomain();  // 'my-plugin'
$context->version();     // '1.0.0'
$context->namespace();   // 'MyPlugin'
$context->file();        // '/path/to/my-plugin.php'

Paths & URLs

$context->path();                     // /path/to/plugin/
$context->path('config/app.php');     // /path/to/plugin/config/app.php
$context->url('assets/js/app.js');    // https://example.com/wp-content/plugins/my-plugin/assets/js/app.js

Prefixed Keys

$context->hook('settings_saved');          // 'myplugin_settings_saved'
$context->optionKey('version');            // 'myplugin_version'
$context->transientKey('cache_data');      // 'myplugin_cache_data'
$context->cronHook('daily_cleanup');       // 'myplugin_daily_cleanup'
$context->metaKey('order_id');             // '_myplugin_order_id'
$context->assetHandle('admin-js');         // 'my-plugin-admin-js'
$context->tableName('orders');             // 'wp_myplugin_orders'
$context->tableName('orders', 'network');  // 'wp_myplugin_orders' (uses base_prefix)

Creating an Application

use WPZylos\Framework\Core\Application;

$app = new Application($context);

// Register service providers
$app->register(new DatabaseServiceProvider());
$app->register(new RoutingServiceProvider());

// Boot the application
$app->boot();

Resolving Services

// Resolve from container
$service = $app->make(MyService::class);

// Check if bound
if ($app->has(MyService::class)) {
    // ...
}

// Access context and paths
$ctx   = $app->context();
$paths = $app->paths();

Creating Service Providers

Extend the ServiceProvider base class and implement register(). Always call parent::register($app) to store the $app reference.

use WPZylos\Framework\Core\ServiceProvider;
use WPZylos\Framework\Core\Contracts\ApplicationInterface;

class MyServiceProvider extends ServiceProvider
{
    public function register(ApplicationInterface $app): void
    {
        parent::register($app);

        // Use the shortcut methods provided by ServiceProvider
        $this->singleton(MyService::class, function () {
            return new MyService($this->context());
        });
    }

    public function boot(ApplicationInterface $app): void
    {
        // Called after ALL providers are registered
        $config = $this->make('config');
    }
}

ServiceProvider Shortcut Methods

Inside any service provider, you have access to these convenience methods:

$this->bind(Abstract::class, $concrete);      // Bind a service
$this->singleton(Abstract::class, $concrete);  // Bind a singleton
$this->make(Abstract::class);                  // Resolve a service
$this->context();                              // Get plugin context

Working with Paths

The Paths instance is created automatically by Application and resolves paths using the plugin context.

Basic Usage

$paths = $app->paths();

$paths->path('config/app.php');   // /plugin/root/config/app.php
$paths->url('assets/css/app.css'); // https://example.com/.../my-plugin/assets/css/app.css

Using Aliases

Aliases let you reference directories with @alias syntax:

// Use built-in aliases
$paths->path('@views/welcome.php');     // /plugin/root/resources/views/welcome.php
$paths->path('@config/database.php');   // /plugin/root/config/database.php
$paths->url('@assets/css/app.css');     // https://example.com/.../resources/assets/css/app.css

// Register custom aliases (chainable)
$paths->alias('templates', 'resources/templates')
      ->alias('emails', 'resources/emails');

$paths->path('@templates/invoice.php'); // /plugin/root/resources/templates/invoice.php

Checking Existence & Uploads

if ($paths->exists('@config/app.php')) {
    // file exists
}

// Get plugin upload directory (auto-creates if needed)
$uploadPath = $paths->uploads();                // .../wp-content/uploads/my-plugin/
$filePath   = $paths->uploads('invoices/1.pdf'); // .../wp-content/uploads/my-plugin/invoices/1.pdf

Caching with CacheRepository

The CacheRepository provides context-prefixed caching using WordPress object cache with a transient fallback layer.

Setup

use WPZylos\Framework\Core\Cache\CacheRepository;

// Typically registered in a service provider:
$this->singleton(CacheRepository::class, function () {
    return new CacheRepository($this->context());
});

// Then resolve it:
$cache = $app->make(CacheRepository::class);

Object Cache Operations

// Store and retrieve
$cache->put('user_count', 150, 3600);    // Store for 1 hour
$count = $cache->get('user_count');       // 150
$count = $cache->get('missing', 0);      // 0 (default)

// Store only if not already present
$cache->add('lock_key', true, 60);

// Check and remove
$cache->has('user_count');   // true
$cache->forget('user_count');

// Increment / decrement counters
$cache->put('views', 0);
$cache->increment('views');      // 1
$cache->increment('views', 5);   // 6
$cache->decrement('views', 2);   // 4

Remember Pattern

// Compute value only if not cached
$users = $cache->remember('active_users', 3600, function () {
    return get_users(['role' => 'subscriber']);
});

// Cache forever
$settings = $cache->rememberForever('plugin_settings', function () {
    return get_option('myplugin_settings', []);
});

Transient Operations (Persistent Fallback)

Transients persist across page loads even without a persistent object cache:

// Store in transients
$cache->transientPut('license_check', $result, DAY_IN_SECONDS);

// Retrieve
$result = $cache->transientGet('license_check');

// Remember pattern with transients
$data = $cache->transientRemember('remote_data', HOUR_IN_SECONDS, function () {
    return wp_remote_get('https://api.example.com/data');
});

// Delete
$cache->transientForget('license_check');

Utility Classes

Arr (Array Helpers)

use WPZylos\Framework\Core\Support\Arr;

// Dot-notation access
Arr::get($array, 'user.name', 'Guest');     // Get nested value
Arr::set($array, 'user.email', '[email protected]');  // Set nested value
Arr::has($array, 'user.name');              // Check existence
Arr::forget($array, 'user.temp');           // Remove by key
Arr::forget($array, ['a', 'b.c']);          // Remove multiple keys

// Filtering
Arr::only($array, ['name', 'email']);       // Keep only these keys
Arr::except($array, ['password']);          // Exclude these keys

// Utility
Arr::flatten([[1, 2], [3, [4]]]);           // [1, 2, 3, 4]
Arr::flatten([[1, [2]], [3]], 1);            // [1, [2], 3]

Arr::first([1, 2, 3]);                      // 1
Arr::first($users, fn($u) => $u->active);   // First active user

Arr::wrap('hello');                          // ['hello']
Arr::wrap(['hello']);                         // ['hello']
Arr::wrap(null);                             // []

Str (String Helpers)

use WPZylos\Framework\Core\Support\Str;

// Case conversion
Str::studly('hello_world');    // 'HelloWorld'
Str::camel('hello_world');     // 'helloWorld'
Str::snake('HelloWorld');      // 'hello_world'
Str::kebab('HelloWorld');      // 'hello-world'
Str::slug('Hello World!');     // 'hello-world'

// String checks (accept string or array of needles)
Str::contains('foobar', 'oba');              // true
Str::contains('foobar', ['baz', 'bar']);      // true
Str::startsWith('foobar', 'foo');             // true
Str::endsWith('foobar', 'bar');               // true

// Manipulation
Str::limit('Long text here', 8);             // 'Long tex...'
Str::limit('Long text', 8, '…');             // 'Long tex…'
Str::random(32);                              // Random 32-char string
Str::replaceFirst('bar', 'qux', 'foobar bar'); // 'fooqux bar'
Str::before('hello@world', '@');              // 'hello'
Str::after('hello@world', '@');               // 'world'