You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Modern WordPress Full-Site Development Best Practices
Dependencies & Build Tools
Use modern PHP & Node: Develop with PHP 8.2+ and Node (for build scripts), to leverage latest features and performance . Add declare(strict_types=1); at the top of PHP files to enforce strict typing (catching type errors early).
Composer for autoloading: Manage PHP libraries with Composer and use PSR-4 autoloading to load classes automatically (avoids manual require_once calls)
Keep your plugin/theme’s custom classes under a namespace and let Composer handle loading them.
Leverage WP-CLI scaffolding: Use official tools like wp create-block (or npx @wordpress/create-block) to scaffold block plugins. It generates all necessary PHP, JS, and CSS files plus a no-config build setup .
Use @wordpress/scripts: Rely on the wp-scripts build tool (part of @wordpress/scripts) for bundling and transpiling modern JS. It comes pre-configured with webpack and Babel for ES6+ and JSX, so you can write modern JS/React without custom config  .
Zero-config env with wp-env: Utilize wp-env to spin up a local WordPress instance in Docker with one command
This ensures a consistent dev environment for themes/plugins and can be shared with collaborators via project config.
Theme Development (Block Themes)
Adhere to block theme structure: Organize block themes using the standard folders. Include a templates/ folder for full-page templates (e.g. index.html, single.html) and a parts/ folder for reusable partials (e.g. header.html, footer.html) . Block themes use HTML files and theme.json instead of PHP templates .
Minimal required files: Every block theme must have a style.css (with theme header comments) and an index.html template in the templates directory. (Unlike classic themes, an index.php is not required for block themes in WP 6.0+.)
Use theme.json for style & settings: Define global styles, custom palettes, font sizes, layout spacing, etc., in theme.json. This file is the “heartbeat” of a block theme, controlling core style output and features . The core will inline only the CSS needed for blocks used, making themes more performant .
Template parts and patterns: Implement repeated sections (header, footer, sidebar) as template parts, and include them with Template Part blocks (e.g. <!-- wp:template-part {"slug":"header"} /-->).
Use Block Patterns (pre-defined block layouts) as needed to provide reusable design sections in the theme.
No PHP in templates: Keep presentation in HTML templates and global styles in theme.json. If dynamic behavior is needed, use blocks with render_callback (dynamic blocks) rather than custom PHP template logic. This ensures compatibility with Full Site Editing and clean separation of concerns.
Plugin Development Architecture
Modular structure: Organize plugin code into logical modules or classes instead of one giant file. For large plugins, use OOP – e.g. a main plugin class that initializes components, separate classes/files for admin logic, front-end logic, etc.
For smaller plugins, at least group related functions in an includes/ folder.
Folder conventions: Follow a clear folder structure to separate concerns. For example:
Load conditionally: Only load code when needed. For instance, wrap admin-only code in an if ( is_admin() ) check so it runs only in the dashboard. Similarly, only enqueue admin scripts on admin pages and front-end scripts on the front-end.
Avoid globals & name collisions: Encapsulate functionality in classes or namespaces, or prefix your function names, class names, and options to avoid conflicts. e.g. use a unique 3-5 letter prefix (or vendor namespace) for all identifiers to prevent clashing with other plugins.
Hooks for integration: Use WordPress Hooks API extensively. Attach plugin logic to appropriate actions and filters (e.g. init, admin_menu, the_content) rather than altering core files. This makes your code execute at the right time and remain override-safe. Remove or adjust hooks via remove_action/remove_filter in edge cases rather than hacking core behavior.
PHP Best Practices
Modern syntax and features: Take advantage of modern PHP features (supported in 8.x) – e.g. type declarations, return types, nullable types, short closures. These improve code clarity and reliability now that WordPress supports PHP 7.4+ (and higher in many environments)  .
Namespaces and scope: Wrap plugin classes/functions in a PHP namespace (e.g. MyPlugin\Utils) to organize code and prevent collisions . Use use statements to import WP core classes or other classes for clarity. This makes code more modular and autoload-friendly.
PSR-12 coding style: Follow PSR-12 coding standards for consistent code style (4-space indent, braces on new lines, etc.), which aligns with modern PHP community practices. WordPress-core PHP code has its own historic style, but your custom code can use PSR-12 since plugins/themes are not required to stick to WP core’s legacy style.
Error handling and testing: Check for environment compatibility (e.g. required PHP version using Requires PHP header or a runtime check) to avoid “white screen” errors on older setups . Implement error handling (try/catch around risky operations) and consider writing unit tests for critical plugin components if possible. Use WP debug tools (WP_DEBUG, error_log) during development to catch issues early.
JavaScript & Block Development
ES6+ and modules: Write JS using modern ES6+ syntax (arrow functions, const/let, template literals) and organize code into modules. Import WordPress-provided packages (e.g. import { registerBlockType } from '@wordpress/blocks';) instead of using global variables, so your code is clearer and avoids global scope issues.
JSX and React for blocks: Use JSX syntax and React components for building Gutenberg blocks. The block editor environment provides React (via wp.element), so you can create interactive block interfaces in the editor. Example: <InspectorControls><PanelBody title="Settings">… in your block’s edit function, to add custom controls.
Transpile and bundle: Since browsers don’t natively support JSX/ESNext, use build tools to transpile. Running wp-scripts build will compile your src/ JavaScript (with JSX) into browser-ready code . Keep source files (JS/JSX, SCSS) in a /src folder and the generated build in /build (this is the default setup from wp-scripts) .
Use WP Block APIs: Register blocks using the Block API. Define a block.json file for each block with its metadata (name, category, editor script, style, etc.), and call register_block_type() in PHP to load that JSON on init. This ensures your block is registered on server and client, enabling features like server-side rendering, theme.json support, and block variations .
Dynamic blocks: For blocks that display dynamic or server-derived content (latest posts, forms, etc.), use a render callback in PHP. In block.json, set "render" to a PHP function or provide 'render_callback' when calling register_block_type. This function should sanitize and output the block’s HTML at runtime. Keep block PHP logic minimal—fetch data and markup it, while styling is done via editor/frontend CSS.
WP data & state: When building richer applications in the editor or front-end, leverage WordPress’ data stores (via @wordpress/data) instead of custom global state. For example, use wp.data.select('core').getEntityRecords() to fetch posts in JS, or wp.data.dispatch('core/editor') to interact with editor state. This aligns with core and avoids reinventing state management.
Security
Never trust user input: Always assume data coming from users (or external sources) is malicious until proven safe. Validate inputs for type/range (e.g. use is_email(), is_numeric()) and only accept expected values (whitelist).
Sanitize on save: Clean all data before saving to the database. Use WordPress sanitization functions like sanitize_text_field(), sanitize_email(), sanitize_file_name() as appropriate . This strips out or neutralizes harmful code (tags, scripts) from user-submitted content.
Escape on output: Escape data as late as possible – i.e. when outputting to HTML – to prevent XSS attacks
Use contextual escaping functions: esc_html() for plain text, esc_attr() for attributes, esc_url() for URLs, etc. This ensures any remaining special characters are rendered as text, not executed.
Use nonces and capability checks: Protect forms and AJAX actions with nonces ( wp_nonce_field() in forms and check_admin_referer() or wp_verify_nonce() in processing code ) to prevent CSRF
Always verify the user’s capabilities (e.g. current_user_can('edit_posts')) before performing sensitive operations. This ensures only authorized users can perform certain actions.
Avoid direct file access: Prevent direct access to PHP files by exiting if ! defined('ABSPATH') at top of your scripts
This is a simple precaution to ensure your plugin/theme PHP files aren’t executed in isolation by an attacker.
Keep dependencies updated: Regularly update your plugins, themes, and third-party libraries to patch known vulnerabilities
Remove any code dependencies you don’t need. Security is an ongoing process – stay vigilant with updates and testing.
Internationalization & Accessibility
Internationalize all strings: Wrap all user-facing text in translation functions and include a text domain. Use __() for returning translated strings and _e() for echoing them . For example: __('Hello World', 'my-textdomain'). The text domain should be unique to your theme/plugin (usually its slug) and declared in the plugin header or theme’s style.css. Load the text domain in PHP (using load_theme_textdomain or load_plugin_textdomain) so translations files are recognized.
RTL and locale support: When applicable, include RTL styles (e.g. a rtl.css or use logical properties in CSS) to support right-to-left languages. Use WordPress functions like n() for plural forms and esc_html/esc_attr__ to combine internationalization with escaping. Always provide a text domain in every translation function call; missing text domains lead to untranslated strings .
Follow accessibility standards: Build with accessibility (a11y) in mind from the start. Use semantic HTML5 elements (landmarks like , , ) and add ARIA roles/attributes only when necessary to clarify structure . Ensure proper heading hierarchy (one H1 per page, nested subsections with H2, H3, etc.) to aid screen reader navigation .
Alt text and labels: Provide descriptive alt text for images and labels for form fields. Every image that conveys information should have an appropriate alt attribute (e.g. <img src="..." alt="A smiling woman holding a coffee cup">) . Form inputs should have corresponding <label> tags or aria-label attributes for screen readers.
Keyboard navigation: Test that all interactive components (menus, dialogs, sliders, etc.) are usable via keyboard alone . This means focusable elements (links, buttons, form fields) should be reachable with Tab, and UI controls should display a visible focus state. Implement “skip to content” links for bypassing large menus, and ensure no action requires a mouse.
Color and contrast: Use sufficient color contrast for text and UI elements to support users with low vision. Follow WCAG guidelines (e.g. 4.5:1 contrast ratio for body text) . Don’t rely on color alone to convey meaning (e.g. also use icons or text labels) so that colorblind users can understand all information. Where possible, test your theme with tools like WAVE or Axe to catch a11y issues.
Coding Standards & Quality
Consistent PHP style: Adhere to a consistent coding style for PHP. If following WordPress PHP Coding Standards, use spaces, naming conventions, and formatting as outlined in the WP Handbook. If you opt for PSR-12, be consistent: e.g. 4-space indent, lowercase keywords, CamelCase class names, underscore_separated function names (or camelCase if you prefer)  . Use a linter (PHP_CodeSniffer with WordPress Coding Standards ruleset or PHP-CS-Fixer for PSR-12) to automatically detect issues.
Consistent JS style: Follow the official WP JavaScript standards (which are largely based on ESLint and Prettier defaults). For Gutenberg/React code, use camelCase for variables and functions, PascalCase for React components, and single quotes for strings (except when using template literals). Run wp-scripts format or an ESLint config with the WordPress rules to keep code style uniform.
Document and comment: Write clear inline documentation for complex code. Use PHPDoc blocks for functions and classes (describe parameters, return types, and purpose). In JS, use JSDoc/TSDoc comments for functions and important sections. This not only helps others (and future you) understand the code, but also aids IDEs in providing autocomplete and type hints.
Version control and testing: Maintain your theme/plugin in version control (e.g. Git) and use meaningful commit messages. Follow semantic versioning for releases. Test your code in different environments (multiple PHP versions, WordPress versions) and consider using tools like PHPUnit for PHP unit tests or Jest for JS, especially for mission-critical code. Quality assurance and coding standards go hand-in-hand to produce reliable, maintainable WordPress projects.