Thank you for considering contributing to the Integration Features Block! This document provides guidelines for development and contribution.
- Development Setup
- Development Workflow
- Code Standards
- Testing
- Pull Request Process
- Architecture Guidelines
- Node.js 18+ and npm 9+
- WordPress 6.0+ development environment
- Basic understanding of React and TypeScript
- Familiarity with WordPress Gutenberg block development
-
Clone the repository:
git clone https://github.com/code-atlantic/integration-features-block.git cd integration-features-block -
Install dependencies:
npm install
-
Start development build:
npm start
-
Create production build:
npm run build
npm start- Start development mode with watchnpm run build- Create production buildnpm run type-check- Run TypeScript type checkingnpm run lint:js- Lint JavaScript/TypeScript filesnpm run lint:css- Lint SCSS filesnpm run format- Format code with Prettier
-
Create a feature branch:
git checkout -b feature/your-feature-name
-
Make changes with
npm startrunning for hot reload -
Test changes in WordPress editor
-
Run quality checks:
npm run type-check npm run lint:js npm run lint:css
-
Build for production:
npm run build
-
Commit changes with descriptive message
-
Push and create pull request
- Strict mode enabled: All code must pass strict TypeScript checks
- Explicit types: Prefer explicit type annotations over inference for public APIs
- No
any: Avoidanytype; useunknownor proper types - Interface over type: Use
interfacefor object shapes,typefor unions/intersections
Example:
// ✅ GOOD
interface MyProps {
label: string;
tier: TierType;
}
export function MyComponent({ label, tier }: MyProps): JSX.Element {
// ...
}
// ❌ BAD
export function MyComponent(props: any) {
// ...
}Always use derived state with useMemo instead of useEffect + setAttributes:
// ✅ GOOD: Derived state
const hasDescription = useMemo(
() => computeHasDescription(innerBlocks || []),
[innerBlocks]
);
// ❌ BAD: useEffect feedback loop risk
useEffect(() => {
setAttributes({ hasDescription: computeHasDescription(innerBlocks) });
}, [innerBlocks]);- Use
useMemofor expensive computations - Use
useSelectfor WordPress data store access - Avoid
useEffectfor synchronizing state to attributes - Keep hooks at top level (no conditional hooks)
- BEM methodology: Use Block-Element-Modifier naming
- Prefix classes: All classes start with
pm-(Popup Maker) - Mobile-first: Use
min-widthmedia queries - Accessibility: Include focus states, high contrast mode, reduced motion
Example:
// ✅ GOOD
.pm-integration-feature {
&__header {
display: flex;
}
&--pro {
background-color: var(--action);
}
}
// ❌ BAD
.feature {
.header {
display: flex;
}
}- Files: kebab-case (
integration-feature.tsx) - Components: PascalCase (
IntegrationFeature) - Functions: camelCase (
computeHasDescription) - Constants: UPPER_SNAKE_CASE (
TIER_CONFIG) - Types/Interfaces: PascalCase (
TierType,EditProps)
src/integration-features/
├── block.json # Block metadata and attributes
├── types.ts # TypeScript type definitions
├── edit.tsx # Editor component
├── save.tsx # Frontend save component
├── style.scss # Frontend + editor styles
├── editor.scss # Editor-only styles
├── index.ts # Block registration
└── lib/
└── hasDescription.ts # Shared utilities
- Unit tests: 70% coverage
- Integration tests: 15% coverage
- Accessibility tests: 10% coverage
- E2E tests: 5% coverage
- Total target: 82%+ coverage
-
Unit Tests
- Individual functions and utilities
- Component rendering
- State management
-
Integration Tests
- Block registration
- Attribute persistence
- InnerBlocks integration
- Toolbar interactions
-
Accessibility Tests
- ARIA attributes
- Keyboard navigation
- Screen reader compatibility
- Focus management
-
E2E Tests
- Complete user workflows
- Multi-block interactions
- Save/load cycles
# Run all tests (when implemented)
npm test
# Run with coverage
npm run test:coverage
# Run specific test file
npm test -- hasDescription.test.ts
# Run in watch mode
npm test -- --watch- ✅ All tests pass
- ✅ TypeScript type-check passes
- ✅ Linting passes (JS and CSS)
- ✅ Code follows project conventions
- ✅ Commit messages are descriptive
- ✅ Documentation updated if needed
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
How to test these changes
## Checklist
- [ ] TypeScript passes (`npm run type-check`)
- [ ] Linting passes (`npm run lint:js && npm run lint:css`)
- [ ] Build succeeds (`npm run build`)
- [ ] Tested in WordPress editor
- [ ] Documentation updated
- [ ] Changelog updated- Automated checks: TypeScript, linting, build
- Code review: At least one maintainer approval
- Testing: Verify in WordPress environment
- Merge: Squash and merge to main branch
Never store computed values as block attributes.
Computed values like hasDescription should be derived during render using useMemo:
// ✅ CORRECT
const hasDescription = useMemo(
() => computeHasDescription(innerBlocks || []),
[innerBlocks]
);
// ❌ WRONG
const { hasDescription } = attributes;Rationale:
- Prevents useEffect feedback loops
- Ensures single source of truth
- Eliminates race conditions
- Better performance
All duplicate logic must be extracted to shared utilities.
The computeHasDescription function is used by both Edit and Save components:
// lib/hasDescription.ts
export function computeHasDescription(
innerBlocks: WPBlock[] | null | undefined
): boolean {
// Single implementation
}
// edit.tsx
import { computeHasDescription } from './lib/hasDescription';
// save.tsx
import { computeHasDescription } from './lib/hasDescription';Edit Component (edit.tsx):
- User interaction handling
- Toolbar controls
- Live preview
- Derived state computation
- InnerBlocks configuration
Save Component (save.tsx):
- Minimal logic
- Deterministic output
- Native HTML elements
- Same hasDescription computation as Edit
- Block attributes: Only store user-editable data
- Derived values: Compute during render with
useMemo - Editor-only state: Use local state or attributes not in
block.json - WordPress data: Access via
useSelecthook
All UI elements must:
- Be keyboard accessible
- Have proper ARIA attributes
- Support screen readers
- Work in high contrast mode
- Respect reduced motion preferences
- Use
useMemofor expensive computations - Minimize re-renders with proper dependencies
- Avoid inline function definitions in render
- Use CSS for animations (not JavaScript)
This project follows Semantic Versioning:
- Major (1.0.0): Breaking changes
- Minor (0.1.0): New features (backward compatible)
- Patch (0.0.1): Bug fixes (backward compatible)
- Be respectful and inclusive
- Provide constructive feedback
- Focus on what's best for the project
- Show empathy towards other contributors
- Harassment or discriminatory language
- Trolling or insulting comments
- Publishing private information
- Unprofessional conduct
- Open an issue for bugs or feature requests
- Start a discussion for questions or ideas
- Review existing issues before creating new ones
By contributing, you agree that your contributions will be licensed under the GPL-2.0-or-later license.