wp-guidelines

WordPress Coding Standards & Conventions

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "wp-guidelines" with this command: npx skills add peixotorms/odinlayer-skills/peixotorms-odinlayer-skills-wp-guidelines

WordPress Coding Standards & Conventions

Quick-reference for WordPress PHP development. Rules are distilled from the official WordPress Coding Standards (WPCS) sniffs and WordPress core documentation.

  1. Naming Conventions

All names use snake_case for functions, variables, and properties. Classes use Pascal_Case with underscores (My_Plugin_Admin ). Hook names are all-lowercase with underscores, prefixed with your plugin slug.

Element Convention Example

Functions snake_case

acme_get_settings()

Variables snake_case

$post_title

Classes Pascal_Case (underscored) Acme_Plugin_Admin

Constants UPPER_SNAKE_CASE

ACME_VERSION

Files lowercase-hyphens

class-acme-admin.php

Hook names lowercase_underscores

acme_after_init

Post type slugs lowercase , a-z0-9_- , max 20 chars acme_book

File naming rules: All lowercase, hyphens as separators, class- prefix for single-class files.

Global prefix rule: ALL plugin/theme globals (functions, classes, constants, hooks, namespaces) must start with a unique prefix (min 4 chars). Blocked prefixes: wordpress , wp , _ , php .

Post type slugs: Max 20 chars, no reserved names (post , page , attachment , etc.), no wp_ prefix.

  1. PHP Best Practices (WordPress-Specific)

Yoda conditions: Place literals on the LEFT side of == , != , === , !== comparisons.

Strict comparisons: Always pass true as third arg to in_array() , array_search() , array_keys() .

Forbidden functions:

Function Why Alternative

extract()

Pollutes local scope unpredictably Destructure manually

@ (error suppression) Hides errors Check return values; use wp_safe_*

ini_set()

Breaks interoperability Use WP constants (WP_DEBUG , etc.)

Development-only functions (remove before shipping): var_dump , var_export , print_r , error_log , trigger_error , phpinfo , and related debug functions.

Use WordPress functions over PHP natives:

PHP Native WordPress Alternative

json_encode()

wp_json_encode()

parse_url()

wp_parse_url()

curl_*()

wp_remote_get() / wp_remote_post()

file_get_contents() (remote) wp_remote_get()

unlink()

wp_delete_file()

strip_tags()

wp_strip_all_tags()

rand() / mt_rand()

wp_rand()

file_put_contents() , fopen()

WP_Filesystem methods

Note: file_get_contents() for local files (using ABSPATH , WP_CONTENT_DIR , plugin_dir_path() ) is acceptable.

Type casts: Use short forms: (int) , (float) , (bool) , (string) . Never (integer) , (real) , or (unset) .

  1. Hooks & Actions

3.1 Registration Patterns

// Actions: side effects (send email, save data, enqueue assets) add_action( 'init', 'acme_register_post_types' ); add_action( 'wp_enqueue_scripts', 'acme_enqueue_assets' ); add_action( 'admin_menu', 'acme_add_admin_page' );

// Filters: modify and return a value add_filter( 'the_content', 'acme_append_cta' ); add_filter( 'excerpt_length', 'acme_custom_excerpt_length' );

3.2 Priority and Argument Count

// Default priority is 10, default accepted args is 1 add_filter( 'the_title', 'acme_modify_title', 10, 2 );

