定制 boxybird/waffle 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

boxybird/waffle

Composer 安装命令:

composer require boxybird/waffle

包简介

Tools built using Illuminate components (https://github.com/illuminate). Inspired by https://github.com/mattstauffer/Torch

README 文档

README

Important note

This tool brings the power of Laravel's Illuminate packages to your WordPress project. However, it's important to know that it doesn't include every single feature from Laravel. The examples below will give you a good idea of what's possible, but they don't cover everything.

As a specific example, waffle_cache()->flexible('...') will not work because Waffle does not yet support Laravel's Deferred functionality. If you plan to explore addition features, please test first.

We hope to add more features as the community's needs grow.

Installation

Install the package via composer.

composer require boxybird/waffle

Boot Waffle within a theme or plugin.

require_once __DIR__.'/vendor/autoload.php';

BoxyBird\Waffle\Waffle::boot();

Available functions

waffle_queue

waffle_worker

waffle_schedule

waffle_db

waffle_router

waffle_validator

waffle_encrypter

waffle_http

waffle_cache

waffle_session

waffle_storage

waffle_request

waffle_collection

waffle_str

waffle_arr

waffle_uri

waffle_carbon

waffle_benchmark

waffle_process

waffle_queue / waffle_worker

<?php

// Define a job class
class LongRunningJob
{
    /**
     * The number of times the job may be attempted.
     *
     * @var int
     */
    public $tries = 5;

    /**
     * The maximum number of unhandled exceptions to allow before failing.
     *
     * @var int
     */
    public $maxExceptions = 3;

    /**
     * Indicate if the job should be marked as failed on timeout.
     *
     * @var bool
     */
    public $failOnTimeout = true;

    /**
     * The number of seconds to wait before retrying the job.
     *
     * @var int
     */
    public $backoff = 3;

    /**
     * The number of seconds the job can run before timing out.
     *
     * @var int
     */
    public $timeout = 120;

    /**
     * Handle the job. 
     *
     */
    public function fire($job, $data)
    {
        // Simulate long running code
        sleep($data['how_long']);

        // Something may or may not have gone wrong
        $oops = false;

        // If $oops === true release the job back to the queue to try 
        // again based on waffle_worker()->setOptions(['maxTries' => 3 // default is 1])
        // Failed jobs are caught and stored in the database and can be
        // viewed in the admin (/wp-admin/tools.php?page=waffle-options.php)
        if ($oops) {
            return $job->release();
        }

        // Delete the job from the queue
        $job->delete();
    }
}

// Push a job onto the default queue
waffle_queue()->push(LongRunningJob::class, ['how_long' => 5]);

// Push a job onto a custom queue
waffle_queue()->push(LongRunningJob::class, ['how_long' => 5], 'my_custom_queue');

// Process the next job on the default queue immediately. Note: This is a blocking call. 
waffle_worker()->runNextJob();

// Run the default queue worker in the background
waffle_worker()->work();

// Run the custom queue worker in the background
waffle_worker(['my_custom_queue'])->work();

// Run multiple queue workers in the background. Array order determines the priority
waffle_worker(['my_custom_queue', 'default'])->work();

// Run a queue worker in the background with overridden global options
waffle_worker()->setOptions([
    'memory'   => 256, // default is 128 (MB)
    'sleep'    => 3, // default is 0 (seconds to sleep after each job)
    'maxTries' => 3, // default is 1 (number of times to try a job before failing)
    'maxJobs'  => 3, // default is 500 (number of jobs to process before stopping)
    'maxTime'  => 90, // default is 60 (number of seconds to process each job before stopping)        
    'timeout'  => 120, // Attempts to default to 80% of the servers max_execution_time, else default is 60 seconds (server timeout/worker timeout)
])->work();

// Notes on setOptions(): 
// Both 'timeout' and 'maxTime' work hand in hand as exceptions are thrown if either exceeds server timeout
// Defined Job class properties will override global setOptions() values

// Notes on workers:
// Workers use WP-Cron to run in the background. The interval is 60 seconds
// Only a single worker can be run at a time. The last declared worker will be the one that runs
waffle_worker()->work(); // This will not run
waffle_worker(['my_custom_queue', 'default'])->work(); // This will run 

waffle_schedule

<?php

waffle_schedule()->call(function () {
    // Run code... Ex: waffle_worker()->runNextJob();
})->everyMinute();

waffle_schedule()->as('your_custom_hook_name')->call(function () {
    // Run code... Ex: waffle_worker()->runNextJob();
})->everyMinute();

// ->everyFiveMinutes()
// ->everyFifteenMinutes()
// ->everyThirtyMinutes()
// ->hourly()
// ->twiceDaily()
// ->daily()
// ->weekly()

waffle_db

Reference: https://laravel.com/docs/12.x/queries

<?php

// Create a custom table in the database if it doesn't exist
if (!waffle_db()->schema()->hasTable('waffle_custom_table')) {
    waffle_db()->schema()->create('waffle_custom_table', function ($table) use ($wpdb) {
        $table->increments('id');
        $table->bigInteger('user_id')->unsigned();
        $table->string('extra_user_content');
        $table->timestamp('created_at')->default(waffle_db()::raw('CURRENT_TIMESTAMP'));
        $table->timestamp('updated_at')->default(waffle_db()::raw('CURRENT_TIMESTAMP'));
        $table->foreign('user_id')->references('ID')->on('wp_users');
    });
}

// Insert data
waffle_db()->table('waffle_custom_table')->insert([
    'user_id' => get_current_user_id(),
    'extra_user_content' => 'Some extra content about the user.',
]);

// Query new table and join with user table
$query = waffle_db()
    ->table('waffle_custom_table')
    ->join('wp_users', 'wp_users.ID', '=', 'waffle_custom_table.user_id')
    ->select('wp_users.*', 'waffle_custom_table.extra_user_content')
    ->where('waffle_custom_table.user_id', get_current_user_id())
    ->get();

waffle_router

Reference: https://laravel.com/docs/12.x/routing

<?php

waffle_router(function ($router) {
    $router->group(['prefix' => 'custom/v1/'], function ($router) {
        $router->get('/', fn() => ['method' => 'GET']);
        $router->post('/', fn() => ['method' => 'POST']);
        $router->put('/', fn() => ['method' => 'PUT']);
        $router->patch('/', fn() => ['method' => 'PATCH']);
        $router->delete('/', fn() => ['method' => 'DELETE']);
    });
});

// Ideally `waffle_router` should be called within `init` hook
add_action('init', function () {
    if (is_admin()) {
        return;
    }

    waffle_router(...);
});

waffle_validator

Reference: // https://laravel.com/docs/12.x/validation

<?php

$nonce = wp_create_nonce('secret');

$data = [
    'name'  => 'John Doe',
    'email' => 'john@doe.com',
    'age'   => 20,
    'nonce' => $nonce,
];

$validator = waffle_validator($data,
    [
        'name'  => 'required',
        'email' => 'required|email',
        'age'   => 'required|integer|min:21',
        'nonce' => 'required|verify_nonce:secret',
    ],
    [
        'age.min' => 'Not old enough', // Custom error message for age.min
    ]
);

waffle_encrypter

Reference: https://laravel.com/docs/12.x/encryption

<?php

// Add to wp-config.php
define('WAFFLE_ENCRYPTER_KEY', 'REPLACE_WITH_SOME_16_CHARACTER_STRING');

// Example usage
$encrypted = waffle_encrypter()->encrypt('Some secret');

$decrypted = waffle_encrypter()->decrypt($encrypted);

waffle_http

Reference: https://laravel.com/docs/12.x/http-client

<?php

// GET
$response = waffle_http()->get('https://rickandmortyapi.com/api/character');

if ($response->failed()) {
    // Handle error
}

$data = $response->json();

// POST
$response = waffle_http()
    ->withHeaders([
        'Bearer' => 'SOME_TOKEN',
    ])
    ->post('https://example.test/create', [
        'name'   => 'John Doe',
        'status' => 'active',
    ]);

waffle_cache

Reference: https://laravel.com/docs/12.x/cache

<?php

// Cache forever, or until the cache is flushed
waffle_cache()->put('foo', 'bar');

// Cache for 60 seconds
waffle_cache()->put('foo', 'bar', 60);

// Get cached value
$foo = waffle_cache()->get('foo');

// Flush the cache
waffle_cache()->flush();

// -----

// Cache the query results for 1 hour. If the hour is up, the query will be run again.
$posts = waffle_cache()->remember('posts', HOUR_IN_SECONDS, function () {
    $query = new WP_Query([
        // SOME EXPENSIVE QUERY ARGS
    ]);

    return $query->get_posts();
});

// Flush the cache on some action
add_action('save_post', function ($post_id) {
    // Flush the entire cache
    waffle_cache()->flush();

    // Flush a specific key
    waffle_cache()->forget('posts');
});

waffle_session

Reference: https://laravel.com/docs/12.x/session

<?php

// Handle logic to determine 'status' of the user
// Store items in the session
waffle_session()->put('status', $active);

// Retrieve an item from the session if it exists
if (waffle_session()->has('status')) {
    echo waffle_session()->get('status');
}

// Handle example form submission...
// Store items in the session for the next request only
waffle_session()->flash('message', 'Thanks for signing up!');

// Retrieve a flash message if it exists
if (waffle_session()->has('message')) {
    echo waffle_session()->get('message');
}

Sessions and full-page caching

The session cookie (wp_waffle_sessions) is only sent on a response when:

  1. The session was actually used during the request (anything that resolves waffle_session()), or
  2. The incoming request already carries the session cookie.

A plain anonymous request that never touches the session sends no Set-Cookie header and writes no session row. This keeps such responses cacheable by full-page caches (Pressable batcache, Varnish, etc.), which refuse to serve a cached response that carries a cookie. No configuration is required — this is the default behavior.

waffle/should_send_session_cookie filter

Use this filter to override the per-response cookie decision. It runs once per request and receives the computed boolean. It does not enable or disable sessions — waffle_session()->put()/get() still work within a request regardless. It only controls whether the Set-Cookie header is written.

<?php

// Restore the legacy behavior: always send the cookie on every response.
add_filter('waffle/should_send_session_cookie', '__return_true');

// Or surgically keep a specific route cacheable, even if something touched the
// session, by suppressing the cookie there. Note: the session ID then won't be
// persisted to the browser on that response.
add_filter('waffle/should_send_session_cookie', function (bool $send): bool {
    return is_front_page() ? false : $send;
});

This filter is not a master switch. Returning false only stops the cookie from being written on that response. The session can still be read from an incoming cookie, session code still runs within the request, and the wp_waffle_sessions table and hourly cleanup cron still exist. To turn the session subsystem off entirely (no cookie, no shutdown save, no table, no cron), you would need a dedicated master switch — which Waffle does not currently provide. The filter is a per-response override, not a feature flag.

waffle_storage

Reference: https://laravel.com/docs/12.x/filesystem

<?php

// LOCAL
$disk = waffle_storage()->build([
    'driver' => 'local',
    'root'   => wp_upload_dir()['basedir'],
    'url'    => wp_upload_dir()['baseurl'],
]);

// /wp-content/uploads/custom-folder/hello-world.txt
$disk->put('custom-folder/hello-world.txt', 'Hello World');

// https://example.test/wp-content/uploads/custom-folder/hello-world.txt
$url = $disk->url('custom-folder/hello-world.txt');

// -----

// AMAZON S3
$disk = waffle_storage()->build([
    'driver' => 's3',
    'key'    => 'YOUR_KEY',
    'secret' => 'YOUR_SECRET',
    'region' => 'YOUR_REGION',
    'bucket' => 'YOUR_BUCKET',
]);

$disk->put('hello-world.txt', 'Hello World', 'public');

// https://YOUR_BUCKET.s3.amazonaws.com/hello-world.txt
$url = $disk->url('hello-world.txt');

waffle_request

Reference: https://laravel.com/docs/12.x/requests

<?php

// https://example.com?first_name=Jane&last_name=Doe&age=40

$params = waffle_request()->input(); 
// [
//     'first_name' => 'Jane',
//     'last_name' => 'Doe',
//     'age' => 40
// ];

$first_name = waffle_request()->only(['first_name']);
// [
//     'first_name' => 'Jane',
// ];

waffle_collection

Reference: https://laravel.com/docs/12.x/collections

<?php

$posts = waffle_collection(get_posts())
    ->map(function ($item) {
        return [
            'id'    => $item->ID,
            'title' => get_the_title($item->ID),
            'url'   => get_permalink($item->ID),
            'image' => get_the_post_thumbnail_url($item->ID),
        ];
    })
    ->toArray();

waffle_str

Reference: https://laravel.com/docs/12.x/helpers#fluent-strings

<?php

$string = waffle_str('hello world')
    ->replace('world', 'universe')
    ->snake()
    ->upper();

echo $string; // HELLO_UNIVERSE

waffle_arr

Reference: https://laravel.com/docs/12.x/helpers#arrays-and-objects-method-list

<?php

$array = ['products' => ['desk' => ['price' => 100]]];
 
$price = waffle_arr()->get($array, 'products.desk.price');

echo $price; // 100

waffle_uri

Reference: https://laravel.com/docs/12.x/helpers#uri

<?php

$uri = waffle_uri()->of('https://example.com')
    ->withScheme('https')
    ->withHost('test.com')
    ->withPort(8000)
    ->withPath('/users')
    ->withQuery(['page' => 2])
    ->withFragment('section-1');

echo $uri; // 'https://test.com:8000/users?page=2#section-1'

waffle_carbon

Reference: https://carbon.nesbot.com/docs/

<?php

$mutable = waffle_carbon()->now();
$immutable = waffle_carbon()->toImmutable()->now();

waffle_benchmark

Reference: https://laravel.com/docs/12.x/helpers#benchmarking

<?php

waffle_benchmark()->dd([
    fn() => get_posts(),
    fn() => waffle_db()->table('wp_posts')->take(10)->get(),
]);

waffle_process

Reference: https://laravel.com/docs/12.x/processes

<?php

$output = waffle_process()::run('ls -la')->output();

boxybird/waffle 适用场景与选型建议

boxybird/waffle 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 178 次下载、GitHub Stars 达 9, 最近一次更新时间为 2022 年 06 月 15 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「plugin」 「wordpress」 「laravel」 「illuminate」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 boxybird/waffle 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 boxybird/waffle 我们能提供哪些服务?
定制开发 / 二次开发

基于 boxybird/waffle 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 178
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 9
  • 点击次数: 1
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 9
  • Watchers: 2
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2022-06-15