name: storegrowth-backend-dev description: Add or modify StoreGrowth (Sales Booster) backend PHP code following project conventions. Use when creating classes, services, hooks, REST controllers, ajax handlers, or modifying existing backend PHP. Read before writing backend PHP in this plugin.
StoreGrowth Backend Development
Guidance for writing backend PHP in the StoreGrowth Sales Booster plugin. For module scaffolding see storegrowth-module-dev; for review criteria see storegrowth-code-review.
Namespace & file structure
- Root namespace:
StorePulse\StoreGrowth\(PSR-4 →includes/). Note: NOTDokanorWeDevs. - Integrations:
StorePulse\StoreGrowth\Integrations\→integrations/includes/ - Modules:
StorePulse\StoreGrowth\Modules\{ModuleName}\→modules/{slug}/includes/(each mapped explicitly incomposer.jsonautoload) - Mozart-prefixed third-party:
StorePulse\StoreGrowth\ThirdParty\Packages\→lib/packages/. Import the DI container asStorePulse\StoreGrowth\ThirdParty\Packages\League\Container\..., neverLeague\Container\.... Never hand-editlib/— it's regenerated by composer (seestoregrowth-git). - File path mirrors namespace:
StorePulse\StoreGrowth\Modules\BoGo\OrderBogo→modules/bogo/includes/OrderBogo.php. - Every PHP file starts with
defined( 'ABSPATH' ) || exit;(or theif ( ! defined( 'ABSPATH' ) ) { exit; }form).
Conventions
- Methods / functions / variables:
snake_case(WordPress convention). - Hook names:
spsg_prefix for feature hooks (e.g.spsg_bogo_fly_cart_badge_enabled,spsg_modules);storegrowth_prefix for plugin-lifecycle hooks (storegrowth_loaded,storegrowth_module_after_boot). Usespsg_for new feature hooks. - Options / meta keys:
spsg_prefix (e.g.spsg_active_module_ids). - Constants:
STOREGROWTH_*(STOREGROWTH_DIR_PATH,STOREGROWTH_VERSION, …). - Singletons: use the
StorePulse\StoreGrowth\Traits\Singletontrait (private constructor +::instance()). @sincetag: every new class/method/property/param/hook/route gets@since SPSG_VERSION(the literal placeholder — never a hardcoded number). The release pipeline swaps it for the real version. Seestoregrowth-git.
Bootstrap & lifecycle
storegrowth-sales-booster.php builds the global container, registers the root ServiceProvider, requires each module/integration bootstrap.php, then boots Bootstrap (singleton). All runtime loading happens on the woocommerce_loaded action (Bootstrap::on_wc_loaded()) — the plugin no-ops without WooCommerce. Order: modules → assets → ajax → admin → hooks → integrations.
Access the container anywhere: storegrowth_get_container(). Bootstrap also has a magic __get resolving container entries.
Dependency injection
Uses league/container v4 (mozart-prefixed). Service providers extend:
BaseServiceProvider— register-only.BootableServiceProvider— adds an immediateboot().
Key helpers (from BaseServiceProvider) tag a class by every interface and abstract parent it has, so the container can later resolve "all X":
$this->add_with_implements_tags( $id, $concrete, $shared = false );
$this->share_with_implements_tags( $id, $concrete ); // shared = true
This is the mechanism behind auto-registration below.
Registering hooks — the HookRegistry pattern
To register WordPress hooks, implement StorePulse\StoreGrowth\Interfaces\HookRegistry. Bootstrap::register_hooks() resolves everything tagged HookRegistry and calls register_hooks() automatically:
namespace StorePulse\StoreGrowth\Modules\BoGo;
use StorePulse\StoreGrowth\Traits\Singleton;
use StorePulse\StoreGrowth\Interfaces\HookRegistry;
class EnqueueScript implements HookRegistry {
use Singleton;
/**
* @since SPSG_VERSION
*/
public function register_hooks(): void {
add_action( 'wp_enqueue_scripts', [ $this, 'front_scripts' ] );
add_filter( 'spsg_some_filter', [ $this, 'handle' ] );
}
}
Register the class in a BootstrapServiceProvider via share_with_implements_tags( EnqueueScript::class ) and it loads automatically when the owning module is active.
REST API controllers
Extend WP_REST_Controller. Bootstrap::register_rest_routes() resolves everything tagged WP_REST_Controller (on rest_api_init) and calls register_routes() — so just registering the controller in a provider wires it up.
- Namespace:
sales-booster/v1. Set in the constructor:$this->namespace = 'sales-booster/v1'; $this->rest_base = 'bogo/offers'; - Always provide a
permission_callbackon every route (e.g.[ $this, 'check_permission' ]returning a capability check likecurrent_user_can( 'manage_options' )). - Sanitize every
$requestparam (absint,sanitize_text_field,wc_clean, …); defineargswithsanitize_callback/validate_callback. - The plugin also extends WC's product controller:
includes/REST/ProductController.php(sales-booster/v1, product picker for the settings UI).
namespace StorePulse\StoreGrowth\Modules\BoGo\REST;
use WP_REST_Controller;
use WP_REST_Server;
class BogoController extends WP_REST_Controller {
public function __construct() {
$this->namespace = 'sales-booster/v1';
$this->rest_base = 'bogo/offers';
}
public function register_routes(): void {
register_rest_route( $this->namespace, '/' . $this->rest_base, [
[
'methods' => WP_REST_Server::READABLE,
'callback' => [ $this, 'get_items' ],
'permission_callback' => [ $this, 'check_permission' ],
'args' => $this->get_collection_params(),
],
] );
}
}
Ajax
Admin-ajax handlers live in includes/Ajax.php (container alias ajax-service, loaded only when DOING_AJAX). Actions use the spsg_ prefix, e.g. add_action( 'wp_ajax_spsg_admin_ajax', ... ). New REST-style data should prefer a REST controller; ajax is for the existing admin-ajax surface.
i18n
- Text domain:
storegrowth-sales-boosterfor ALL translatable strings. - Use
__(),esc_html__(),esc_attr__(),_e(),_n(),_x()with the text domain. - Add
/* translators: */comments before anysprintf()with placeholders. Never concatenate translated strings — usesprintf(). - Regenerate the POT with
npm run makepot.
Helpers
StorePulse\StoreGrowth\Helper— static helpers:Helper::get_plugin_assets_url(),Helper::get_modules_url(),Helper::get_modules_path().helpers/functions.php— global procedural helpers (composerfilesautoload).
Coding standards
- Ruleset
phpcs.xml:WordPress+PHPCompatibilityWP+WooCommerce-Core, text domain enforced. - Run
composer phpcs(andcomposer phpcbfto auto-fix). PRs run PHPCS on changed files (.github/workflows/phpcs.yml). - PHP 7.4+. Use strict comparisons (
===/!==) andin_array( $needle, $haystack, true ).
Key reference files
storegrowth-sales-booster.php— entry point, container bootstrap, module/integration includesincludes/Bootstrap.php— lifecycle, hook & REST auto-registrationincludes/DependencyManagement/BaseServiceProvider.php—*_with_implements_tags()helpersincludes/DependencyManagement/Providers/ServiceProvider.php— root providerincludes/Interfaces/HookRegistry.php,includes/Interfaces/ModuleSkeleton.phpincludes/Helper.php,helpers/functions.php