Open any WordPress theme folder over FTP and, next to style.css and index.php, there’s a file called functions.php. It looks unremarkable: a few hundred lines of PHP, sometimes fewer. Ask around and you’ll get two very different reactions to it: “that’s where you add code” from one camp, and “isn’t that the file that breaks sites” from the other. Both are describing the same file correctly.
functions.php runs on every single request to your site, before most of the page has been assembled. It isn’t a config file WordPress merely reads. It’s live PHP, executed with the same access to hooks, options, and the database as any plugin. That’s what makes it genuinely useful for small customizations, and it’s exactly why a single missing semicolon in it can take the whole site down.
Most people meet the file the same way: a forum post or an old tutorial has a snippet that promises to fix something, they paste it in through the wp-admin theme editor, click “Update File,” and refresh the homepage to see what happens. Sometimes it works. Sometimes the page is just white.
What functions.php actually is
So, what is functions.php? Every WordPress theme is allowed to ship one: a single functions.php file in its root folder. WordPress looks for it automatically (there’s no setting to enable, no special naming beyond that exact filename), and if it’s present, WordPress loads it on every request, right after plugins have loaded and well before the template files (header.php, index.php, and so on) render any markup.
Functionally, it behaves like a plugin that’s scoped to your theme. You can register hooks with add_action() and add_filter(), define helper functions, enqueue scripts and styles, register custom image sizes, adjust admin behavior: anything a plugin can do, provided it doesn’t need to work independently of the theme. WordPress core itself treats it that way: inside wp-settings.php, core does a plain include of the active theme’s functions.php early in the request, alongside the rest of theme setup, not lazily loaded when a particular template part needs it.
That “runs on every request, before rendering starts” detail matters practically. Because it executes so early, it’s the right place to register things WordPress needs to know about before the page starts building: image sizes, theme support flags, menu locations, widget areas. It’s the wrong place to try to output HTML directly; there’s no guarantee the page structure you’re expecting has been decided yet.
The mistake almost everyone makes with it
Here’s the misconception that causes the most lost work: functions.php belongs to the theme, not to the site. It is theme code, stored inside the theme’s own folder, and WordPress treats it exactly like the rest of the theme’s files.
Two ordinary events erase everything in it. Switch to a different theme, and the new theme’s functions.php takes over. The old one, and every custom function you wrote into it, simply stops loading. Update the theme through wp-admin, and if the update ships a new functions.php (which it usually does), your edits get overwritten along with it, because the update process replaces theme files wholesale. Neither of these is a bug. It’s the file doing exactly what it’s supposed to do. It just isn’t supposed to be a permanent home for anything.
This is why the advice you’ll see repeated everywhere (“don’t edit the parent theme’s functions.php directly”) isn’t caution for its own sake. If a customization needs to survive a theme change or a theme update, it needs to live somewhere WordPress won’t touch during either of those events. There are two reasonable places for that:
- A small, dedicated plugin. Even a single-file plugin with nothing but a plugin header comment and your functions in it survives theme switches and theme updates untouched, because plugins and themes are managed completely separately.
- A child theme’s
functions.php. This is the more approachable option for anyone not ready to write a plugin: a child theme has its ownfunctions.php, it survives updates to the parent theme, and WordPress loads the child’s file in addition to (not instead of) the parent’s.
The parent theme’s own functions.php is still worth understanding and reading (it’s where you’ll find out what image sizes, menus, and theme supports are already registered), but treat direct edits to it as temporary, disposable, and gone the moment the theme changes underneath you.
Editing it without taking the site down
The built-in Theme File Editor under Appearance in wp-admin will let you edit functions.php directly in the browser and save it with one click. On a live site, don’t use it. There’s no draft state, no syntax check before saving, and no confirmation step. The file is overwritten the instant you click “Update File,” and if there’s a mistake in what you typed, that broken version is what every visitor gets on the very next page load.
A safer workflow costs almost nothing extra:
- Edit the file over FTP/SFTP, or better, in a local copy under version control, rather than through the live admin editor.
- Before you save anything, copy the current, working version of the file somewhere safe. A dated copy in a local folder is enough: the point is having something to restore in under a minute if the new version breaks.
- Make one change at a time and check the site before making the next one. It’s far easier to spot which five-line addition broke things than to untangle fifty new lines at once.
- If you’re not on a child theme or a plugin, treat the edit as temporary, and plan to move it there once you’ve confirmed it works.
PHP is unforgiving about syntax. A missing semicolon, an unclosed brace, a stray quotation mark: any one of those is enough for PHP to refuse to parse the file at all, and because functions.php loads before the rest of the page, that parse failure takes the entire site down with it. That’s the white screen of death most WordPress site owners eventually run into: one syntax error in a theme file, and every page on the site (front end and often wp-admin too) goes blank. Having a backup of the previous file ready is what turns that from a support ticket into a thirty-second fix: re-upload the last working copy over FTP and the site comes straight back.
Snippets people actually paste into this file
Almost everything that belongs in functions.php follows the same shape: hook a function onto an action or filter, and let WordPress call it at the right moment. Code sitting at the top level of the file, outside any function, runs immediately when the file loads (before WordPress has finished setting things up), which is how a lot of “this snippet doesn’t work” reports start. Wrapping each piece in its proper hook avoids that. A few small, commonly searched-for examples below are safe to paste into a child theme’s functions.php as-is.
Register a custom image size. Image sizes need to be registered before WordPress finishes setting up the theme, which is exactly what the after_setup_theme hook is for, the same mechanism covered in more depth in our guide to WordPress image sizes:
add_action( 'after_setup_theme', 'wpie_register_image_sizes' );
function wpie_register_image_sizes() {
// Drop a default size you don't use.
remove_image_size( 'medium_large' );
// Add one sized for your own layout.
add_image_size( 'card-thumbnail', 400, 300, true );
}
Turn off the emoji scripts. WordPress loads a small script and inline styles on every page so older browsers can render emoji consistently. Most current browsers don’t need it, and removing it trims a request and a bit of inline CSS from every page load:
add_action( 'init', 'wpie_disable_emojis' );
function wpie_disable_emojis() {
remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
remove_action( 'wp_print_styles', 'print_emoji_styles' );
remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
remove_action( 'admin_print_styles', 'print_emoji_styles' );
}
Change how long excerpts are. The default auto-generated excerpt cuts off at 55 words, which is often shorter than site owners want on an archive page. The excerpt_length filter controls it:
add_filter( 'excerpt_length', 'wpie_custom_excerpt_length' );
function wpie_custom_excerpt_length( $length ) {
return 40;
}
Hide the WordPress version number. By default, WordPress prints its version in a meta tag in the page’s <head>. It’s a minor detail, but it’s also free information for anyone scanning your site for a known vulnerability in an outdated version, so most security checklists recommend removing it:
add_action( 'init', 'wpie_hide_generator_tag' );
function wpie_hide_generator_tag() {
remove_action( 'wp_head', 'wp_generator' );
}
Notice the pattern repeats: an add_action() or add_filter() call naming a hook, and a function that does the actual work, defined separately rather than inline. That structure is also what makes these safe to move into a plugin or a child theme later without rewriting anything: the function bodies don’t change, only where the file that contains them lives.
Before you paste anything into that file, it is worth having the snippet read by something that knows what breaks a site.
Paste it below. The checker looks for the things that take the site down immediately, whitespace before the opening tag, an unbalanced brace, a stray closing tag, and the ones that bite later, a function without a prefix, a hook name that does not exist, a filter that forgets to return. It reads the text, it never runs it.
functions.php snippet checker
Paste the snippet you are about to drop into functions.php and see what would break before the server sees it. The code is read as text and never run, nothing is uploaded, and nothing leaves this browser tab.
A snippet in functions.php is gone the day the theme is switched, and an error in it takes the whole site down, dashboard included. The same code in a small plugin survives a theme change, can be switched off from the plugin screen, and can be disabled by renaming its folder over FTP when the site is already white. Save the file below as wp-content/plugins/site-snippets/site-snippets.php and activate it.
The lists of hook names and core function names behind these checks are deliberately short: they hold the common ones, not all of them. A name that is not in the list is not wrong by that fact alone, and a hook name with a typo in it never raises an error, it just means the callback is never called.
When functions.php is the wrong tool
Not everything that could go in functions.php should. A few signs it’s time to reach for a plugin instead:
- It needs to survive a theme change. If losing the customization the day you switch themes would be a problem, it doesn’t belong in theme code at all, parent or child.
- It’s growing its own settings. The moment a snippet needs an admin page, options stored in the database, or configuration a non-developer should be able to change, it has outgrown a theme file and become a small plugin, whether or not you’re calling it one yet.
- You’ll want it on more than one site. A plugin can be zipped up and installed anywhere. Code buried in one theme’s
functions.phphas to be copied and adapted by hand every time.
The rule of thumb: functionality belongs in a plugin, presentation belongs in the theme. Registering an image size or trimming the excerpt length is closely tied to how this particular theme displays content, so a theme file is a defensible home for it. A custom post type, a shortcode, or anything with its own settings screen is functionality the site depends on regardless of which theme is active, and it should be packaged accordingly.
When something looks wrong
The site went white right after you saved an edit. This is almost always a PHP parse error in the file you just changed: a missing semicolon, an extra or missing closing brace, an unmatched quote. Restore the backup copy of functions.php over FTP and the site comes back immediately; then reapply the change more carefully, ideally testing it locally first.
A customization that worked for months is suddenly gone. Check whether the theme was recently updated or switched. Both operations replace theme files, including functions.php, which is why anything meant to be permanent needs to live in a plugin or a child theme rather than the active parent theme.
A fatal error mentions a function that “cannot be redeclared.” Somewhere, the same function name has been defined twice, often because a snippet got pasted into functions.php a second time, or the same function exists in both a parent and child theme. PHP won’t allow two functions with identical names in the same request, so one copy has to be removed or renamed.
A newly added image size doesn’t show up anywhere. Registering a size with add_image_size() only affects images uploaded from that point forward. Photos already in the media library need their thumbnails regenerated before the new size exists for them, which is normal WordPress behavior rather than anything wrong with the snippet.
Where this leaves you
functions.php is neither the dangerous file its reputation suggests nor the all-purpose settings panel some tutorials treat it as. It’s ordinary PHP, loaded early, on every request, with theme-level scope: useful for exactly the things that are genuinely tied to how the active theme presents content, and a liability for anything you’d be upset to lose.
The habits that keep it safe are small: edit outside the live admin editor, keep a backup before every save, change one thing at a time, and ask honestly whether what you’re adding is theme presentation or site functionality before deciding where it goes. None of that requires being a developer. It just requires treating a file that runs on every page load with the seriousness that implies.
Get that much right, and functions.php stops being a file people warn each other about and becomes what it was always meant to be: a small, ordinary place to tell your theme how to behave.