Getting Started with Woodev Framework¶
This guide covers everything you need to start building WooCommerce plugins with the Woodev Framework.
Requirements¶
Server Requirements¶
| Requirement | Minimum | Recommended |
|---|---|---|
| PHP | 7.4 | 8.1+ |
| WordPress | 5.9 | 6.4+ |
| WooCommerce | 5.6 | 8.0+ |
| MySQL | 5.6 | 8.0+ |
| PHP Extensions | curl, json | mbstring, xml |
Required PHP Extensions¶
The framework can check for required extensions automatically:
<?php
parent::__construct(
'my-plugin',
'1.0.0',
[
'dependencies' => [
'php_extensions' => [ 'curl', 'json', 'mbstring' ],
],
]
);
Required PHP Functions¶
<?php
parent::__construct(
'my-plugin',
'1.0.0',
[
'dependencies' => [
'php_functions' => [ 'gzinflate', 'base64_decode' ],
],
]
);
Required PHP Settings¶
<?php
parent::__construct(
'my-plugin',
'1.0.0',
[
'dependencies' => [
'php_settings' => [
'allow_url_fopen' => '1',
'max_execution_time' => '30',
],
],
]
);
Installation¶
Step 1: Include the Framework¶
Copy the woodev/ directory into your plugin:
my-plugin/
├── my-plugin.php
├── includes/
│ └── class-my-plugin.php
└── woodev/
├── bootstrap.php
├── class-plugin.php
└── ...
Step 2: Register Your Plugin¶
In your main plugin file (my-plugin.php):
<?php
/**
* Plugin Name: My Plugin
* Plugin URI: https://example.com/my-plugin
* Description: My WooCommerce plugin
* Version: 1.0.0
* Author: Your Name
* Text Domain: my-plugin
* Domain Path: /languages
* Requires at least: 5.9
* Requires PHP: 7.4
* WC requires at least: 5.6
* License: GPL-3.0+
* License URI: http://www.gnu.org/licenses/gpl-3.0.txt
*/
defined( 'ABSPATH' ) || exit;
// Include the bootstrap file
if ( ! class_exists( 'Woodev_Plugin_Bootstrap' ) ) {
require_once plugin_dir_path( __FILE__ ) . 'woodev/bootstrap.php';
}
// Initialize the plugin
add_action( 'plugins_loaded', 'init_my_plugin', 0 );
function init_my_plugin() {
Woodev_Plugin_Bootstrap::instance()->register_plugin(
'1.4.0', // Framework version bundled
'My Plugin',
__FILE__,
'my_plugin_init',
[
'minimum_wc_version' => '8.0',
'minimum_wp_version' => '5.9',
'backwards_compatible' => '1.4.0',
]
);
}
Step 3: Create Plugin Class¶
Create includes/class-my-plugin.php:
<?php
/**
* Main Plugin Class
*
* @package MyPlugin
*/
defined( 'ABSPATH' ) || exit;
/**
* Main Plugin Class
*/
final class My_Plugin extends Woodev_Plugin {
/**
* @var self|null
*/
private static $instance;
/**
* Get plugin instance
*
* @return self
*/
public static function instance(): self {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructs the class
*/
public function __construct() {
parent::__construct(
'my-plugin',
'1.0.0',
[
'text_domain' => 'my-plugin',
'supported_features' => [
'hpos' => true,
'blocks' => [
'cart' => true,
'checkout' => true,
],
],
]
);
}
/**
* Get the main plugin file
*
* @return string
*/
protected function get_file() {
return __FILE__;
}
/**
* Get the plugin name
*
* @return string
*/
public function get_plugin_name() {
return __( 'My Plugin', 'my-plugin' );
}
/**
* Get the download ID for licensing
* Return 0 if no licensing
*
* @return int
*/
public function get_download_id() {
return 0;
}
}
Step 4: Initialize the Plugin¶
Back in my-plugin.php:
<?php
function my_plugin_init() {
require_once plugin_dir_path( __FILE__ ) . 'includes/class-my-plugin.php';
return My_Plugin::instance();
}
Architecture Overview¶
Framework Bootstrap Flow¶
graph TD
A[Plugin File Loads] --> B[Include bootstrap.php]
B --> C[Call register_plugin]
C --> D[plugins_loaded priority 0]
D --> E{Framework Already Loaded?}
E -->|No| F[Load class-plugin.php]
E -->|Yes| G[Skip Loading]
F --> H[Call Plugin Factory]
G --> H
H --> I[Plugin Instance Created]
I --> J[Plugin Hooks Registered]
Plugin Lifecycle¶
1. Registration (register_plugin)
↓
2. Bootstrap (plugins_loaded)
↓
3. Dependencies Check
↓
4. Plugin Construction
↓
5. init hook
↓
6. admin_init (if admin)
↓
7. before_woocommerce_init
↓
8. woocommerce_init
Directory Structure¶
Recommended plugin structure:
my-plugin/
├── my-plugin.php # Main plugin file
├── includes/
│ ├── class-my-plugin.php # Main plugin class
│ ├── class-settings.php # Settings handler
│ ├── class-api.php # API client
│ └── class-admin.php # Admin handler
├── admin/
│ ├── class-admin-page.php # Admin page class
│ └── views/
│ └── settings.php # Settings view
├── assets/
│ ├── css/
│ │ └── admin.css
│ └── js/
│ └── admin.js
├── languages/
│ └── my-plugin.pot
├── templates/
│ └── email-template.php
└── woodev/ # Framework directory
├── bootstrap.php
├── class-plugin.php
└── ...
Plugin Registration Arguments¶
Complete Example¶
<?php
Woodev_Plugin_Bootstrap::instance()->register_plugin(
'1.4.0', // Framework version
'My Plugin',
__FILE__,
'my_plugin_init',
[
// Version requirements
'minimum_wc_version' => '8.0',
'minimum_wp_version' => '5.9',
'backwards_compatible' => '1.4.0',
// Plugin type flags
'load_shipping_method' => false,
'is_payment_gateway' => false,
// Text domain
'text_domain' => 'my-plugin',
]
);
Arguments Reference¶
| Argument | Type | Default | Description |
|---|---|---|---|
minimum_wc_version |
string |
'' |
Minimum WooCommerce version |
minimum_wp_version |
string |
'' |
Minimum WordPress version |
backwards_compatible |
string |
'' |
Minimum framework version for compatibility |
load_shipping_method |
bool |
false |
Load shipping method base classes |
is_payment_gateway |
bool |
false |
Load payment gateway base classes |
Plugin Constructor Arguments¶
Complete Example¶
<?php
parent::__construct(
'my-plugin', // Plugin ID
'1.0.0', // Plugin version
[
'text_domain' => 'my-plugin',
// PHP dependencies
'dependencies' => [
'php_extensions' => [ 'curl', 'json' ],
'php_functions' => [ 'mb_strtolower' ],
'php_settings' => [ 'allow_url_fopen' ],
],
// Feature support
'supported_features' => [
'hpos' => true,
'blocks' => [
'cart' => true,
'checkout' => true,
],
],
]
);
Arguments Reference¶
| Argument | Type | Description |
|---|---|---|
$id |
string |
Unique plugin identifier |
$version |
string |
Plugin version |
$args['text_domain'] |
string |
Text domain for translations |
$args['dependencies'] |
array |
PHP dependencies |
$args['supported_features'] |
array |
Feature flags |
Required Methods¶
Every plugin must implement these three methods:
<?php
class My_Plugin extends Woodev_Plugin {
protected function get_file() {
return __FILE__;
}
public function get_plugin_name() {
return __( 'My Plugin', 'my-plugin' );
}
public function get_download_id() {
return 0; // EDD download ID or 0
}
}
Optional Methods¶
Override these methods to customize plugin behavior:
Override the init_* methods (not the get_* getters) to customize plugin subsystems:
<?php
class My_Plugin extends Woodev_Plugin {
// Custom settings handler (this is the one getter you override)
public function get_settings_handler() {
return new My_Settings( $this );
}
// Custom lifecycle handler
protected function init_lifecycle_handler() {
$this->lifecycle_handler = new My_Lifecycle( $this );
}
// Custom setup wizard
protected function init_setup_wizard_handler() {
parent::init_setup_wizard_handler();
$this->setup_wizard_handler = new My_Setup_Wizard( $this );
}
// Custom blocks handler
protected function init_blocks_handler(): void {
parent::init_blocks_handler();
$this->blocks_handler = new My_Blocks_Handler( $this );
}
// Custom REST API handler
protected function init_rest_api_handler() {
$this->rest_api_handler = new My_REST_API( $this );
}
}
Common Tasks¶
Adding Admin Menu¶
<?php
class My_Plugin extends Woodev_Plugin {
public function init_admin() {
parent::init_admin();
add_action( 'admin_menu', [ $this, 'add_admin_menu' ] );
}
public function add_admin_menu() {
add_submenu_page(
'woocommerce',
__( 'My Plugin', 'my-plugin' ),
__( 'My Plugin', 'my-plugin' ),
'manage_woocommerce',
'my-plugin',
[ $this, 'render_settings_page' ]
);
}
public function render_settings_page() {
echo '<h1>' . esc_html( $this->get_plugin_name() ) . '</h1>';
// Settings form here
}
}
Adding Settings¶
<?php
class My_Settings extends Woodev_Abstract_Settings {
public function __construct() {
parent::__construct( 'my-plugin' );
}
protected function register_settings() {
$this->register_setting(
'api_key',
'string',
[
'name' => __( 'API Key', 'my-plugin' ),
'description' => __( 'Your API key', 'my-plugin' ),
'default' => '',
]
);
}
}
Adding Background Jobs¶
<?php
class My_Job_Handler extends Woodev_Background_Job_Handler {
protected $prefix = 'my_plugin';
protected $action = 'process';
protected function process_item( $item, $job ) {
// Process item
return null;
}
}
// Usage
$handler = new My_Job_Handler();
$job = $handler->create_job( [
'data' => [ [ 'id' => 1 ], [ 'id' => 2 ] ],
] );
$handler->dispatch();
Debugging¶
Enable Debug Mode¶
<?php
// In wp-config.php
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
Logging¶
<?php
// Log message
$plugin->log( 'Processing order #' . $order_id );
// Log error
$plugin->log( 'Error: ' . $error_message );
// View logs: WooCommerce > Status > Logs
System Status¶
Your plugin automatically adds data to:
WooCommerce > Status > [Your Plugin]
Best Practices¶
1. Use Singleton Pattern¶
<?php
final class My_Plugin extends Woodev_Plugin {
private static $instance;
public static function instance(): self {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
}
2. Mark Class as Final¶
3. Use Text Domain¶
4. Escape Output¶
5. Sanitize Input¶
<?php
// Sanitize input
$value = sanitize_text_field( $_POST['value'] ?? '' );
$id = absint( $_GET['id'] ?? 0 );
Next Steps¶
After completing setup:
- Core Framework — Learn about the plugin base class
- Settings API — Add plugin settings
- Admin Module — Create admin pages
- Utilities — Implement background processing
Troubleshooting¶
Plugin Not Loading¶
- Check that
bootstrap.phpis included correctly - Verify
register_plugin()is called onplugins_loaded - Check PHP error logs for fatal errors
Dependencies Not Met¶
The framework displays admin notices for missing dependencies. Check:
- PHP extensions in
phpinfo() - PHP functions availability
- PHP settings in
php.ini
Version Conflicts¶
If multiple plugins bundle different framework versions:
- The highest version is always loaded
- Lower version plugins still initialize
- Check
backwards_compatibleargument
For more information, see README.md and Core Framework.