Introduction
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!
Highlight.js Initialization
First, we’ll use Highlight.js to make your code snippets look great. Highlight.js is a fantastic library that automatically styles your code snippets, making them more readable and aesthetically pleasing.
Step 1: Enqueue Highlight.js Scripts and Styles
To start, we’ll need to load the Highlight.js library and its CSS styles from a CDN. This ensures that your code snippets are styled correctly.
Step 2: Adding Copy Code Button
Next, we enhance the Highlight.js functionality by adding a “Copy Code” button to each code block. This button lets users easily copy code snippets to their clipboard with just one click!
Making it Work
Using a bit of PHP, we can enqueue the necessary scripts and styles, then add a JavaScript snippet that initializes Highlight.js and appends the “Copy Code” button to each code block.
Step 3: Wrap Standalone Code Tags
To ensure all your standalone <code> tags within <p> tags are correctly highlighted, a PHP filter will wrap these within <pre> tags. This is a crucial step for consistent styling.
Step 4: Custom Styles
Finally, we add custom CSS styles. This will style the pre and code elements and the “Copy Code” button, ensuring everything looks clean and professional.
And that’s it! You’ve now enhanced your WordPress site with beautifully highlighted code that’s easy to copy. This improves the aesthetic and enhances user experience by making code snippets more functional and user-friendly.
Code Sample
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
You can also apply this using a functions.php file or a custom plugin.
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 );
?>