Skip to main content

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
  1. Using get_option() for plugin/theme data — Always use wpec_get_option() or flavor_get_option()
  2. Using __() for translations — Use flavor_t() / flavor_te() instead
  3. Using return in block render callbacks — Use echo
  4. Using data-lucide attributes — Use inline SVG instead
  5. Forgetting composer dump-autoload — Required after adding new PHP classes

Distribution

When distributing your module:

  1. Document requirements — PHP version, theme version, dependencies
  2. Include a README — Installation and usage instructions
  3. Version semantically — Major.Minor.Patch
  4. Test thoroughly — With different license tiers and theme versions