Repository navigation
v3.0.0
WP Bones 3.0 changes what the framework does when a plugin says nothing. The changes are breaking, and php bones migrate:to-v3 converts what it can and lists the rest. Read the upgrade guide before you update: https://wpbones.com/docs/migrating-to-v3
PHP stays 8.1+, React stays 18 (from @wordpress/element), and the build does not change.
💥 Migrations run once per site (#40, #119, #121)
- When a migration runs:
- each migration runs once per site, in file-name order, and its name is recorded in an option;
- the pending ones run on activation, on the first request after the plugin's
Versionchanges (however the update arrived: dashboard, ZIP, FTP, git, Composer), and withphp bones migrate; - a lock keeps concurrent requests from running them twice;
- a failure stops the run and shows administrators a notice until it runs.
- What 2.x did instead: it re-ran every migration and every seeder on each activation and dashboard update, inside the update request, with the old code still loaded.
- Seeders do not run any more: seed data is a migration.
migrate:to-v3converts the seeders, and one with$runOnceseeds only an empty table, as before. - The base class is
WPBones\Database\Migration. Its constructor has no side effects. The old class still loads, deprecated. - New commands:
php bones migrateandphp bones migrate:status.migrate:create <table>creates the table it is given. plugin/updated.phpruns on the first request after an update, in the new code, with$previousVersion.
💥 What declares nothing is for administrators (#125)
- Pages and menus: a page of
config/routes.phporpages/, or a menu ofconfig/menus.php, without a capability now needsmanage_options. It wasread(2.1.2), and before that nothing. To keep the old behaviour, declare'capability' => 'read'. - REST routes: a route without a
permission_callbackrefuses every request with WordPress'srest_forbidden. It was public. To keep it public, declare'permission_callback' => '__return_true'.
💥 Requests that change something carry a nonce (#129)
- Admin pages: every request to a WP Bones admin page that is not a GET or a HEAD carries the plugin's nonce. The form prints it with
$plugin->csrfField(); it can also travel in the query string or in anX-WPBones-Nonceheader. The check runs before anyloadcallback or controller method. Up to 2.x, a form on another site could post to these pages with an administrator's cookies. - Opting out: a page that checks its own nonce says
'csrf' => false. - Ajax: a
loggedaction of a provider without$nonceHashrefuses every request.make:ajaxnow sets$nonceHashfor you. useHTTPPost()returns unslashed values.
💥 Generated files leave the plugin folder (#128)
- Where they go: compiled Blade views and
single/dailylogs go towp-content/uploads/wpbones/<plugin folder>/, with anindex.phpat every level and a deny-all.htaccess. - Log names carry a hash keyed with
AUTH_SALT, so they cannot be guessed where nginx ignores the.htaccess. - Blade compiles only when a Blade view renders.
- No fallback: when uploads cannot be written, a Blade view throws a
RuntimeExceptionthat says so, and the logs fall back toerror_log(). Storage::delete()is there for anuninstall.php.
✨ php bones migrate:to-v3
Run it in your plugin's source folder after the update. It converts the migrations and the seeders, then lists for you to review:
- every page, menu and REST route that declares nothing;
- every POST form without
csrfField(); - every Ajax provider without a nonce;
- every second unslash of a
useHTTPPost()value.
It rewrites nothing in that list.
Update
composer require "wpbones/wpbones:^3.0"
php bones migrate:to-v3The 14 boilerplates and their Playground demos are on 3.0. Plugins on ^2.x stay on 2.1.3 until they change their constraint.
Full Changelog: v2.1.3...v3.0.0