Skip to: Content or Footer

WordPress, add click to copy functionality to core code block

Created on
No updates
Approx ~8 minutes reading time for 1,572 words.

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 and fadeOutAnimation
    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 the DOM the ToolTop should be placed for each instance of the code block.
  • copycode_apply()
    Event listeners for click, mouseover & moueout.
  • document.querySelector('.copycode_tt')
    Selects the ToolTip HTML div (See above.)
  • querySelectorAll('.wp-block-code code')
    Selects all code blocks with the CSS 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

Category: Technical
Topics: #Tech-Stack, #WordPress

Dave Barr

Bristol based Scottish Expat who has 20+ years experience of Web Development and is continually on the look out to improve his skill sets. Learning new and innovative solutions for current requirements in the world of IT, WebDev and eCommerce.

About Dave Barr

Image for Dave Barr
Bristol based Scottish Expat who has 20+ years experience of Web Development and is continually on the look out to improve his skill sets. Learning new and innovative solutions for current requirements in the world of IT, WebDev and eCommerce.

Read more about Dave

Click to Copy