WordPress Development
WordPress 7.0 PHP-Only Blocks vs Code Snippets: Which Should You Use?
WordPress 7.0 shipped PHP-only block registration — no React, no build step. That does not retire snippet plugins. Here is how to choose the right container.
May 21, 2026 4 min read Mark Ashton
- wordpress
- php
- news
- workflow
WordPress 7.0 "Armstrong" shipped on 20 May 2026 with something snippet authors have wanted for years: PHP-only block registration. You can register a simple, server-rendered block with register_block_type(), set supports.autoRegister to true, provide a render_callback, and skip npm, webpack, and React. Gutenberg 22.3+ had the same path during the beta.
The Make WordPress Core note from 3 March 2026 is the canonical write-up. Inspector controls generate for string, integer, boolean, and enum attributes. Use get_block_wrapper_attributes(). Do not expect inner blocks or a custom editor UI. The feature was marked experimental in 7.0, which means the API can still move.
This is a genuine workflow change. It is also being over-read as "you do not need snippet plugins anymore." Those are different objects.
What a PHP-only block is for
A block is something an editor inserts on a page. The new API is for dynamic, server-rendered pieces of UI: a pricing card that reads a custom field, a small WooCommerce grid, a "related products" strip, a shortcode you are finally retiring.
If the job is "the editor should drop this on a page and tweak three attributes in the sidebar," a PHP-only block is the right shape. You get a block in the inserter, theme.json-friendly wrapper attributes, and a render function you can keep next to the rest of your PHP.
If you have been stuffing HTML into a shortcode snippet because a real block meant a JS build, 7.0 is the release that ends that excuse for simple cases.
What a snippet is still for
A snippet is site behavior, not an inserter item.
- Filters and actions (
pre_get_posts,woocommerce_checkout_fields,auth_redirect) - Admin-only CSS, login-page CSS, checkout JS
- Tracking pixels and consent-gated tags
- Capability tweaks, CPT registration you do not want in the theme
- One-off fixes that must survive a theme switch
None of those belong in a block. A block that "runs a filter when it is present on the page" is how you get heisenbugs: the filter exists on the marketing page and vanishes on the blog. Site-wide behavior needs a snippet (or a real plugin), with conditional loading when the behavior is *not* actually site-wide.
We already walked the 7.0 / PHP 8.4 audit list in WordPress 7.0 and PHP 8.4: what breaks in custom code first. This article is the complementary question: new container vs old container.
A practical split
Use a PHP-only block when:
- An editor must place it
- Output is HTML for a region of the page
- Attributes are a handful of scalars
- You are fine pinning WordPress/Gutenberg versions while the API is experimental
Use a snippet when:
- It must run whether or not a block is on the page
- It is CSS or JavaScript with no block UI
- It is a hook, not a template
- You need a toggle, a sandbox, Git, or an audit trail independent of the theme
Use a real plugin when the block needs InnerBlocks, a custom inspector, or a build anyway. PHP-only registration is not a secret back door to full Gutenberg. Ryan Welcher's March write-up is explicit about the gaps.
How to keep PHP-only blocks from becoming the new functions.php
The failure mode is predictable. Agencies will drop register_block_type into a 400-line snippet called "misc 7.0 blocks" and call it architecture.
Do this instead:
- One block per file, named after the block
- Register on
init, render callbacks that escape output - Store the files in the same place you store snippets — a file-based manager or a small mu-plugin — not in the parent theme
- Version them. A PHP-only block is still production PHP.
In SnipVault that means a PHP snippet (or a project workspace) that only registers blocks, reviewed like any other publish. The Snippet Engineer can draft the register_block_type call; you still approve it. The security audit still cares whether the render callback prints unsanitized attributes.
Experimental means have a rollback
Because autoRegister is experimental in 7.0, treat public-site blocks as pinned. If you ship a client site on 7.0.x, note the Gutenberg/core versions in the snippet description. When 7.1 or 7.2 changes the generated inspector, you want a GitHub history, not folklore.
If a PHP-only block fatals in render_callback, it usually takes down the page that contains it, not the whole admin — a better blast radius than a snippet on init. That is an argument for blocks *as UI*, not an argument for putting checkout total calculations in a render callback.
Shortcodes you can finally retire
The best migration candidates are shortcodes that only exist because "we did not want a React block." Inventory add_shortcode in your snippet library. For each one, ask: should an editor insert this as a block now? If yes, write the PHP-only block and leave the shortcode as a deprecated wrapper for a release. If no — it is a cron, a filter, a pixel — leave it as a snippet.
Bottom line
WordPress 7.0 gave PHP developers a legal way to ship simple blocks without a JS toolchain. Use it. Do not use it as a reason to delete your snippet plugin. Blocks are for the canvas. Snippets are for the runtime. Mixing them is how 2024's functions.php becomes 2026's "autoRegister dump."
Keep site behavior in a snippet workflow you can disable. Keep placeable UI in PHP-only blocks with one render function each. Promote either to a plugin when it grows a schema or a UI you cannot generate from an attributes array.