Instruction file imported from campaignmonitor/forms-for-campaign-monitor (
.github/instructions/*.instructions.md). Copyright stays with the author.
WordPress Plugin: forms-for-campaign-monitor
This is a WordPress plugin that integrates Campaign Monitor email marketing with WordPress sites, providing customizable signup forms (Bar, Slideout, Lightbox, Button, Embedded).
Architecture
- PHP (WordPress Plugin): Core logic in
forms/core/, views informs/views/ - JavaScript: Admin JS in
forms/views/admin/js/, public JS informs/views/public/js/ - Entry point:
campaign-monitor.php(plugin bootstrap) - Main class:
forms/core/Application.php— handles hooks, scripts, routing - AJAX handler:
forms/core/Ajax.php— admin AJAX endpoint - Form model:
forms/core/Form.php— form CRUD and rendering
Security Requirements
- All admin AJAX endpoints (
wp_ajax_*) must include:current_user_can('manage_options')capability checkcheck_ajax_referer()nonce verification
- All admin POST endpoints (
admin_post_*) must include:current_user_can('manage_options')capability checkwp_verify_nonce()verification
- Nonces are delivered to JS via
wp_localize_script()asajax_request.nonce - All JS AJAX calls must include
dataToSend.nonce = ajax_request.nonce - Public endpoints (
wp_ajax_nopriv_*) do not require nonce or capability checks - User input must be sanitized using
Request::getPost()/Request::getParam()or WordPress sanitization functions - Never trust
$_GET,$_POST,$_REQUESTdirectly — use the plugin'sRequestclass orsanitize_text_field()
Code Review Focus Areas
- CSRF protection: Verify every admin AJAX/POST handler has nonce verification. Missing nonces was the root cause of CVE-2026-0674.
- Authorization: Every admin endpoint must check
current_user_can('manage_options')before processing. - Input sanitization: Watch for unsanitized user input, especially in database queries and HTML output.
- Output escaping: Ensure
esc_html(),esc_attr(),esc_url()are used when outputting user data. - SQL injection: Any direct database queries should use
$wpdb->prepare(). - File operations: Verify no user-controlled paths in file reads/writes.
Conventions
- Plugin version is tracked in three places:
campaign-monitor.phpheader,Application::VERSION, andreadme.txtStable tag. All three must match. - Changelog entries for security fixes should be vague (e.g., "Security enhancement for admin AJAX requests") to avoid disclosing details before users update.
- The plugin supports WordPress 3.9+ and PHP 5.3+. Do not use modern PHP features (typed properties, union types, etc.).