Suma Toolshed Plugin (v1.0.0)
A modular tools framework that provides a REST API for performing operations against BigCommerce and WooCommerce stores. Routes are auto-discovered from the filesystem, making it easy to add new tools without modifying core code.
Plugin Structure
suma-toolshed/
├── suma-toolshed.php ← Bootstrap, hook registration
├── inc/
│ ├── API.php ← Route auto-discovery + registration
│ ├── Route.php ← Base route class
│ ├── BigCommerce_Route.php ← BC-specific base class (v2 + v3 clients)
│ ├── WooCommerce_Route.php ← WC-specific base class
│ ├── Admin.php ← Admin module auto-loader
│ ├── Utils.php ← Shared utility functions
│ ├── routes/ ← Auto-discovered route modules
│ │ ├── product-export/
│ │ │ └── init.php
│ │ ├── bulk-update/
│ │ │ └── init.php
│ │ ├── category-sync/
│ │ │ └── init.php
│ │ └── [additional routes]/
│ └── mods/ ← Admin module auto-loader
│ ├── some-tool/
│ │ └── init.php
│ └── [additional modules]/
└── composer.json ← BigCommerce + WooCommerce API clients
Route Auto-Discovery
The API class automatically discovers and registers routes from subdirectories:
namespace Suma\ToolShed;
class API {
private array $routes = [];
private string $routes_path;
public function __construct() {
$this->routes_path = plugin_dir_path(__FILE__) . 'routes/';
}
/**
* Scans the routes directory for init.php files and loads them.
*
* @return void
*/
public function get_all_routes(): void {
$directories = glob($this->routes_path . '*', GLOB_ONLYDIR);
foreach ($directories as $directory) {
$init_file = $directory . '/init.php';
if (file_exists($init_file)) {
require_once $init_file;
}
}
/**
* Allow external plugins to register additional routes.
*
* @param API $api The API instance for route registration.
*/
do_action('suma_tools_register_routes', $this);
}
}
Adding a New Route
-
Create a subdirectory in
inc/routes/:inc/routes/my-new-tool/
└── init.php -
Define the route class in
init.php:
<?php
namespace Suma\ToolShed\Routes\MyNewTool;
use Suma\ToolShed\BigCommerce_Route;
class My_Route extends BigCommerce_Route {
/**
* Registers REST routes for this tool.
*
* @return void
*/
public function register_routes(): void {
register_rest_route('suma-tools/v1', '/my-new-tool', [
'methods' => 'POST',
'callback' => [$this, 'handle'],
'permission_callback' => [$this, 'check_permissions'],
]);
}
/**
* Handles the API request.
*
* @param \WP_REST_Request $request The incoming request.
* @return \WP_REST_Response
*/
public function handle(\WP_REST_Request $request): \WP_REST_Response {
$site_id = $request->get_param('site_id');
$this->setup($site_id); // Initializes BC clients from suma_sites data
// Perform BigCommerce operations...
$products = $this->v3_client->get('/catalog/products');
return new \WP_REST_Response(['data' => $products], 200);
}
}
// Auto-register
$route = new My_Route();
$route->register_routes();
Base Route Class
The Route base class provides common functionality:
namespace Suma\ToolShed;
class Route {
protected int $site_id;
/**
* Checks if the current user has permission to access this route.
*
* @return bool
*/
public function check_permissions(): bool {
return current_user_can('manage_options');
}
/**
* Loads site configuration from suma_sites table.
*
* @param int $site_id The site to configure for.
* @return void
*/
protected function load_site_config(int $site_id): void {
global $wpdb;
$this->site_id = $site_id;
// Load site credentials from suma_sites or related tables
}
}
BigCommerce Route
Extends Route with pre-configured BigCommerce v2 and v3 API clients:
namespace Suma\ToolShed;
use Bigcommerce\Api\Client as V2Client;
use BigCommerce\ApiV3\Client as V3Client;
class BigCommerce_Route extends Route {
protected V2Client $v2_client;
protected V3Client $v3_client;
/**
* Initializes BigCommerce API clients for a specific site.
*
* @param int $site_id The site whose credentials to use.
* @return void
*/
public function setup(int $site_id): void {
$this->load_site_config($site_id);
// V2 client (legacy endpoints)
V2Client::configure([
'store_url' => $this->config['store_url'],
'username' => $this->config['api_username'],
'api_key' => $this->config['api_key'],
]);
$this->v2_client = new V2Client();
// V3 client (modern endpoints)
$this->v3_client = new V3Client(
$this->config['store_hash'],
$this->config['client_id'],
$this->config['access_token']
);
}
}
Available BigCommerce Operations
| Operation | API Version | Endpoint |
|---|---|---|
| Get products | v3 | /catalog/products |
| Update product | v3 | /catalog/products/{id} |
| Get orders | v2 | /orders |
| Get customers | v3 | /customers |
| Get categories | v3 | /catalog/categories |
| Bulk price update | v3 | /pricing/products |
WooCommerce Route
Extends Route with the Automattic WooCommerce REST API client:
namespace Suma\ToolShed;
use Automattic\WooCommerce\Client as WC_Client;
class WooCommerce_Route extends Route {
protected WC_Client $wc_client;
/**
* Initializes WooCommerce API client for a specific site.
*
* @param int $site_id The site whose credentials to use.
* @return void
*/
public function setup(int $site_id): void {
$this->load_site_config($site_id);
$this->wc_client = new WC_Client(
$this->config['site_url'],
$this->config['consumer_key'],
$this->config['consumer_secret'],
[
'version' => 'wc/v3',
'timeout' => 30,
]
);
}
}
Available WooCommerce Operations
| Operation | Endpoint |
|---|---|
| Get products | wc/v3/products |
| Update product | wc/v3/products/{id} |
| Get orders | wc/v3/orders |
| Get customers | wc/v3/customers |
| Bulk update | wc/v3/products/batch |
Admin Module Auto-Loading
The Admin class auto-loads modules from the inc/mods/ directory, similar to route discovery:
class Admin {
/**
* Loads all admin modules from the mods directory.
*
* @return void
*/
public function load_modules(): void {
$mods_path = plugin_dir_path(__FILE__) . 'mods/';
$directories = glob($mods_path . '*', GLOB_ONLYDIR);
foreach ($directories as $directory) {
$init_file = $directory . '/init.php';
if (file_exists($init_file)) {
require_once $init_file;
}
}
}
}
Modules can add admin pages, settings, or background functionality without modifying the core plugin.
Utils Class
Shared utility functions:
class Utils {
/**
* Formats a file size in bytes to human-readable format.
*
* @param int $bytes File size in bytes.
* @return string Formatted size string.
*/
public static function format_bytes(int $bytes): string;
/**
* Sanitizes a filename for safe storage.
*
* @param string $filename The original filename.
* @return string Sanitized filename.
*/
public static function sanitize_filename(string $filename): string;
/**
* Generates a unique identifier.
*
* @return string UUID v4 string.
*/
public static function generate_uuid(): string;
}
Extensibility
External Route Registration
Other plugins can register routes via the suma_tools_register_routes action:
add_action('suma_tools_register_routes', function($api) {
// Register custom route from external plugin
require_once __DIR__ . '/my-custom-route.php';
$route = new My_Custom_Route();
$route->register_routes();
});
Credential Lookup
Routes automatically look up site credentials from the suma_sites table (managed by Suma Management), so any route can operate on any managed site by passing the site_id parameter.
Composer Dependencies
{
"require": {
"bigcommerce/api": "^2.0",
"bigcommerce/apiv3": "^1.0",
"automattic/woocommerce": "^3.0"
}
}
Security Considerations
- All routes require
manage_optionscapability by default - Site credentials are stored encrypted where possible
- API clients use HTTPS for all external calls
- Rate limiting follows platform-specific guidelines (BigCommerce: 150 req/30s, WooCommerce: varies)