Thank you for your interest in contributing to Contact Form 7 to API! This document provides guidelines and instructions for contributing to this project.
- Development Setup
- Coding Standards
- Testing Requirements
- Pull Request Process
- Project Architecture
- CI/CD Workflows
- Release Process
- PHP: 8.2 or higher
- WordPress: 6.5 or higher
- Contact Form 7: Latest version
- Composer: 2.x
- MySQL: 5.7+ or 8.0+ (for tests)
- Clone the repository:
git clone https://github.com/SilverAssist/contact-form-to-api.git
cd contact-form-to-api- Install dependencies:
composer install- Set up WordPress Test Suite (for running tests):
./scripts/install-wp-tests.sh cf7_api_test root '' localhost latestThe project uses the WordPress Test Suite for integration testing. The test environment is automatically set up when running quality checks.
Environment Variables:
export WP_TESTS_DIR=/tmp/wordpress-tests-lib
export WP_CORE_DIR=/tmp/wordpress/Manual Setup:
# Install WordPress Test Suite
bash scripts/install-wp-tests.sh <db-name> <db-user> <db-pass> <db-host> <wp-version>
# Example
bash scripts/install-wp-tests.sh cf7_api_test root '' localhost latestThis project follows WordPress-Extra coding standards with SilverAssist extensions:
- ALL strings MUST use double quotes:
"string"not'string' - i18n functions:
__("Text", "contact-form-to-api")not__('text', 'domain') - Exception: Single quotes only inside double-quoted strings when necessary
- Use typed properties and return types
- Use constructor property promotion where appropriate
- Prefer
matchoverswitchfor cleaner code - Use null coalescing operator
?? - Use short array syntax
[]notarray()
- Prefix all WordPress functions with
\in namespaced code:\add_action(),\get_option() - NO
\prefix for PHP native functions:array_key_exists(),explode() - Text domain:
"contact-form-to-api"(literal string, not constant) - Use WordPress escaping:
\esc_html(),\esc_attr(),\esc_url() - Use WordPress sanitization:
\sanitize_text_field(),\sanitize_email()
- Namespace:
SilverAssist\ContactFormToAPI\ - Import all classes at top of file (alphabetically sorted)
- NEVER import classes from same namespace
- NEVER use fully qualified names in methods
- Complete PHPDoc for ALL classes, methods, and properties
- Required tags:
@since,@param,@return,@throws - ALL documentation in English
- Use translator comments for sprintf placeholders
Run all quality checks:
./scripts/run-quality-checks.shIndividual checks:
# PHP CodeSniffer
composer phpcs
# Auto-fix PHPCS issues
composer phpcbf
# PHPStan (Level 8)
composer phpstan
# PHPUnit Tests
composer test
# Test Coverage
composer test:coverage- Minimum Coverage: 80% for new code
- Test Types: Unit tests, Integration tests, WordPress integration tests
- Framework: PHPUnit 9.6+ with WordPress Test Suite
-
Extend appropriate base class:
SilverAssist\ContactFormToAPI\Tests\Helpers\TestCasefor unit testsSilverAssist\ContactFormToAPI\Tests\Helpers\CF7TestCasefor CF7 integration tests
-
Use descriptive test method names:
- Pattern:
test_<method_name>_<scenario>_<expected_result>() - Example:
test_activate_creates_database_tables()
- Pattern:
-
Test both success and failure scenarios
-
Use specific assertions:
assertSame()overassertEquals()
# Run all tests
vendor/bin/phpunit
# Run specific test file
vendor/bin/phpunit tests/Unit/PluginTest.php
# Run with coverage
vendor/bin/phpunit --coverage-html coverage
# Run with testdox output
vendor/bin/phpunit --testdox-
Create a feature branch:
git checkout -b feature/your-feature-name
-
Run quality checks:
./scripts/run-quality-checks.sh
All checks must pass before submitting PR.
-
Update documentation:
- Add/update PHPDoc comments
- Update README.md if needed
- Add entry to CHANGELOG.md
-
Write/update tests:
- Add tests for new functionality
- Update existing tests if modifying behavior
- Ensure all tests pass
Follow Conventional Commits:
<type>(<scope>): <subject>
<body>
<footer>
Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting, etc.)refactor: Code refactoringtest: Test updateschore: Build process or auxiliary tool changes
Examples:
feat(api): add support for XML payload format
- Implement XML serialization for form data
- Add XML content-type header support
- Add tests for XML format processing
Closes #123
fix(integration): resolve CF7 mail tag processing issue
- Fix mail tag replacement for nested arrays
- Update test assertions for edge cases
Fixes #456
- Code follows SilverAssist WordPress standards
- All strings use double quotes
- Text domain uses literal "contact-form-to-api"
- PHPDoc comments are complete
- All quality checks pass (PHPCS, PHPStan, PHPUnit)
- Tests added/updated for changes
- Documentation updated
- CHANGELOG.md updated
- Commit messages follow conventional commits
- Branch is up to date with main
- Submit PR with clear description
- Address automated CI/CD feedback
- Respond to code review comments
- Make requested changes in new commits
- Wait for approval from maintainers
- PR will be squashed and merged
contact-form-to-api/
├── includes/ # Source code (PSR-4)
│ ├── Core/ # Core plugin functionality
│ │ ├── Interfaces/ # Contracts
│ │ ├── Activator.php # Lifecycle management
│ │ ├── Plugin.php # Main controller
│ │ └── Updater.php # GitHub updater
│ └── ContactForm/ # CF7 integration
│ └── Integration.php
├── assets/ # Frontend assets
│ ├── css/ # Stylesheets
│ └── js/ # JavaScript
├── tests/ # Test suite
│ ├── Helpers/ # Test utilities
│ ├── Unit/ # Unit tests
│ ├── Integration/ # WordPress integration tests
│ └── ContactForm/ # CF7 integration tests
├── scripts/ # Build and utility scripts
├── docs/ # Documentation
└── languages/ # Translation files
All components implement LoadableInterface:
interface LoadableInterface {
public function init(): void;
public function get_priority(): int;
public function should_load(): bool;
}Main classes use singleton:
public static function instance(): self {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}- 10: Core components
- 20: Services
- 30: Admin components
- 40: Utility components
ALWAYS use plugin constants instead of hardcoded values:
CF7_API_VERSION // Plugin version
CF7_API_FILE // Main plugin file
CF7_API_DIR // Plugin directory path
CF7_API_URL // Plugin URL
CF7_API_BASENAME // Plugin basename
CF7_API_MIN_PHP_VERSION
CF7_API_MIN_WP_VERSIONi18n Text Domain: Always use literal string 'contact-form-to-api' (not a constant) for WordPress i18n extraction tools.
The project uses GitHub Actions for automated testing and releases:
.github/workflows/
├── quality-checks.yml # Reusable quality check workflow
├── ci.yml # Pull request validation
├── release.yml # Automated releases
└── dependency-updates.yml # Automated dependency updates
Triggers: All pull requests to main or develop
Required Checks:
- ✅ Composer validation
- ✅ PHPCS (WordPress-Extra)
- ✅ PHPStan (Level 8)
- ✅ PHPUnit (all tests passing)
main (production)
└── develop (integration)
└── feature/* (features)
└── fix/* (bug fixes)
-
Create feature branch from
develop:git checkout -b feature/your-feature-name develop
-
Run quality checks frequently:
./scripts/run-quality-checks.sh
-
Commit with conventional commits:
git commit -m "feat(scope): description" -
Push and create PR to
develop -
After CI passes and approval, PR is squashed and merged
Follow Semantic Versioning 2.0.0:
- MAJOR: Breaking changes
- MINOR: New features (backward-compatible)
- PATCH: Bug fixes (backward-compatible)
- All tests passing
- PHPCS clean (0 errors)
- PHPStan Level 8 passing
- CHANGELOG.md updated
- Manual testing completed
-
Update version:
./scripts/update-version.sh 1.2.0
-
Update CHANGELOG.md with release notes
-
Run quality checks:
./scripts/run-quality-checks.sh
-
Commit and tag:
git commit -am "chore: prepare release v1.2.0" git tag -a v1.2.0 -m "Release version 1.2.0" git push origin main --tags
-
GitHub Actions will automatically:
- Run quality checks
- Build release package
- Create GitHub release with ZIP
For critical issues:
-
Create hotfix branch from
main:git checkout -b hotfix/1.2.1 main
-
Implement fix with regression test
-
Update version to patch number (1.2.1)
-
Tag and push (triggers release)
-
Merge back to
mainanddevelop
- SilverAssist Standards
- WordPress Coding Standards
- PHPStan Documentation
- PHPUnit Documentation
- Contact Form 7 Documentation
// Before displaying logs page
do_action('cf7_api_before_logs_page');
// After log deletion
do_action('cf7_api_log_deleted', $log_id);
// After bulk deletion
do_action('cf7_api_logs_bulk_deleted', $log_ids);
// Before sending data to API
do_action('cf7_api_before_send', $form_id, $data, $config);
// After API response received
do_action('cf7_api_after_send', $form_id, $response, $log_id);// Modify logs query arguments
$args = apply_filters('cf7_api_logs_query_args', $args);
// Modify statistics output
$stats = apply_filters('cf7_api_logs_statistics', $stats, $form_id);
// Modify request data before sending
$data = apply_filters('cf7_api_request_data', $data, $form_id);
// Modify request headers
$headers = apply_filters('cf7_api_request_headers', $headers, $form_id);
// Modify API response handling
$response = apply_filters('cf7_api_response', $response, $form_id);Logs are stored in custom table: {prefix}cf7_api_logs
Indexed columns for performance:
form_idstatuscreated_at
- Open an issue
- Check existing discussions
- Review documentation
Thank you for contributing! 🎉