function acme_modify_title( $title, $post_id ) { // Always declare the correct number of parameters return $title; }

3.3 Removing Hooks

Must match the exact callback, priority, and (for objects) the same instance:

// Remove a function callback remove_action( 'wp_head', 'wp_generator' );

// Remove with matching priority remove_filter( 'the_content', 'acme_append_cta', 10 );

// Remove an object method (must be same instance) remove_action( 'init', array( $instance, 'init' ) );

3.4 Hook Naming Conventions

// Plugin hooks should be prefixed and use underscores do_action( 'acme_before_render', $context ); $value = apply_filters( 'acme_output_format', $default, $post );

// Dynamic hooks: prefix the static part do_action( "acme_process_{$type}", $data );

  1. Internationalization (i18n)

4.1 Core Functions

Function Purpose

__( $text, $domain )

Return translated string

_e( $text, $domain )

Echo translated string

_x( $text, $context, $domain )

Return with disambiguation context

_ex( $text, $context, $domain )

Echo with disambiguation context

_n( $single, $plural, $number, $domain )

Pluralization

_nx( $single, $plural, $number, $context, $domain )

Plural + context

esc_html__( $text, $domain )

Return translated + HTML-escaped

esc_html_e( $text, $domain )

Echo translated + HTML-escaped

esc_attr__( $text, $domain )

Return translated + attribute-escaped

esc_attr_e( $text, $domain )

Echo translated + attribute-escaped

esc_html_x( $text, $context, $domain )

Return translated + escaped + context

esc_attr_x( $text, $context, $domain )

Return translated + escaped + context

4.2 Rules

  • Text domain must match your plugin/theme slug exactly.

  • All user-facing strings must be wrapped in a translation function.

  • Prefer combined escape+translate over separate calls:

// BAD - separate escape and translate echo esc_html( __( 'Hello', 'acme-plugin' ) );

// GOOD - combined function echo esc_html__( 'Hello', 'acme-plugin' );

If you pass two parameters to esc_html() or esc_attr() , you probably meant esc_html__() / esc_attr__() .

4.3 Translator Comments

Add translator comments for ambiguous strings, sprintf placeholders, or context:

// BAD printf( __( '%s: %s', 'acme-plugin' ), $label, $value );

// GOOD /* translators: 1: field label, 2: field value */ printf( __( '%1$s: %2$s', 'acme-plugin' ), $label, $value );

4.4 sprintf Placeholder Rules

  • With 2+ placeholders, use ordered placeholders: %1$s , %2$s (not %s , %s ).

  • Do NOT use %1$s if there is only one placeholder (use %s ).

  • The number of placeholders must match the number of arguments.

  1. Enqueuing Assets

5.1 Never Use Direct Tags

// BAD - direct output echo '<script src="my-script.js"></script>'; echo '<link rel="stylesheet" href="my-style.css">';

// GOOD - proper enqueue function acme_enqueue_assets() { wp_enqueue_script( 'acme-main', plugin_dir_url( FILE ) . 'js/main.js', array( 'jquery' ), '1.2.0', true // in_footer ); wp_enqueue_style( 'acme-styles', plugin_dir_url( FILE ) . 'css/styles.css', array(), '1.2.0' ); } add_action( 'wp_enqueue_scripts', 'acme_enqueue_assets' );

5.2 Required Parameters

Parameter Required? Notes

$handle

Yes Unique identifier

$src

Conditional Omit only when registering dependency-only handle

$deps

Recommended Array of dependency handles

$ver

Yes (when src given) Must be non-false; use explicit version string. false = WP core version (bad for cache busting). null = no version query string (also discouraged).

$in_footer (scripts) Yes Explicitly set true (footer) or false (header). Defaults to header if omitted.

$media (styles) Optional Default 'all'

// BAD - missing version, missing in_footer wp_enqueue_script( 'acme-main', $url );

// GOOD wp_enqueue_script( 'acme-main', $url, array(), '1.0.0', true );

5.3 Conditional Loading

Load assets only where needed:

function acme_admin_assets( $hook ) { if ( 'toplevel_page_acme-settings' !== $hook ) { return; } wp_enqueue_style( 'acme-admin', ... ); } add_action( 'admin_enqueue_scripts', 'acme_admin_assets' );

function acme_frontend_assets() { if ( ! is_singular( 'acme_portfolio' ) ) { return; } wp_enqueue_script( 'acme-portfolio', ... ); } add_action( 'wp_enqueue_scripts', 'acme_frontend_assets' );

  1. WordPress API Usage

Key rules for WordPress API calls. Use capabilities (not roles) in current_user_can() . Cron intervals must be 15+ minutes. Limit posts_per_page (no -1 ). Never overwrite WP globals ($post , $wp_query ). Always pass $single to get_post_meta() . Avoid current_time( 'timestamp' ) -- use time() for UTC or current_time( 'mysql' ) for formatted local time.

Common capabilities: manage_options , edit_posts , edit_others_posts , publish_posts , delete_posts , upload_files , edit_theme_options , activate_plugins .

get_post_meta() $single applies to: get_post_meta , get_user_meta , get_term_meta , get_comment_meta , get_site_meta , get_metadata , get_metadata_raw , get_metadata_default .

  1. Deprecated Functions (Common Replacements)

Common deprecated functions and their replacements. WPCS flags usage as an error if the function was deprecated before your configured minimum WP version, and a warning otherwise.

Deprecated Since Replacement

get_currentuserinfo()

4.5 wp_get_current_user()

get_page_by_title()

6.2 WP_Query

is_taxonomy()

3.0 taxonomy_exists()

is_term()

3.0 term_exists()

get_settings()

2.1 get_option()

get_usermeta()

3.0 get_user_meta()

update_usermeta()

3.0 update_user_meta()

delete_usermeta()

3.0 delete_user_meta()

wp_get_sites()

4.6 get_sites()

like_escape()

4.0 $wpdb->esc_like()

get_all_category_ids()

4.0 get_terms()

post_permalink()

4.4 get_permalink()

force_ssl_login()

4.4 force_ssl_admin()

wp_no_robots()

5.7 wp_robots_no_robots()

wp_make_content_images_responsive()

5.5 wp_filter_content_tags()

add_option_whitelist()

5.5 add_allowed_options()

remove_option_whitelist()

5.5 remove_allowed_options()

wp_get_loading_attr_default()

6.3 wp_get_loading_optimization_attributes()

the_meta()

6.0.2 get_post_meta()

readonly()

5.9 wp_readonly()

attribute_escape()

2.8 esc_attr()

wp_specialchars()

2.8 esc_html()

js_escape()

2.8 esc_js()

clean_url()

3.0 esc_url()

seems_utf8()

6.9 wp_is_valid_utf8()

current_user_can_for_blog()

6.7 current_user_can_for_site()

  1. Formatting

Spacing: WordPress uses spaces inside parentheses, brackets, and around operators. Control structures always have spaces after keywords and inside parens: if ( $x ) , foreach ( $arr as $v ) .

Indentation: Use tabs, not spaces. Multi-line arrays: one item per line, trailing comma.

Operator spacing: Spaces around = , + , . , => , etc. No spaces around -> or ?-> .

Cast spacing: Space after cast, no space inside: (int) $val .

  1. Testing

PHP: Use PHPUnit with WP_UnitTestCase . Install via composer require --dev phpunit/phpunit or wp scaffold plugin-tests . Test files in tests/ , named test-class-{name}.php .

JavaScript: Use @wordpress/scripts (bundles Jest): npx wp-scripts test-unit-js . E2E via @wordpress/e2e-test-utils .

Linting: vendor/bin/phpcs --standard=WordPress src/ for PHP. npx wp-scripts lint-js and npx wp-scripts lint-style for JS/CSS.

  1. Quick Reference Tables

Control Structure Spacing

Pattern BAD GOOD

if if($x)

if ( $x )

elseif elseif($x)

elseif ( $x )

foreach foreach($a as $b)

foreach ( $a as $b )

for for($i=0;$i<10;$i++)

for ( $i = 0; $i < 10; $i++ )

switch switch($x)

switch ( $x )

while while($x)

while ( $x )

Naming Quick Reference

Element Convention Example

Functions snake_case

acme_get_settings()

Variables snake_case

$post_title

Classes Pascal_Case (underscored) Acme_Plugin_Admin

Constants UPPER_SNAKE_CASE

ACME_VERSION

Files lowercase-hyphens

class-acme-admin.php

Hook names lowercase_underscores

acme_after_init

Post type slugs lowercase , a-z0-9_-

acme_book

WordPress i18n Functions at a Glance

Need Function

Return translated string __()

Echo translated string _e()

Return + HTML escape esc_html__()

Echo + HTML escape esc_html_e()

Return + attr escape esc_attr__()

Echo + attr escape esc_attr_e()

With context _x() , esc_html_x() , esc_attr_x()

Singular/plural _n()

Singular/plural + context _nx()

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

elementor-themes

No summary provided by upstream source.

Repository SourceNeeds Review
General

elementor-controls

No summary provided by upstream source.

Repository SourceNeeds Review
General

elementor-forms

No summary provided by upstream source.

Repository SourceNeeds Review
General

flyonui

No summary provided by upstream source.

Repository SourceNeeds Review