Developer Library
This guide describes the current SCPress extension points and the path a request takes through the platform. It reflects the implementation in this repository; a hook is available only when the relevant component runs.
Platform map
| Path | Responsibility |
|---|---|
index.php | Front controller for public requests. |
sc-core/bootstrap.php | Loads core services, connects the database, starts sessions, loads active plugins, initializes the active theme, and applies security settings. |
sc-core/Router.php | Routes public pages, admin paths, and /api/*; fires sc_before_dispatch before matching a route. |
sc-core/Hooks.php | In-process action and filter callback registry. |
sc-core/helpers.php | Public template helpers, hooks, and shared content functions. |
sc-core/PluginManager.php | Discovers plugin folders and manifests, loads active plugin entry files, and fires plugin lifecycle actions. |
sc-core/ThemeManager.php | Loads core templates and current content, and initializes visual theme settings. |
sc-core/WidgetManager.php | Registers widget types and zones, then renders assigned widgets. |
sc-admin/ | Signed-in administration screens. Plugins can add menu items and editor tools through documented actions. |
sc-content/plugins/ | Installed plugin code. Each plugin should use its own folder and unique prefix/namespace. |
sc-content/themes/ | Theme packages and StyleFinder child-theme overrides. SCPress core owns page operations and templates. |
Request and extension lifecycle
sc-core/bootstrap.phploads core classes and helper functions.- The database and session are initialized.
- Active plugin entry files are required from
sc-content/plugins/<plugin-id>/; plugins register actions and filters while loading. - SCPress fires
sc_plugins_loaded, then initializes the active theme and firessc_theme_init($activeTheme). - The router fires
sc_before_dispatch($path), then dispatches the requested page or API route. - Frontend templates call shared helpers such as
sc_header(),sc_the_content(), widget rendering, andsc_footer().
Actions and filters
Register with the SCPress helpers or the WordPress-compatible aliases:
sc_add_action('sc_head', 'my_plugin_add_markup', 10);
sc_add_filter('the_content', 'my_plugin_add_note', 20);
function my_plugin_add_markup(): void {
echo '<meta name="my-plugin" content="enabled">';
}
function my_plugin_add_note(string $content, ?array $post = null): string {
return $content . '<p class="my-plugin-note">A note added by my plugin.</p>';
}Equivalent aliases include add_action, do_action, add_filter, and apply_filters. SCPress callbacks run in ascending priority order (lower number first; default 10). Actions receive the arguments passed by the caller. Filters receive the value first and must return the updated value.
The compatibility bridge currently accepts an $accepted_args parameter for add_action() and add_filter(), but SCPress's hook dispatcher does not use it to trim callback arguments. Write callbacks to accept the arguments documented for the hook and avoid relying on WordPress-only hook behavior that is not listed here.
Core action hooks
| Hook | Arguments | Runs when |
|---|---|---|
sc_before_dispatch | $path | Before a URL is routed; a callback that short-circuits routing must complete the response itself. |
sc_plugins_loaded | none | After active plugin entry files have been included. |
sc_plugin_activated | $pluginId | After a plugin is activated. |
sc_plugin_deactivated | $pluginId | After a plugin is deactivated. |
sc_theme_init | $activeTheme | When the active theme settings and core widget zones are initialized. |
sc_get_header | $name | When sc_header($name) is called. |
sc_get_footer | $name | When sc_footer($name) is called. |
sc_head | none | At the frontend head extension point. |
sc_footer | none | At the frontend footer extension point. |
sc_admin_head | none | In the admin document head. |
sc_admin_menu | none | In the admin sidebar; callbacks may output their own menu links. |
sc_admin_post_editor_tools | $post, $action | In the post editor tools area. |
sc_api_center_ai_settings | none | At the API Center AI settings extension point. |
sc_subscription_signup_fields | none | In the registration form extension point. |
sc_api_{endpoint} | none | For /api/{endpoint} requests; replace {endpoint} with the route name. |
Core filter hooks
| Hook | Arguments | Return |
|---|---|---|
the_content | $content, sometimes $post | Updated HTML/content string. |
sc_page_templates | $templates | Updated associative array of page template IDs and labels. |
sc_widget_render | $output, $widget, $settings | Updated widget HTML. |
sc_render_zone_output | $output, $zoneId, $widgets | Updated rendered widget-zone HTML. |
sc_notification_can_send | $canReceive, $userId, $type, $payload | Boolean allow/deny value. |
sc_validate_user_registration | $result, $_POST | Result array, normally ['valid' => bool, 'error' => string]. |
sc_user_registration_redirect | $redirect, $userId, $_POST | Redirect URL string. |
Example: register a page template label without replacing the core template system:
sc_add_filter('sc_page_templates', static function (array $templates): array {
$templates['my-landing'] = 'My Landing Page';
return $templates;
});This filter adds the label to the page editor. At present ThemeManager::loadTemplate() loads files from sc-core/templates/ only, so adding a label does not give a plugin a separate template loader. For plugin-specific page output, use a shortcode, a content filter, or a route action until a plugin template API is added.
Building a plugin
Create a unique folder and entry file:
sc-content/plugins/my-plugin/
├── plugin.json
└── my-plugin.phpMinimal manifest:
{
"name": "My Plugin",
"slug": "my-plugin",
"version": "1.0.0",
"author": "Your name",
"description": "A short description of what it adds.",
"entry": "my-plugin.php"
}Minimal entry file:
<?php
declare(strict_types=1);
if (!defined('SC_PATH')) {
exit;
}
sc_add_action('sc_plugins_loaded', static function (): void {
// Register plugin services after active plugin files are loaded.
});Use namespaced classes or a distinctive prefix for functions, classes, database tables, option keys, routes, and asset handles. Escape output at the point of display, validate and sanitize incoming values, check permissions on admin operations, and use CSRF protection for state-changing requests. Do not assume an uploaded plugin is trusted merely because it is installed.
Template helpers
Common helpers in sc-core/helpers.php include:
sc_header(); // Render the SCPress header and shell.
sc_footer(); // Render the SCPress footer and shell.
sc_the_title(); // Print the current title, escaped.
sc_the_content(); // Print the filtered current page/post content.
sc_site_title(); // Return the configured site title.
sc_site_tagline(); // Return the configured site tagline.
sc_theme_url('assets/app.css'); // Resolve a theme asset URL.
sc_render_widgets('sidebar_left'); // Render a registered widget zone.
sc_render_page_footer(); // Render the configurable page footer.the_content is applied before page content is printed. Use the current-post helpers or ThemeManager where a plugin needs the current record; do not query by a hard-coded page ID.
Data, APIs, widgets, and compatibility
- Use
SCPress\Core\Databasefor prepared database queries and site options. The platform supports SQLite and MySQL through the same wrapper; write SQL compatible with both where practical. - Register REST/API routes through the API services or the
sc_api_{endpoint}action for a small custom endpoint. Authenticate and authorize write operations, validate request data, and return JSON with an appropriate status code. - Register custom widget types through
WidgetManager::registerWidgetType()and render zones throughsc_render_widgets(); registered built-in zones includecanvas_widgets,top_bar,sidebar_left,sidebar_right, andbottom_bar. - SCPress provides selected WordPress-compatible functions for migration. Compatibility does not mean every WordPress API, hook timing, plugin, or theme is supported. Prefer the SCPress helpers and documented hook names for new work.
- SCPress core owns content operations, routing, the shell, navigation, widget zones, and page templates. Theme packages primarily provide reusable visual settings; follow the current theme and child-theme documentation for supported styling extensions.
Source of truth
Hook names and signatures are taken from call sites in sc-core/ and sc-admin/. They can change as the platform evolves. Before depending on a hook, verify the call site for the SCPress version you target and keep plugins compatible with the minimum version they declare.