WordPress, add click to copy functionality to core code block
Introduction
I’d already added quite a few articles to this site when I realised that I really wanted the ‘click to copy’ functionality applied to the WordPress Gutenberg (Editor) core/code block. I didn’t want to have to add YAP (Yet Another Plugin), nor did I wish to have to re-save any posts
after amends.
There’s always more than one way to do things but the following is how I implemented it.
Example ‘click to copy’ code block
Hover/tap on this code block 👀
Contains CSS, JavaScript and PHP all in one file
For ease of use I’ve added everything in one file (which I named click-to-copy.php
and added to my inc
directory), you may wish to split it up… I’ll leave that to your imagination and how you’ve setup your code base.
Breaking the code down
You can skip to the code below if you want to see it in full before reading the article.
Which Post Types should this be applied to?
I didn’t want this code to apply to every Post Type
so I added an array to check against the page being viewed.
$allowed_post_types = [
'posts',
'my-custom-post-type',
'…',
];
Then check for $allowed_post_types
using the is_singular() function and if there’s a match, fire the code.
if ( is_singular( $allowed_post_types ) ) {…}
ToolTip name strings
You can change these to match your needs and/or language.
$click_to_copy_str = 'Click to Copy';
$copied_str = 'Copied!';
$click_to_copy_str
Text that is displayed when code block is hovered over.$copied_str
Text that is displayed when code block is clicked.
Cascading Style Sheets (CSS)
Fairly straightforward setup, you can change to match your sites design.
.copycode_tt
Styles applied to the ToolTip when the cursor is hovered over the code block..clicked
Styles applied to the ToolTip when the code block is clicked..mouseover_anim
and.mouseout_anim
Animation properties applied to Mouse Over and Mouse Out respectively.@keyframes fadeInAnimation
andfadeOutAnimation
The animation styles.
ToolTip HTML div
<div class="copycode_tt"><?php echo esc_attr( $click_to_copy_str ); ?></div>
This HTML div
is applied via the JavaScript
each time a code block is found on the page. This is what the ToolTip ‘attaches’ to.
JavaScript to apply the ‘click to copy’ functionality
copycode_get_element_position()
Determines where in theDOM
the ToolTop should be placed for each instance of the code block.copycode_apply()
Event listeners forclick
,mouseover
&moueout
.document.querySelector('.copycode_tt')
Selects the ToolTip HTML div (See above.)querySelectorAll('.wp-block-code code')
Selects all code blocks with theCSS
selector.wp-block-code code
.
If you want to learn more about interacting with the clipboard read the MDN documentation as that covers everything nicely.
Call the action function
Last is the call to the add_action
function.
add_action( 'wp_footer', 'barrd_copycode' );
This will add the code to the footer (via the wp_footer()
function) of each Post Type supplied to the allowed post types array.
Putting it all together
/**
* Copy Code Function
*/
function barrd_copycode() {
/**
* Allowed Post Types array
*/
$allowed_post_types = [
'posts',
'my-custom-post-type',
'…',
];
if ( is_singular( $allowed_post_types ) ) {
// ToolTip text strings.
$click_to_copy_str = 'Click to Copy';
$copied_str = 'Copied!';
?>
<style>
.copycode_tt {
background: yellow;
position: absolute;
display: none;
color: #000;
padding: 0 8px;
opacity: 0;
}
.clicked {
background: green;
color: #fff;
}
.mouseover_anim {
animation: fadeInAnimation ease 0.4s forwards;
}
.mouseout_anim {
animation: fadeOutAnimation ease 0.4s forwards;
}
@keyframes fadeInAnimation {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fadeOutAnimation {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
</style>
<!-- ToolTip Div -->
<div class="copycode_tt">
<?php echo esc_attr( $click_to_copy_str ); ?>
</div>
<script>
function copycode_get_element_position(el) {
let rect = el.getBoundingClientRect(),
scrollLeft = window.pageXOffset || document.documentElement.scrollLeft,
scrollTop = window.pageYOffset || document.documentElement.scrollTop;
return { top: rect.top + scrollTop - 30, left: rect.left + scrollLeft }
}
function copycode_apply(element) {
element.addEventListener('click', function () {
event.stopPropagation();
const el = document.createElement('textarea');
el.value = element.textContent;
document.body.appendChild(el);
el.select();
document.execCommand('copy');
document.body.removeChild(el);
copycode_tt.classList.add('clicked');
copycode_tt.innerHTML = '<?php echo esc_attr( $copied_str ); ?>';
});
element.addEventListener('mouseover', function () {
event.stopPropagation();
let position = copycode_get_element_position(element);
copycode_tt.innerHTML = '<?php echo esc_attr( $click_to_copy_str ); ?>';
copycode_tt.classList.remove('mouseout_anim', 'clicked');
copycode_tt.style.display = 'block';
copycode_tt.classList.add('mouseover_anim');
copycode_tt.style.top = position.top + 'px';
copycode_tt.style.left = position.left + 'px';
});
element.addEventListener('mouseout', function () {
event.stopPropagation();
let position = copycode_get_element_position(element);
copycode_tt.classList.remove('mouseover_anim');
copycode_tt.classList.add('mouseout_anim');
});
}
const copycode_tt = document.querySelector('.copycode_tt');
document.querySelectorAll('.wp-block-code code').forEach(function (element) {
copycode_apply(element);
});
</script>
<?php
};
};
add_action( 'wp_footer', 'barrd_copycode' );
Final thoughts
I wanted a system that fitted in with the rest of my site design ethos, big, chunky, easy to use and accessible. This was the result, if you use it in one of your projects please get in touch and let me know the URL
so I can take a look.
As I said at the beginning, there’s always more than one way to do things so I’d be interested to see your approach.
// End of Article
Article Information
Further Reading
- MDN Docs: Interact with the clipboard (developer.mozilla.org)
- WordPress core/code Documentation (wordpress.org)
- WordPress is_singular() Function (developer.wordpress.org)
- WordPress wp_footer() Function (developer.wordpress.org)