Contact Form Manual Fix

2-minute wp-admin save to move the form above the footer on /contact-us/

โฑ 2 minutes
๐Ÿ“‹ 9 steps
๐Ÿ›ก 0 risk (append-only)
๐Ÿ”Œ 7 API attempts failed โ†’ manual is the only way

?Why Manual (And Not API)

After 7 API attempts today (Apr 13), the conclusion is structural: the Code Snippets REST endpoint returns HTTP 200 but silently does not persist UPDATE operations the way wp-admin's save flow does.

  • Byte-count proof: Snippet #55 measured 44,650 bytes before the API PUT, 44,650 bytes after. The marker string was not found in the persisted code.
  • Cached HTML verification: 7 snippets created via API during this session did not appear in the rendered /contact-us/ HTML.
  • Cache architecture: Deep LiteSpeed and Oxygen caches only regenerate when the wp-admin CodeMirror save triggers the plugin nonce and cascading cache invalidation.
  • Only path that works: The blue Update button in wp-admin cascades through all cache layers. That's the only reliable persistence path right now.

โ˜…What This Fix Does

  • Appends a new add_action('wp_footer', ...) block to the bottom of Snippet #55. Nothing existing is modified.
  • Runs only on /contact-us/ via the is_page gate โ€” zero impact elsewhere.
  • Uses a setInterval retry loop (50 attempts ร— 300ms = 15 seconds of retries) to handle Oxygen Builder's late element rendering.
  • Primary target: #shortcode-15-90 (the booking section โ€” preserves Audrey's designed layout).
  • Fallback target: insertBefore #footer โ€” guarantees form is at least above the footer.
  • Preserves ALL GTM tracking listeners โ€” the DOM node is moved, never cloned. Event listeners stay attached.
  • Registered at priority 9999 so it runs after every other wp_footer script including Oxygen's late loaders.

9The Click-by-Click Steps

1
Log into wp-admin
โœ“

Action

  • Open browser and go to: https://www.callbrightside.com/wp-admin
  • Enter your username and password
  • Click the blue "Log In" button
WordPress login screen with two text fields and a blue "Log In" button below them.
WordPress dashboard loads. You'll see "Welcome to WordPress" or the Dashboard widgets.
2
Navigate to Code Snippets
โœ“

Action

  • Look in the left sidebar for "Snippets" with a lightning โšก icon
  • Click "Snippets" โ†’ then "All Snippets"
Left sidebar sub-menu expands. "All Snippets" is usually the first item.
A table of 73+ snippets loads. Columns: Name, Type, Scope, Priority, Tags.
3
Find Snippet #55
โœ“

Action

  • Scan for: "BSP CRO Contact Form + EC4L v4.0 (REVIEW BEFORE ACTIVATING)"
  • Status badge should show "Active" (green indicator)
  • Click the title link to open it
Green dot or "Active" badge next to the snippet name. If it's not active, stop and check with Claude before proceeding.
CodeMirror editor opens with approximately 44,650 bytes of PHP code. Line count should be ~900+.
4
Scroll to the bottom of the code
โœ“

Action

  • Click anywhere inside the code editor
  • Press Ctrl + End to jump to the end of the code
  • Last visible lines should be PHP ending with something like }, 99); or });
Scrollbar snaps to the bottom. Cursor blinks after the final line of code.
Cursor is at the very end of all existing code, ready for you to press Enter and paste.
5
Paste the new code block
โœ“

Action

  • Confirm the cursor is after the last existing ); or }
  • Press Enter twice to make a blank line of separation
  • Click the Copy button below โ†’ paste with Ctrl + V into the editor
โš ๏ธ
DO NOT modify anything above this. The existing code contains the contact form itself. You are ONLY appending at the very bottom.

Code block to paste

// APR 13 2026: Repositioning retry loop - moves form above footer
add_action('wp_footer', function() {
    if (!is_page('contact-us')) return;
    echo '<script data-cfasync="false" id="bsp-reposition-retry-apr13">(function(){var moved=false;function moveForm(){if(moved)return true;var form=document.getElementById("bsp-contact-wrapper");if(!form)return false;var primary=document.getElementById("shortcode-15-90");if(primary){if(primary.contains(form)){moved=true;return true;}primary.appendChild(form);form.style.display="block";moved=true;return true;}var footer=document.getElementById("footer");if(footer&&footer.parentNode){footer.parentNode.insertBefore(form,footer);form.style.display="block";moved=true;return true;}return false;}var n=0,max=50;var intId=setInterval(function(){n++;if(moveForm()||n>=max)clearInterval(intId);},300);if(document.readyState==="loading"){document.addEventListener("DOMContentLoaded",moveForm);}window.addEventListener("load",function(){setTimeout(moveForm,500);setTimeout(moveForm,1500);setTimeout(moveForm,3000);});})();</script>';
}, 9999);
Pasted code sits at the very bottom of the editor. Total byte count increases by ~1,000 bytes.
6
Click the blue Update button
โœ“

Action

  • Scroll below the code editor
  • Find the big blue "Update" or "Save Changes" button
  • Click it. Wait 1-3 seconds.
Green success banner at the top: "Snippet updated." If you see a red error, STOP and see Step 9 fallback.
Success notification within 2 seconds. No error, no 500 page.
7
Clear WP Rocket cache
โœ“

Action

  • Look at the top admin bar (black bar across the top)
  • Click "WP Rocket"
  • Click "Clear and preload cache"
