How to Add Source Code Highlights in Bricks Builder + Core Framework
WPCodeBox
Enhancing the readability and functionality of your source code snippets can be a game-changer for your WordPress site. Today, let's talk about how to add source code highlights and a handy "Copy Code" button to your site - specially for Bricksbuilder with Core framework—without using any plugins!
Additional Snippets
Instructions for WPCodeBox:
- Add a new snippet in WPCodeBox.
- Paste the script
- Save it once, then Enable it, and Save it again
- Clear your cache
- Check your existing PRE or CODE tags
This version is only for Bricksbuilder with Core Framework
You will need to modify this if you are using ACSS or AT Framework.<?php
/**
* Highlight.js + Copy button + Folding (Bricks-safe) + CF light/dark theme switching
*
* @author Ruhani Rabin
* @link https://www.ruhanirabin.com/code-snippet/
* @version 1.3.0
*
* Changelog:
* 1.3.0 - Fixed theme switching to properly load correct stylesheet
* - Implemented dynamic stylesheet loading via JavaScript
* - Removed CSS-based hiding approach (didn't work)
* 1.2.0 - Changed light theme to Stack Overflow Light for better contrast
* - Improved color visibility in light mode
* 1.1.0 - Fixed light mode rendering issues
* - Added JetBrains Mono font from Google Fonts
* - Improved theme switching logic
* 1.0.0 - Initial release
*
* Requirements: WP 6.5+, PHP 8.1+
*/
add_action( 'wp_enqueue_scripts', function () {
// Highlight.js core
wp_enqueue_script(
'rr-highlight-js',
'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js',
array(),
'11.11.1',
true
);
// JetBrains Mono font from Google Fonts
wp_enqueue_style(
'rr-jetbrains-mono',
'https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap',
array(),
null
);
// Don't run in admin.
if ( is_admin() ) {
return;
}
// Don't run in Bricks builder/editor/preview.
if ( isset( $_GET['bricks'] ) || isset( $_GET['bricks_preview'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
return;
}
// Extra safety: Bricks often adds these body classes.
if ( isset( $_GET['brxe_iframe'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
return;
}
// Theme switching + Bricks-safe highlighter + wrapper logic.
$inline_js = <<<'JS'
(function () {
"use strict";
// Bail if we're inside Bricks builder UI
if (
document.querySelector('#bricks-panel, .bricks-panel, body.bricks-is-builder, body.bricks-builder, #brxe-editor')
|| window.location.search.includes('bricks=')
|| window.location.search.includes('bricks_preview=')
|| window.location.search.includes('brxe_iframe=')
) {
return;
}
// === Dynamic Theme Stylesheet Loading ===
var currentThemeLink = null;
var LIGHT_THEME = 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/stackoverflow-light.min.css';
var DARK_THEME = 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/github-dark.min.css';
function loadHljsTheme() {
var isDark = document.documentElement.classList.contains('cf-theme-dark');
var themeUrl = isDark ? DARK_THEME : LIGHT_THEME;
// If already loaded, skip
if (currentThemeLink && currentThemeLink.href === themeUrl) {
return;
}
// Remove old theme
if (currentThemeLink) {
currentThemeLink.remove();
}
// Add new theme
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = themeUrl;
link.id = 'rr-hljs-theme';
document.head.appendChild(link);
currentThemeLink = link;
}
// Load initial theme
loadHljsTheme();
// Watch for theme changes
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.attributeName === 'class') {
loadHljsTheme();
}
});
});
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ['class']
});
// === Code Enhancement Logic ===
function ensureCodeChild(pre) {
if (!pre) return null;
var code = pre.querySelector("code");
if (code) return code;
var text = pre.textContent || "";
pre.textContent = "";
code = document.createElement("code");
code.textContent = text;
pre.appendChild(code);
return code;
}
function enhanceCodeBlock(codeBlock) {
if (!codeBlock || codeBlock.dataset.rrEnhanced === "1") return;
var pre = codeBlock.closest("pre");
if (!pre) return;
// Wrap once
if (!pre.parentElement.classList.contains("code-block-wrapper")) {
var wrapper = document.createElement("div");
wrapper.className = "code-block-wrapper";
pre.parentNode.insertBefore(wrapper, pre);
wrapper.appendChild(pre);
// Copy button
var copyBtn = document.createElement("button");
copyBtn.type = "button";
copyBtn.className = "copy-code-btn";
copyBtn.textContent = "Copy";
copyBtn.setAttribute("aria-label", "Copy code to clipboard");
wrapper.appendChild(copyBtn);
copyBtn.addEventListener("click", async function () {
try {
await navigator.clipboard.writeText(codeBlock.textContent);
copyBtn.textContent = "Copied";
setTimeout(function () { copyBtn.textContent = "Copy"; }, 1600);
} catch (e) {
copyBtn.textContent = "Failed";
setTimeout(function () { copyBtn.textContent = "Copy"; }, 1600);
}
});
// Fold logic (word-count)
var wordCount = (codeBlock.textContent || "").trim().split(/\s+/).filter(Boolean).length;
if (wordCount > 300) {
var foldBtn = document.createElement("button");
foldBtn.type = "button";
foldBtn.className = "fold-toggle-btn";
foldBtn.textContent = "Show more";
wrapper.appendChild(foldBtn);
pre.classList.add("folded");
foldBtn.addEventListener("click", function () {
pre.classList.toggle("unfolded");
foldBtn.textContent = pre.classList.contains("unfolded") ? "Show less" : "Show more";
});
}
}
// Highlight once
if (window.hljs && codeBlock.dataset.rrHighlighted !== "1") {
try {
window.hljs.configure({ ignoreUnescapedHTML: true });
window.hljs.highlightElement(codeBlock);
codeBlock.dataset.rrHighlighted = "1";
} catch (e) {}
}
codeBlock.dataset.rrEnhanced = "1";
}
function scan(root) {
root = root || document;
// Only scan content areas, NOT builder/editor UIs
var containers = root.querySelectorAll(
".entry-content, main, article, .brxe-text, .brxe-post-content, .brxe-rich-text"
);
if (!containers.length) {
containers = [root];
}
containers.forEach(function (container) {
container.querySelectorAll("pre code").forEach(enhanceCodeBlock);
container.querySelectorAll("pre:not(.rr-pre-checked)").forEach(function (pre) {
pre.classList.add("rr-pre-checked");
var code = ensureCodeChild(pre);
if (code) enhanceCodeBlock(code);
});
});
}
document.addEventListener("DOMContentLoaded", function () {
scan(document);
});
// Bricks frontend events (safe if not present)
document.addEventListener("bricks/ajax/end", function () { scan(document); });
document.addEventListener("bricks/frontend/init", function () { scan(document); });
// Observe dynamic injections (Bricks, tabs, accordions, lazy content)
var mo = new MutationObserver(function (mutations) {
for (var i = 0; i < mutations.length; i++) {
var m = mutations[i];
if (!m.addedNodes) continue;
m.addedNodes.forEach(function (node) {
if (node.nodeType !== 1) return;
scan(node);
});
}
});
mo.observe(document.documentElement, { childList: true, subtree: true });
})();
JS;
wp_add_inline_script( 'rr-highlight-js', $inline_js );
}, 20 );
/**
* Optional: Wrap <p><code>...</code></p> into <pre><code>..</code></pre> for classic editor content.
* If you only use Bricks, you can remove this filter.
*/
add_filter( 'the_content', function ( $content ) {
$pattern = '/<p>\s*<code>(.*?)<\/code>\s*<\/p>/is';
$replacement = '<div class="code-container"><pre><code>$1</code></pre></div>';
return preg_replace( $pattern, $replacement, $content );
}, 20 );
/**
* Core Framework-based styling + theme switching
*/
add_action( 'wp_head', function () {
?>
<style>
:root {
/* Core Framework tokens for wrapper UI */
--rr-code-bg: var(--bg-surface, #f6f6f6);
--rr-code-fg: var(--text-body, #2f3337);
--rr-code-border: color-mix(in oklab, var(--base, #000), transparent 85%);
--rr-btn-bg: var(--primary, #0066cc);
--rr-btn-bg-hover: var(--primary-d-1, #0052a3);
--rr-btn-fg: var(--light, #ffffff);
--rr-btn-border: color-mix(in oklab, var(--primary, #0066cc), transparent 55%);
--rr-radius: var(--radius-s, 8px);
--rr-pad: var(--space-s, 16px);
}
/* Dark mode tuning */
html.cf-theme-dark {
--rr-code-bg: var(--bg-surface, #0d1117);
--rr-code-fg: var(--text-body, #c9d1d9);
--rr-code-border: color-mix(in oklab, var(--base, #fff), transparent 85%);
}
.code-block-wrapper {
position: relative;
margin: var(--space-s, 16px) 0;
}
.code-block-wrapper pre {
margin: 0;
padding: var(--rr-pad);
border-radius: var(--rr-radius);
background: var(--rr-code-bg);
color: var(--rr-code-fg);
border: 1px solid var(--rr-code-border);
overflow-x: auto;
transition: max-height .3s ease;
max-height: 520px;
}
.code-block-wrapper pre.folded {
max-height: 260px;
overflow: hidden;
}
.code-block-wrapper pre.unfolded {
max-height: none;
}
.code-block-wrapper pre code {
font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: clamp(1.2rem, 0.25vw + 1.1rem, 1.4rem);
font-weight: 400;
line-height: 1.6;
padding: 0;
background: transparent !important;
display: block;
}
/* Ensure highlight.js colors show properly */
.code-block-wrapper pre code.hljs {
background: transparent !important;
padding: 0;
}
/* Light mode specific - Stack Overflow theme has good contrast */
html:not(.cf-theme-dark) .code-block-wrapper pre code {
color: #2f3337;
}
/* Dark mode */
html.cf-theme-dark .code-block-wrapper pre code {
color: #c9d1d9;
}
/* Buttons */
.copy-code-btn,
.fold-toggle-btn {
position: absolute;
right: 1.2rem;
padding: .5em .9em;
font-size: 1.2rem;
font-weight: 500;
line-height: 1;
color: var(--rr-btn-fg);
background: var(--rr-btn-bg);
border: 1px solid var(--rr-btn-border);
border-radius: calc(var(--rr-radius) - .2rem);
cursor: pointer;
transition: transform .15s ease, background-color .2s ease, box-shadow .2s ease;
z-index: 10;
}
.copy-code-btn { top: 1.2rem; }
.fold-toggle-btn { bottom: 1.2rem; }
.copy-code-btn:hover,
.fold-toggle-btn:hover {
background: var(--rr-btn-bg-hover);
transform: translateY(-1px);
box-shadow: 0 10px 26px rgba(0,0,0,.18);
}
.copy-code-btn:focus-visible,
.fold-toggle-btn:focus-visible {
outline: 2px solid currentColor;
outline-offset: 2px;
}
@media (max-width: 600px) {
.copy-code-btn,
.fold-toggle-btn {
font-size: 1.1rem;
padding: .45em .8em;
}
}
</style>
<?php
}, 999 );
?>