Skip to content
Community content. Review instructions before giving them to an AI agent — treat modules like open-source code.

WordPress Conventions

WordPress development conventions: child themes over core edits, hooks over patching, sanitize on input and escape on output, proper script/style enqueueing, universal prefixing, custom post types versus pages, and update discipline.

Mby @markdownersPublished August 21, 2026 · ~4 min read

0 downloads · Used by 0 stacks

Never modify WordPress core, a parent theme, or a third-party plugin's files directly — every customization goes through a child theme, a plugin, or a hook, because any direct edit is silently destroyed the next time that software updates.

Child themes, never core edits

  • Build all theme customization in a child theme that declares the parent via Template: in its stylesheet header — never edit a parent/purchased theme's files in place, and never edit WordPress core files under any circumstances.
  • Override a parent theme's template file by copying it into the child theme at the same relative path, not by editing the parent's copy — the child theme's copy takes precedence automatically.
  • Keep the child theme's functions.php for hooks and enqueueing, not as a dumping ground for unrelated logic — genuinely reusable functionality belongs in a plugin instead, since themes are for presentation and plugins are for functionality.

Hooks over patching

  • Extend or modify core, theme, or plugin behavior exclusively through actions and filters (add_action, add_filter) — a hook survives updates; a direct file edit does not.
  • Prefer the most specific hook available (e.g., a particular filter on a specific value) over a broad hook that requires re-deriving context (checking post type, checking current screen) to figure out whether it should act.
  • Remove a hook you no longer need with remove_action/remove_filter using the exact same priority and argument count it was added with — mismatched priority/argument count silently fails to remove it.

Sanitize on input, escape on output

  • Sanitize every piece of user or external input at the point it's saved (sanitize_text_field, sanitize_email, wp_kses_post, etc., matched to the data's expected shape) — never trust $_POST/$_GET/$_REQUEST values directly.
  • Escape every piece of dynamic data at the point it's output (esc_html, esc_attr, esc_url, esc_js, matched to the output context) — even data that was sanitized on the way in must still be escaped on the way out, because the safe encoding differs by context (HTML body vs. an HTML attribute vs. a URL).
  • Use $wpdb->prepare() (or the query-builder equivalent) for every database query that includes a variable — never interpolate a variable directly into SQL.
  • Verify a nonce (wp_verify_nonce/check_admin_referer) on every form submission and state-changing AJAX/REST request, and check the current user's capability (current_user_can) before performing a privileged action — a nonce alone proves the request came from your form, not that the user is authorized to do the action.

Enqueueing scripts and styles

  • Register and enqueue every script and style through wp_enqueue_script/wp_enqueue_style (hooked to wp_enqueue_scripts for the front end, admin_enqueue_scripts for admin) — never hard-code a <script>/<link> tag directly into a template.
  • Declare accurate dependencies (e.g., depending on the bundled jQuery handle) so WordPress loads scripts in the correct order and avoids loading a library twice under different handles.
  • Only enqueue a script/style on the specific admin screen or front-end template that needs it, using the conditional available in the enqueue hook — loading everything everywhere bloats every page load.

Prefix everything

  • Prefix every function, class, global variable, option name, hook name, and post-meta/user-meta key you define with a short, unique namespace tied to the theme/plugin — an unprefixed get_data() or a global $settings will eventually collide with core, another plugin, or the theme.
  • Prefer wrapping related functions in a class or namespace over a long list of prefixed global functions, once a plugin grows past a handful of functions.

Custom post types vs. pages

  • Use a custom post type for any content that's structurally repeated with its own fields and archive/listing needs (products, events, team members) — using regular Pages with ad hoc naming conventions for repeated structured content doesn't scale and has no proper archive/query support.
  • Use static Pages for genuinely one-off, non-repeating content (About, Contact, a landing page) — don't invent a custom post type for content that will only ever have one instance.
  • Register custom post types and taxonomies in a plugin, not a theme, whenever the content should survive a theme change — content types are data, not presentation.

Update discipline

  • Keep WordPress core, themes, and plugins updated on a schedule, and always test updates on a staging copy before applying to production — an outdated plugin with a known vulnerability is one of the most common WordPress compromise vectors.
  • Pin explicit version constraints when a customization depends on specific behavior from a third-party plugin, and revisit the pin on a schedule rather than freezing it indefinitely.
  • Remove any theme or plugin that's inactive rather than leaving it installed-but-disabled — an inactive plugin's files are still on disk and can still be a vulnerability if directly reachable.
Badge

Link back to this module from your own README.

Get it on Markdowners
[![Get it on Markdowners](https://markdowners.com/mdstack-badge.svg)](https://markdowners.com/m/markdowners/wordpress-conventions)

Comments (0)

Sign in to comment. Sign in

No comments yet. Be the first to add one.

Discussions about this module

No discussions about this module yet.

Start a discussion