Rocket icon in admin bar. Dropdown shows cache options.
"Cache cleared" notification appears. Takes 5-15 seconds to fully propagate.
8
Verify in an incognito window
โœ“

Action

  • Open incognito: Ctrl + Shift + N (Chrome) or Ctrl + Shift + P (Firefox)
  • Go to: https://www.callbrightside.com/contact-us/
  • Confirm the form sits above the footer, inside the booking section
  • To confirm the code is live: press Ctrl + U (view source), then Ctrl + F โ†’ search for bsp-reposition-retry-apr13
Form is visible within the page content area โ€” NOT below the footer links. Source view contains the marker string.
Marker string found in source = fix is live. Form is visually positioned above the footer.
9
Fallback if the form is still wrong
โœ“

Action (only if Step 8 didn't show the marker or form is misplaced)

  1. Clear browser cache completely: Ctrl + Shift + Del โ†’ select "All time" โ†’ clear everything
  2. Retry /contact-us/ in the same incognito window
  3. If STILL wrong: try a different browser (Firefox if you were in Chrome, or vice versa)
  4. If STILL wrong: screenshot the page + open DevTools (F12) โ†’ Inspect the #bsp-contact-wrapper element โ†’ copy its parent element ID โ†’ send to Claude for an adjusted selector
Either the fix works after a harder cache clear, or Claude gets enough info to adjust the selector.

โœ“What Success Looks Like

โŒ BEFORE (broken)

Form renders after the footer in source order.

<header>...</header> <main>...</main> โ””โ”€ wrapper missing here โŒ <footer> โ† pos 32,658 contact links social links </footer> <div id="bsp-contact-wrapper"> โ† pos 48,068 โŒ [form below footer] </div>

Wrapper position 48,068 > footer position 32,658 = form visually orphaned.

โœ… AFTER (fixed)

Form sits inside #shortcode-15-90 booking section.

<header>...</header> <main> <section id="shortcode-15-90"> <div id="bsp-contact-wrapper"> โœ… [contact form] </div> </section> </main> <footer> โ† comes LAST โœ… contact links </footer>

Wrapper rendered inside booking section, both above footer. Layout preserved.

โš™Technical Details (for reference)

Why DOMContentLoaded alone doesn't work

Oxygen Builder renders shortcodes after DOMContentLoaded fires. When our script looks for #shortcode-15-90 at DOMContentLoaded, the element doesn't exist yet. This is why 3 earlier attempts kept failing silently โ€” no error, just a missing target.

Why setInterval retry (50 ร— 300ms)

Catches the target element whenever Oxygen finishes rendering โ€” which can be anywhere from 500ms to 5000ms after load depending on network, images, and other shortcodes. 15 seconds of retries covers every real-world case without blocking the page.

Why two fallbacks (shortcode-15-90 โ†’ footer)

Primary: #shortcode-15-90 preserves Audrey's designed booking section layout.
Secondary: insertBefore #footer ensures that even if the shortcode is renamed or removed, the form is at least not orphaned below the footer.

Why priority 9999

add_action('wp_footer', ..., 9999) runs LAST in the wp_footer hook chain. This puts our script after all Oxygen late-loading scripts, so when our setInterval starts polling, Oxygen is already doing its work in parallel.

Why appendChild preserves GTM

Moving a DOM node with appendChild or insertBefore keeps all attached event listeners intact. Only cloneNode or innerHTML replacement would break GTM tracking. This is why the fix uses direct DOM moves โ€” every GTM click event on the form keeps firing correctly.

โ†บBackup + Rollback

Backup of Snippet #55 (pre-fix) is saved at:

  • Local: C:\Users\dovew\Documents\Clients\BrightSidePlumbing\backups\snippet_55_pre_apr13_fix.php
  • VM: /opt/nexus/nexus/scripts/output/backups/snippet_55_pre_apr13_fix.php

If this fix causes a 500 error or the form disappears:

  1. Go back to Snippet #55 in wp-admin
  2. Delete the appended block (everything you pasted in Step 5 โ€” from // APR 13 2026 down to }, 9999);)
  3. Click Update
  4. Clear WP Rocket cache
  5. Form returns to pre-fix state. No data lost.

โณHistory โ€” Why This Happened

Mar 16, 2026 โ€” CRO form originally created and deployed.
Mar 22, 2026 โ€” phpMyAdmin crash wiped active snippets. First breakage incident.
Apr 2, 2026 โ€” Redeployed as Snippet #55 v4.0 during the 16-hour marathon session.
Apr 12-13, 2026 โ€” Discovered form rendering AFTER footer on /contact-us/. Third incident in 28 days.
Apr 13, 2026 (today) โ€” 7 API-based fix attempts failed due to cache layer architecture. Manual wp-admin save confirmed as the only reliable path.
Long-term fix โ€” Bricks Builder migration will rebuild /contact-us/ with native form placement. No JS repositioning hack needed.

!Important Call-outs

๐Ÿ›‘
Do NOT modify the existing code in Snippet #55. Only APPEND the new block at the very end. The existing code has the form itself โ€” editing it could break the form entirely. Append-only is safe. Modifying existing lines is not.
โš ๏ธ
If you see a 500 error after clicking Update. Immediately delete what you pasted in Step 5 and click Update again. The original form returns. No data is lost. This is why append-only matters โ€” rollback is literally a delete-and-save.
โœ…
Success confirmation. Once the marker bsp-reposition-retry-apr13 appears in page source, the fix is live and permanent until either Kalen rebuilds /contact-us/ in Oxygen or we migrate to Bricks. No further action needed.
0/9 steps done