Themes versus plugins: where code belongs

Decide whether code belongs in a theme, a plugin or a must-use plugin, so content and features survive a redesign.

  • Intermediate
  • 6 min read
  • Updated 17 Oct 2026

What you will learn

  • Choose theme or plugin for a feature
  • Explain must-use plugins
  • Recognise theme lock-in and avoid it

Before you start

WordPress lets you put PHP in a theme's functions.php, in a plugin or in a must-use plugin, and all three run in the same process. The code works wherever you put it. The question is what happens later, when the theme changes, a plugin is deactivated or another developer takes over. This lesson gives you a rule that answers that question every time.

The rule

Ask one question about each feature:

If the site switched to a different theme tomorrow, should this keep working?

  • Yes: it belongs in a plugin.
  • No, it is only about how this theme looks: it belongs in the theme.

Themes are for presentation. Plugins are for functionality and data.

Why it matters: theme lock-in

Imagine a theme that registers a "Projects" post type in its functions.php. The client adds 200 projects. Two years later they redesign and activate a new theme. The post type is no longer registered, so:

  • The Projects menu vanishes from the admin.
  • Every project URL returns a 404.
  • The 200 projects are still in the database, but nothing can display or edit them.

The content is effectively held hostage by the old theme. This is theme lock-in, and it is one of the most common problems agencies inherit. Had the post type lived in a plugin, the redesign would only have needed new templates.

The same applies to shortcodes. A shortcode registered by a theme leaves raw text such as [team_members] in every post once the theme is gone.

What goes where

FeatureLocationWhy
Custom post types and taxonomiesPluginContent must survive a redesign
Custom fields and meta registrationPluginData, not presentation
Shortcodes and custom blocks used in contentPluginContent depends on them
REST API endpointsPluginOther systems depend on them
Integrations (CRM, payments, email)PluginBusiness logic
Scheduled tasksPluginBehaviour, not display
Templates and template partsThemePure presentation
Styles, fonts, colour palettes, theme.jsonThemePure presentation
Registering menu locations and image sizes used only by the theme's layoutThemeTied to the design
add_theme_support() callsThemeThey describe what the theme supports
Block patterns that only make sense with this designThemeTied to the design

Some items sit in between. Image sizes are a good example: if content editors pick from them, they may belong in a plugin so their names do not disappear. When in doubt, ask the rule again.

Plugins: the default home for code

A plugin is a folder in wp-content/plugins with a main file that has a header comment. You created one in the setup lesson. Plugins have useful properties that theme code does not:

  • They can be activated and deactivated independently.
  • They have activation, deactivation and uninstall hooks, so they can set up and clean up.
  • Several can be active at once, so features stay separate.
  • They can be reused on other sites.

For a client site, it is normal to have one "site plugin" that holds all custom functionality for that site, alongside any general-purpose plugins.

Themes: presentation only

A theme can still contain PHP. Classic themes use PHP templates, and both classic and block themes can have a functions.php. Keep it focused on the theme itself:

PHP
// wp-content/themes/mytheme/functions.php
add_action( 'after_setup_theme', 'mytheme_setup' );

function mytheme_setup() {
    add_theme_support( 'post-thumbnails' );
    add_theme_support( 'title-tag' );

    register_nav_menus(
        array(
            'primary' => __( 'Primary menu', 'mytheme' ),
        )
    );
}

Everything in this function describes what the theme can display. None of it creates content.

Child themes

If you need to change a theme you did not write, do not edit it: updates overwrite your changes. Create a child theme instead. A child theme is a folder with its own style.css whose header names a parent with Template:. WordPress uses the child's files first and falls back to the parent's. Child themes are for presentation changes too. Functionality still belongs in a plugin.

Must-use plugins

A must-use plugin is a PHP file placed directly in wp-content/mu-plugins. They differ from normal plugins:

Normal pluginMust-use plugin
ActivationActivated in the adminAlways on, no activation
Can be deactivated by an adminYesNo, only by removing the file
Load orderAfter must-use pluginsFirst, before normal plugins
SubfoldersLoaded from its own folderOnly PHP files directly in mu-plugins load automatically
Activation and deactivation hooksYesNo
Updates from WordPress.orgYesNo

Use must-use plugins for code that must never be switched off by accident:

  • Security rules, such as disabling XML-RPC or blocking user enumeration.
  • Environment-specific settings, such as forcing a mail server on staging.
  • Code other plugins depend on, which must load first.
  • Agency or host-level code across many client sites.

Because only top-level files load, a common pattern is a small loader file in mu-plugins that requires the main file of a plugin folder inside it.

Must-use plugins are easy to forget because they do not appear in the normal plugin list. They show under a separate "Must-Use" tab on the Plugins screen. Document them in the project's README.

Do not paste code into functions.php

Tutorials often say "add this to your theme's functions.php". For a two-line presentation tweak, that is fine. For anything that creates content, changes data or integrates with other systems, put it in a plugin, even if the snippet is short. The few minutes it takes to create a plugin file saves a broken site after the next redesign.

Decision checklist

Before writing a feature, run through these questions:

  1. Does it create or change content or data? Use a plugin.
  2. Will other systems or other sites depend on it? Use a plugin.
  3. Must it always run, even if an admin deactivates plugins? Use a must-use plugin.
  4. Is it only about this design's layout and styles? Use the theme.
  5. Is the theme someone else's? Use a child theme for presentation, a plugin for the rest.

Summary

  • Themes handle presentation; plugins handle functionality and data.
  • Ask whether the feature should survive a theme change. If yes, use a plugin.
  • Post types, taxonomies, shortcodes, endpoints and integrations in a theme cause theme lock-in.
  • Must-use plugins always run, load first and cannot be deactivated from the admin.
  • Change third-party themes with a child theme, never by editing them.

In the next module you will learn hooks, the mechanism that every plugin and theme uses to change WordPress.

Further reading