-
-
Save cliffordp/335bee91f59a49a378cdfd44bd8f510f to your computer and use it in GitHub Desktop.
GHL: Add meaningful page titles based on heading content so they're not all the same
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <script> | |
| // This script: https://gist.github.com/cliffordp/335bee91f59a49a378cdfd44bd8f510f | |
| // Based on https://www.facebook.com/groups/gohighlevel/posts/2734386397020878 from Jordan Coeyman | |
| // Install this (without this comment block) via "Custom JS": https://app.gohighlevel.com/settings/company?tab=whitelabel | |
| (function() { | |
| 'use strict'; | |
| const POLL_INTERVAL = 2000; | |
| // selectors in priority order | |
| const HEADING_SELECTORS = [ | |
| '.sidebar-v2-agency .active span', | |
| '.sidebar-v2-location .active span', | |
| 'h1', | |
| '[role="heading"][aria-level="1"]', | |
| '.page-title', | |
| '.header-title', | |
| '[data-testid="page-title"]', | |
| 'main h1', | |
| 'main h2', | |
| '.content-header h1', | |
| '.content-header h2', | |
| 'h2', | |
| '[class*="title" i]:not(button):not(a)', | |
| '[class*="heading" i]:not(button):not(a)' | |
| ]; | |
| let lastTitle = null; | |
| let lastUrl = location.href; | |
| const siteName = (location.hostname.split('.').slice(-2, -1)[0] || location.hostname); | |
| function getSubaccountName() { | |
| const subaccount = document.querySelector('.sidebar-v2-location .hl_location-text span.hl_switcher-loc-name'); | |
| return subaccount ? subaccount.textContent.trim() : ''; | |
| } | |
| function getCleanText(el) { | |
| if (!el) return null; | |
| const clone = el.cloneNode(true); | |
| const junkNodes = clone.querySelectorAll( | |
| 'button, svg, [class*="icon"], [class*="badge"], .sr-only' | |
| ); | |
| junkNodes.forEach(function(n) { | |
| if (n && n.parentNode) { | |
| n.parentNode.removeChild(n); | |
| } | |
| }); | |
| let text = clone.textContent; | |
| if (!text) return null; | |
| text = text.trim().replace(/\s+/g, ' '); | |
| if (!text || text.length < 2 || text.length > 100) return null; | |
| return text; | |
| } | |
| function findBestHeading() { | |
| for (let i = 0; i < HEADING_SELECTORS.length; i++) { | |
| const selector = HEADING_SELECTORS[i]; | |
| try { | |
| const el = document.querySelector(selector); | |
| const text = getCleanText(el); | |
| if (text) { | |
| const sub = getSubaccountName(); | |
| return sub ? (text + ' | ' + sub) : text; | |
| } | |
| } catch (e) { | |
| // ignore selector errors and continue | |
| } | |
| } | |
| return null; | |
| } | |
| let updateScheduled = false; | |
| function scheduleUpdateTitle() { | |
| if (updateScheduled) return; | |
| updateScheduled = true; | |
| setTimeout(function() { | |
| updateScheduled = false; | |
| updateTitle(); | |
| }, 100); | |
| } | |
| function updateTitle() { | |
| const heading = findBestHeading(); | |
| // CHANGED: do not append siteName, just use heading (or blank) | |
| const newTitle = heading || ''; | |
| if (newTitle !== lastTitle) { | |
| document.title = newTitle; | |
| lastTitle = newTitle; | |
| } | |
| } | |
| function checkForNavigation() { | |
| if (location.href !== lastUrl) { | |
| lastUrl = location.href; | |
| scheduleUpdateTitle(); | |
| } | |
| } | |
| const observer = new MutationObserver(function() { | |
| // Debounce updates so rapid DOM changes do not spam work | |
| scheduleUpdateTitle(); | |
| }); | |
| if (document.body) { | |
| observer.observe(document.body, { | |
| childList: true, | |
| subtree: true, | |
| characterData: true | |
| }); | |
| } else { | |
| window.addEventListener('DOMContentLoaded', function() { | |
| if (document.body) { | |
| observer.observe(document.body, { | |
| childList: true, | |
| subtree: true, | |
| characterData: true | |
| }); | |
| } | |
| updateTitle(); | |
| }); | |
| } | |
| window.addEventListener('popstate', scheduleUpdateTitle); | |
| window.addEventListener('hashchange', scheduleUpdateTitle); | |
| setInterval(function() { | |
| checkForNavigation(); | |
| scheduleUpdateTitle(); | |
| }, POLL_INTERVAL); | |
| // Initial run | |
| updateTitle(); | |
| })(); | |
| </script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment