Module Development Best Practices
Naming Conventions
- Module ID:
kebab-case(e.g.,my-custom-module) - Functions: Prefix with module name (e.g.,
my_module_init()) - Settings group:
flavor_module_{module_id} - CSS classes: Prefix with module name (e.g.,
.my-module-wrapper) - JS globals: Avoid — use closures or modules
File Organization
my-module/
├── module.php # Entry point — keep it light
├── includes/ # PHP classes and functions
│ ├── class-handler.php
│ └── helpers.php
├── assets/
│ ├── style.css # Frontend styles
│ └── script.js # Frontend scripts
├── admin/
│ └── settings.php # Admin settings UI
└── templates/
└── display.php # Output templates
Performance
Conditional Loading
Only load assets when needed:
function my_module_assets(): void
{
// Only load on shop pages
if (!is_shop() && !is_product()) return;
wp_enqueue_style('my-module', ...);
wp_enqueue_script('my-module', ...);
}
Use Caching
// Cache expensive operations
$result = flavor_cache_get('my_module_data');
if ($result === null) {
$result = expensive_computation();
flavor_cache_set('my_module_data', $result, 3600);
}
Security
Sanitize All Input
$title = sanitize_text_field($_POST['title'] ?? '');
$html = wp_kses_post($_POST['content'] ?? '');
$url = esc_url_raw($_POST['url'] ?? '');
$number = absint($_POST['count'] ?? 0);
Escape All Output
echo esc_html($title);
echo esc_attr($class);
echo esc_url($link);
echo wp_kses_post($html_content);
Use Nonces
// In form
wp_nonce_field('my_module_action', 'my_module_nonce');
// In handler
if (!wp_verify_nonce($_POST['my_module_nonce'] ?? '', 'my_module_action')) {
wp_die('Security check failed');
}
Compatibility
Check Dependencies
function my_module_init(): void
{
// Check if required plugin function exists
if (!function_exists('wpec_get_option')) {
return; // Plugin not active, gracefully degrade
}
// Module code here
}
PHP Version Safety
// Use nullable types (PHP 8.0+)
function process(?int $param = null): void { }
// NOT implicit nullable (deprecated in PHP 8.4)
// function process(int $param = null): void { } // Bad!
Common Gotchas
Common Mistakes
- Using
get_option()for plugin/theme data — Always usewpec_get_option()orflavor_get_option() - Using
__()for translations — Useflavor_t()/flavor_te()instead - Using
returnin block render callbacks — Useecho - Using
data-lucideattributes — Use inline SVG instead - Forgetting
composer dump-autoload— Required after adding new PHP classes
Distribution
When distributing your module:
- Document requirements — PHP version, theme version, dependencies
- Include a README — Installation and usage instructions
- Version semantically — Major.Minor.Patch
- Test thoroughly — With different license tiers and theme versions