Repository navigation
Conversation
Add a Disable Header Globally toggle to the Header panel and a Disable Footer Globally toggle to the Footer panel. Both feed the existing neve_filter_toggle_content_parts filter, at a priority that runs after the post meta, so the site wide setting wins. Move the filter check outside the header element in both templates. The element used to be printed even when the header was off, which left an empty wrapper that held only the skip link. The skip link now sits outside the element, so it survives a disabled header. The builder panels hide every section they do not name, so both sections are added to the whitelist in the customizer styles. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The states were printed on neve_after_header_hook, which does not run when the header is off. One of them drives the WooCommerce shop sidebar, which stays on the page without a header. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Add unit tests for the toggle, its precedence over the post meta, the markup of both templates and the customizer registration. Add end to end tests, one of which opens the builder panels, because a section can register and still be hidden by the panel styles. Complete the WooCommerce stub with the conditional tags, so tests that render body_class() after the cart tests do not fatal. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The test case restores the hooks and rolls back the database, but it does not touch $wp_customize. Keep the previous value and put it back, the way the metabox test does with the REST server. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Hold the panel, the section title and the control label in one array per part, in place of two ternaries. Assert on the toggle structure in the e2e spec, not on the English label. Check that the stylesheet exists before the test reads it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Drop the hook docblock copied into header.php. footer.php documents this filter and the block theme template carries none. Keep only the part of the filter docblock a reader cannot infer. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The animations were printed on `neve_before_header_hook`, which only runs inside the header element. A header turned off in the customizer took them with it, and the button stays hidden until an animation shows it. Print them on `neve_before_header_wrapper_hook`, next to the AMP states. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
An `amp-position-observer` watches its own parent when it has no target. Moving the observer out of the header in 9462899 made the page wrapper its parent, and the wrapper is never out of the viewport, so the button stayed hidden on every AMP page. Print an anchor at the top of the wrapper and point the observer at it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…settings The toggles no longer get a section each. Disable Header now opens the General tab of Global Header Settings, where Neve Pro already keeps its site-wide header controls. Disable Footer lives in a new Global Footer Settings section, the footer's counterpart, so the two panels match. The theme mod keys stay neve_disable_header and neve_disable_footer, so the render filter and saved values are unchanged. Both toggles reuse the per-page labels and say that page builder headers and footers go too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs/ is excluded from the theme build by .distignore. Drop this commit before merging if the images should not stay in the repository. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The toggle was registered only with the new builder's global header settings, so sites still on the legacy builder lost it. Those sites now get a Global Header Settings section with the toggle as a plain control. It has no tabs, so any Neve Pro controls in that section show as before, and a section Pro registered first is kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes requested
The toggles move correctly and the tests pass, but two small code fixes are needed in Header.php and the test provider.
Validation details
- Files reviewed: 12/12 changed files. The four PNG screenshots were not inspected.
TestNeveGlobalHeaderFooterpassed at HEAD with PHP 8.3, WordPress 7.1.3 and PHPUnit 9.6: 29 tests, 109 assertions.- Every changed test failed on the base code with the PR tests kept: 5 failures and 1 error.
- No remaining code references the removed sections or the removed class.
- Capability, sanitization and escaping match the base code.
Untested areas
- The Customizer screens were not opened in a browser. The customizer build was not run.
- The changed Playwright spec was not run.
- Neve Pro was not available, so the order beside its controls is unchecked.
🤖 Automated review · run code-review-agent_6ac6ac6fdea3e6.06896057.
🤖 Review agent — review posted ✅ on 9d082a82 · changes requested · 2 findings · 15 min
Run code-review-agent_6ac6ac6fdea3e6.06896057 · trail
Both registrations of neve_disable_header now take default, transport and sanitize_callback from get_disable_header_setting_args(), so the legacy and the new builder paths cannot drift apart. The user-since data provider gets a precise return type. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… call Theme Check reads each $wp_customize->add_setting() call and requires a sanitize_callback key in it, so passing the shared argument array failed the check. The legacy call now lists the keys, with values still taken from get_disable_header_setting_args(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes requested
Both earlier findings are fixed. Add native : array return types to the two new helpers in Header.php.
Validation details
- Files reviewed: 12/12 changed files. The four PNG screenshots were not inspected.
TestNeveGlobalHeaderFooterpassed at HEAD with PHP 8.3, WordPress 7.1.3 and PHPUnit 9.6: 29 tests, 109 assertions.php -lpassed onHeader.php.- Theme Check needs the literal
sanitize_callbackkey insideadd_setting(), so the unpacked keys are justified. - Base-tree test failures and the security checks come from run code-review-agent_6ac6ac6fdea3e6.06896057, not rerun.
Untested areas
- The Customizer screens were not opened in a browser.
- The changed Playwright spec was not run.
- Neve Pro was not available, so the order beside its controls is unchecked.
🤖 Automated review · run code-review-agent_6ac6b18f6f31b7.82482385.
🤖 Review agent — review posted ✅ on a66fcdbc · changes requested · 2 findings · 7 min
Run code-review-agent_6ac6b18f6f31b7.82482385 · trail
…lpers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟢 Approved
The PR passes. Both helpers in Header.php now declare native : array return types, which fixes the last two findings.
Validation details
- Files reviewed: 12/12 changed files. Only
Header.phpchanged sincea66fcdbc. The four PNG screenshots were not inspected. php -lpassed onHeader.phpwith PHP 8.3.TestNeveGlobalHeaderFooterpassed at HEAD with PHP 8.3, WordPress 7.1.3 and PHPUnit 9.6: 29 tests, 109 assertions.- A standards check of the new commit found no issue.
- Security checks and base-tree test runs come from runs code-review-agent_6ac6ac6fdea3e6.06896057 and code-review-agent_6ac6b18f6f31b7.82482385, not rerun.
Untested areas
- The Customizer screens were not opened in a browser.
- The changed Playwright spec was not run.
- Neve Pro was not available, so the order beside its controls is unchecked.
🤖 Automated review · run code-review-agent_6ac6b67b04eaf5.37804121.
🤖 Review agent — review posted ✅ on 12ef6887 · approved · 0 findings · 2 min
Run code-review-agent_6ac6b67b04eaf5.37804121 · trail
The footer section is now titled Footer Options and both toggles drop their descriptions, so the change adds no strings to translate. Every label it uses already exists in the theme. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…feat/4551-global-settings
… without the footer A disabled header skipped neve_before_header_hook and neve_after_header_hook along with the wrapper. Neve Pro prints its page header on neve_after_header_hook, so a page that turned its header off lost the page header too, which development keeps. The hooks now always run, and the header wrapper prints when the header is on or when the hooks printed something. An empty wrapper is still dropped. The block template follows the same rule. The AMP infinite scroll wraps the footer hooks and removes the regular pagination, so with the footer off an AMP blog archive had no pagination at all. The infinite scroll now steps aside when the footer is off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The skip link used to sit inside <header next-page-hide>, so AMP infinite scroll hid it on the pages it appends. Outside the header it needs its own attribute, or every appended page adds another focusable skip link. Tests now also cover whitespace-only hook output and the per-page switch in the block theme template. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes requested
The feature code works, but four test fixes are needed: one FSE test cannot fail, one comment is false, one case is missing, and some types are too broad.
Validation details
- Files reviewed: 13/17 changed files. The four PNG screenshots were not inspected.
TestNeveGlobalHeaderFooterpassed at HEAD with PHP 8.3, WordPress 7.1.3 and PHPUnit 9.6: 37 tests.- With the changed theme files restored from
pr-base, 25 of 37 tests failed. - A scratch FSE render with FSE templates enabled showed the header part dropped only at HEAD.
- Source checks found no security issue.
Untested areas
- The new Playwright spec was not run.
- The Customizer screens were not opened.
- AMP pages were not rendered in a browser.
- Neve Pro was not available.
🤖 Automated review · run code-review-agent_6ac74d64b38553.54222683.
🤖 Review agent — review posted ✅ on 70f69bf4 · changes requested · 4 findings · 21 min
Run code-review-agent_6ac74d64b38553.54222683 · trail
The block template helper never enabled the theme's FSE templates, so the header part never rendered and the tests passed whatever the template did. They now turn the templates on and check neve_do_header, and a new case covers the AMP attribute on the block template skip link. The shop test is gone: it opened a regular page and never reached the shop branch, and the rule it checked is covered by the global-over-meta test. Docblocks of the providers and helpers now give their shapes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟢 Approved
The PR passes. All four earlier test findings are fixed, and the new commit adds no new problem.
Validation details
- Files reviewed: 13/13 changed files. Since
70f69bf4, only the test file changed and four screenshots were deleted. TestNeveGlobalHeaderFooterpassed at HEAD with PHPUnit 9.6, PHP 8.3 and WordPress 7.1.3: 37 tests.- With the changed theme files from
pr-base, 25 of 37 tests failed, including the FSE disabled-header and FSE AMP tests. - With only
fse.phpfrompr-base, 3 FSE tests failed. - Security checks from run code-review-agent_6ac74d64b38553.54222683 were reused, not rerun. No theme code changed since then.
Untested areas
- The new Playwright spec was not run.
- The Customizer screens and AMP pages were not opened in a browser.
- Neve Pro was not available.
🤖 Automated review · run code-review-agent_6ac753d0713d86.11019970.
🤖 Review agent — review posted ✅ on 22e98438 · approved · 0 findings · 7 min
Run code-review-agent_6ac753d0713d86.11019970 · trail
Users who build their header and footer with a page builder had no way to turn off the theme header and footer for the whole site. This PR adds Disable Header and Disable Footer to existing Customizer sections, and a disabled header no longer leaves an empty wrapper on the page.
Note
This PR replaces #4628. It carries the commits of #4628 and moves the toggles out of the two single-control sections that #4628 added.
What changed
Header panel — Disable Header is the first control on the General tab of Global Header Settings. Neve Pro already shows its site-wide header controls on that tab. Sites still on the legacy header builder get the same section with the toggle as a plain control, without tabs.
Footer panel — a new Footer Options section holds Disable Footer. It sits below the footer rows, after Change Copyright when a site has that section.
Strings — the change adds no strings to translate. It reuses Disable Header, Disable Footer, Global Header Settings and Footer Options.
Header markup — when the header is off, the
<header>element is printed only if other code adds content around the header, such as the Neve Pro page header. With nothing to wrap, no element is printed. Before, an empty element stayed on the page. The skip link now prints outside the header element, and on AMP it keepsnext-page-hide.inc/compatibility/fse.phpgets the same change for the block template.Post meta — a page can still turn its own header or footer off. A page can no longer turn one back on against the global toggle.
AMP — the
amp-stateelements move toneve_after_header_wrapper_hook, because one of them drives the WooCommerce shop sidebar. The scroll-to-top animations print before the header wrapper, and their observer watches an anchor that scrolls out of view. When the footer is off, the infinite scroll steps aside and the archive keeps its regular pagination.Note
The toggle removes the whole header region, and page builders render into that region. Elementor Pro, Header Footer Elementor and Beaver Themer hook
neve_do_headerandneve_do_footer, so their headers and footers go away too. This is intended: a user who wants a page builder header leaves the toggle off. Elementor Canvas templates never callget_header(), so they do not change.Note
The header hooks run inside an output buffer, so the wrapper prints only around real content. A hook callback that calls
ob_flush()or throws can bypass that buffer. No callback in Neve or Neve Pro does this.Note
Disable Header is not a conditional header setting. Neve Pro does not swap it per header layout, so it hides every header layout at once.
What decides if the header renders
flowchart LR A["Page loads"] --> B{"Post meta<br/>set to on?"} B -- yes --> C["No header"] B -- no --> D{"New:<br/>Disable Header<br/>is on?"}:::added D -- yes --> E["Changed:<br/>no header element,<br/>skip link stays"]:::changed D -- no --> F["Header renders"] classDef added fill:#1a7f37,color:#fff,stroke:#116329,stroke-width:3px classDef changed fill:#9a6700,color:#fff,stroke:#5c3d00,stroke-width:3px,stroke-dasharray:6 3QA
Go to
WP Admin → Appearance → Customize → Header → Global Header Settings.Expect: the General tab opens first and shows Disable Header, off. The Style tab still holds the background controls.
Turn on Disable Header and publish. Open the front end in a new tab and view the page source (
Ctrl+UorCmd+Option+U). Search for<header.Expect: no match. One
neve-skip-linkmatch stays, andTabat the top of the page shows Skip to content.Open a category archive and a search results page, for example
/?s=test.Expect: no header on either page. The page metabox never covered these views.
Open a single page in the editor. In the sidebar, open Neve Options. Turn Disable Header on, update, then turn it off and update again.
Expect: with the global toggle on, the page has no header in both states.
Turn off the global Disable Header. On the same page, set the page's Disable Header to on and update.
Expect: this page has no header. Every other page keeps its header.
If WooCommerce is active, turn on the global toggle and open the shop archive on a narrow screen.
Expect: no header. The shop sidebar and its filter toggle still work.
Go to
WP Admin → Appearance → Customize → Footer → Footer Options. Turn on Disable Footer and publish. Search the front-end source forid="site-footer".Expect: no match. The page still ends with
</body>.Switch the site to the legacy header builder with WP-CLI, then go to
Customize → Header.wp theme mod set neve_migrated_builders 0Expect: the panel lists Global Header Settings. It holds Disable Header with no tabs, and turning it on removes the header from the preview.
Switch the site back to the new builder.
Expect: the Header panel shows the builder rows and the tabbed Global Header Settings again.
If Neve Pro is active with a license, go to
Customize → Header → Global Header Settings → General.Expect: Disable Header comes first, above Show This Header Site-wide.
If Neve Pro is active with a license, add a component to its Page Header builder. Turn on Disable Header for one page in Neve Options, then for the whole site.
Expect: in both cases the main header is gone and the page header still shows.
If the AMP plugin is active, set the blog to infinite pagination with no sidebar. The Post Pagination control comes from Neve Pro, so without it use WP-CLI. Turn on Disable Footer and open the blog page on its AMP URL.
Expect: the regular page links show at the end of the post list.
Part of #4551.
🤖 Generated with Claude Code