Architecture
How PeoplePress boots, and the order in which its subsystems become available.
This area is still changing. Steps and screenshots may lag behind the current release.
PeoplePress does almost nothing at file load. The entry point registers an autoloader, boots a service container, and then hands control to a series of bootstrappers. Everything an addon can hook into exists because one of those bootstrappers put it there — which is why boot order, not file structure, is the thing to understand first.
The entry point
peoplepress.php runs five things, in this order:
require 'vendor/autoload.php'— Composer dependencies.require_once 'src/app/bootstrap/pp-hooks-mappings.php'— maps WordPress hooks onto PeoplePress-specific action hooks. This is what makes the later lifecycle hooks fire at predictable points in the WordPress request.- Registers
PP_Autoloaderfor thePeoplePress\namespace againstsrc/. PeoplePress::boot()— sets up the container: module manager, task manager, process manager, and the other global services, exposed as read-only properties on thePeoplePresssingleton.- The bootstrappers.
Boot order
PeoplePress::boot(); // service container
PP_Core_Bootstrapper::boot(); // core functions, module lifecycle hooks
PP_Bootstrapper::boot(); // shortcodes, UI, privacy levels, nav itemsPP_Core_Bootstrapper is the one that matters for extension: it loads core
function files and registers the module lifecycle hooks. Nothing that depends on
a module being registered can run before it.
Notification, background process, async task, and admin bootstrappers follow.
Source: peoplepress.php, class-peoplepress.php,
src/app/bootstrap/class-pp-core-bootstrapper.php
Why a container and not globals
Modules need to reach each other — the activity module reads member data, the
notification module reacts to almost everything — and WordPress offers no
structure for that beyond globals. The PeoplePress singleton exposes services
through a read-only magic getter, so a module can depend on a service without
being able to swap it out from under another module.
The trade-off: service resolution is not type-checked, so a typo in a service name is a runtime error rather than a static one.
Where addons attach
Third-party modules register on the pp_register_modules action, which fires on
plugins_loaded at priority 10100. By that point core has booted and the module
registry exists, so a module registered there participates in the same lifecycle
as a core one.
TODO(verify): the full lifecycle method sequence (initialize, load, setup,
init, rest_api_init, register_item_types, register_extensions) against
src/core/module/class-pp-module.php before this is promoted out of draft.
Request flow
TODO(verify): PP_Item_Matcher parses requests on the do_parse_request
filter, the wp action sets query state, and template_redirect dispatches
through PP_Route_Dispatcher. Confirm each against
src/core/pp-routing-functions.php before publishing.