Use a site-specific plugin for business behavior that should survive a theme change. Use a child theme's functions.php for behavior tied to that theme's presentation. The number of lines is not the deciding factor: a ten-line pricing rule can be more business-critical than a long style customization.
Examples of site behavior include custom content types, CRM routing, order metadata, and an integration endpoint. Theme behavior includes loading that theme's styles or adjusting a template-specific display. Review dependencies before moving code; a snippet can depend on both a theme and another plugin.
Compare the Maintenance Consequences
| Location |
Good fit |
Main question |
| Child theme |
Theme-specific presentation |
Should this disappear when the theme changes? |
| Site-specific plugin |
Persistent business rules |
Who versions, tests, and deploys it? |
| Snippet manager |
Small, controlled customizations |
Can the active version be exported and recovered? |
| Must-use plugin |
Required platform behavior |
Is automatic loading intentional and documented? |
The WordPress theme-functions guide explains the active-theme context. The plugin basics guide describes a separate plugin's structure and hooks. Neither location removes the need for secure input handling and capability checks.
Audit What the Existing Snippet Really Does
Find its function names, hook registrations, dependencies, saved options, scheduled jobs, and any external requests. Record whether it executes in the admin, on public pages, through REST, or in background processing.
For example, a form-to-CRM snippet may appear to run only on submission, yet also register a retry job. Moving only the submission callback leaves the retry path behind. A custom post type registration belongs to the site's content model, while a special display template may remain in the theme.
Use the feature-request brief to state which behavior must remain unchanged. A refactor is easier to review when the acceptance test names an actual record or user action.
Verification record for Custom WordPress Plugin or functions.php? Put Site Logic in the Right Place. Fill in your own evidence.
Move One Responsibility at a Time
Create a versioned plugin in staging, with a clear name and maintainer. Keep secrets in the established configuration mechanism rather than packaging them in source files. Follow the project's dependency-loading conventions and handle missing dependencies without causing a fatal error.
Disable the old hook registration as part of the same controlled deployment that enables the new one. Leaving both copies active can send two CRM requests, apply a price adjustment twice, or raise a duplicate-function error. Renaming the function alone does not prevent duplicate business effects.
Avoid changing output, credentials, and storage schema during the move unless necessary. This makes it possible to distinguish a packaging mistake from a deliberate feature change.
Test the Lifecycle, Not Just Activation
Verify the original workflow, an unauthorized user, a missing dependency, a background invocation, and a theme switch when theme independence is the purpose. Confirm deactivation behavior. Deactivating a plugin should not silently erase important business data; deletion and uninstall behavior require an explicit policy.
Keep the previous source version and recovery access available. If an edit already caused a syntax failure, follow the functions.php parse-error recovery guide before undertaking a larger migration.
The final deliverable is maintained code with an owner and a repeatable test, not simply another entry in the plugin list. HandL WP can help isolate and relocate custom behavior when a theme update or redesign puts that behavior at risk.
References checked September 29, 2026. Diagrams and examples are explanatory, not measured customer results.