Skip to main content

What the plugin includes

The skeleton provides infrastructure you build on, examples you can adapt, and optional development tools you turn on when needed. This page maps all three: what each is, where its source lives, which framework piece it builds on, and how to see it working. Initialization owns the commands that keep, remove and toggle them; Local development owns builds and checks.

Names below use an initialized Acme Content project. In the unrenamed skeleton, read acme-content-features as project-name-features, acme_content as project_name and ACME_CONTENT as PROJECT_NAME.

Plugin infrastructure​

These stay in every project, whichever example sets you remove. Most are thin plugin-owned subclasses of a framework class; follow the link for that class's full API.

FacilitySkeleton sourceFramework pieceDefault / how to use it
Bootstrap and registrationacme-content-features.php, inc/Autoloader.php, inc/Main.phpSingleton, Loader, Registrable, Container (architecture, contracts)The entry file defines the ACME_CONTENT_FEATURES_{FILE,VERSION,PATH,URL} constants, loads Composer, and boots Main. Every loaded class is listed in Main::CLASSES.
Feature modulesinc/Modules/<Domain>.phpAbstractModule (abstracts, modules)Each domain's module returns its concrete classes from get_classes(). See the Development guide.
Asset registrationinc/Core/Assets.php, src/AssetLoader (loaders)Enqueues main.js/main.css on the frontend, registers admin and editor handles, registers block.json blocks and the Interactivity module. See Blocks and assets.
Templatesinc/Core/Templates.php, templates/TemplateLoader (loaders)Util::templates()->get( 'block-templates/example-block-dynamic' ). A theme overrides a template by copying it to <theme>/acme-content-features/.
Componentsinc/Core/Components.phpComponentLoader (loaders)Loader only; no components ship. Put PHP in src/components/<Name>/<Name>.php and assets in src/css/components/ and src/js/components/. Resolve it with Main::get_instance()->get_shared( Components::class ).
Logginginc/Core/Logger.php, Util::logger()Logger (utilities)Util::logger()->info( 'Imported', [ 'count' => 3 ] ). Silent unless WP_DEBUG.
Encryptioninc/Core/Encryption.php, Util::encryption()Encryptor (utilities)Define ACME_CONTENT_FEATURES_ENCRYPTION_KEY in wp-config.php first; without it, calls throw. Util::encryption()->encrypt( $secret ) / ->decrypt().
Activation and i18ninc/Core/PluginSetup.phpRegistrableStores acme_content_features_version on activation, unschedules the example cron job on deactivation, loads the text domain from languages/.
Helpersinc/Helpers/Util.php—Accessors for the shared services above, plus get_data() (reads inc/data/<slug>.php), is_production() and is_mobile().
Quality checkstests/, phpcs.xml.dist, phpstan.neon.dist, eslint.config.mjs, .stylelintrc.jsonShared rtcamp/wp-phpcs, rtcamp/wp-phpstan, @rtcamp/eslint-config, @rtcamp/stylelint-configPHPUnit (one test per module), PHPCS, PHPStan level 5, ESLint, Stylelint, Jest. See Check a change.

The shared services (Assets, Templates, Components, Logger, Encryption) implement Shareable, so the Loader keeps one instance in Main's container. Why that is preferred over singletons is explained in the framework's sharing vs. singletons.

Supplied examples​

Every set is kept by default. Removing a set at init deletes its module, classes, test and registration; it is not a switch you can flip back. Each kept example is a working, tested reference: copy it, rename it, and replace its logic.

Init keySourceWhat it demonstratesHow to see it
post-typesModules/PostTypes/ExamplePostType.php, ExamplePostTypeTwo.phpAbstractPostType: slug, labels, menu iconAdmin menu Post Type Labels; wp post-type list includes post-type-slug.
taxonomiesModules/Taxonomies/ExampleTaxonomy.php, ExampleTaxonomyTwo.phpAbstractTaxonomy attached to the example post types via get_object_types()wp taxonomy list includes taxonomy-slug; it appears on the example post type's editor.
blocksModules/Blocks/ExampleDynamicBlock.php, src/blocks/example-block*, templates/block-templates/example-block-dynamic.phpA static block, a dynamic block (AbstractBlock rendering a template) and an Interactivity API block (render.php + view.js)After npm run build:dev, insert Example Block, Example Dynamic Block or Example Block Interactive in the editor.
shortcodesModules/Shortcodes/ExampleShortcode.phpAbstractShortcode with default attributes, sanitized input and escaped outputAdd [acme_content_example title="Hello" count="3"] to a post.
restModules/REST/ExampleRESTController.phpAbstractRESTController with a real permission_callback (manage_options)GET /wp-json/acme-content-features/v1/examples as an administrator (see below).
cliModules/CLI.php, Modules/CLI/Healthcheck.phpA ConditionallyRegistrable module that only loads under WP-CLI, and a CLICommandnpm run wp-env run cli -- wp acme-content-features health-check
cronModules/Cron/ExampleCronJob.php (+ region in Core/PluginSetup.php)A plain Registrable that schedules a daily event on init and clears it on deactivationnpm run wp-env run cli -- wp cron event list shows acme_content_features_daily_cleanup.
settingsModules/Settings/ExampleSettingsPage.phpAbstractSettingsPage: fields, sanitize callbacks, Settings API renderingSettings → Acme Content Features; save the text field and reload.
adminModules/Admin/ExampleAdminPage.phpAbstractAdminPage as a submenu of ToolsTools → Features Tools.
rolesModules/Roles/ExampleUserRole.phpAbstractUserRole with versioned capabilities (bump get_version() to re-sync)The role is added on admin_init: after loading any admin page, wp role list includes acme_content_content_editor (Content Editor).
cacheModules/Cache/ExampleCache.phpFramework Cache: remember() plus group invalidation on save_post (utilities)No UI; call get_recent_post_ids() from your own code or a test.
transientsModules/Transients/ExampleTransients.phpFramework Transients caching a remote request for an hour (utilities)No UI; call get_remote_payload() from a block, shortcode or REST route.
test-measure.github/workflows/test-measure.ymlThe CI caller for wp-shared-workflowsRuns on every pull request and on pushes to master.

Paths are relative to inc/, except the src/, templates/ and .github/ entries. Each module's test is tests/php/<Module>Test.php.

To call the REST example from the terminal as an administrator:

npm run wp-env run cli -- wp --user=admin eval \
'echo wp_json_encode( rest_do_request( "/acme-content-features/v1/examples" )->get_data() );'

After you remove an example, the original stays browsable in the skeleton source. To build your own version of any of these, use Scaffolding or the Development guide.

Optional development features​

Unlike example sets, these can be turned on and off at any time with npm run init -- --enable=<key> / --disable=<key>.

Init keySkeleton sourceDefaultResultMore
hmrwebpack.config.js, webpack.blocks.config.js, inc/Core/Assets.php, .env.localOnBrowserSync live reload for assets and PHP; Fast Refresh for block editor components. Toggling only flips ENABLE_HMR; dependencies stay installed.Live reload
tailwindbin/features/tailwind/, inc/Core/Assets.php, main plugin fileOffAdds src/css/tailwind.css and postcss.config.js, declares Tailwind dependencies, and sets ACME_CONTENT_FEATURES_ENABLE_TAILWIND to true so the stylesheet is enqueued.Tailwind