使用 ChatGPT 为 WordPress 文章里的引言(或代码)免插件添加「复制」功能

我们收集了一些很有启发性的 Midjourney propmts 提示。为了让读者更容易复制和测试他们感兴趣的 prompts(包括在手机上、没有鼠标),我们想为每段 Prompts 添加一个「复制」按钮。使用 ChatGPT 4,我们仅有几分钟就添加了这个功能,无需插件。

请编写一个 wordpress 函数,实现以下功能:

  1. 如果文中有 blockquote, 请在右下角添加「Copy」按钮。
  2. 用户如果点击「Copy」按钮,会把 blockquote 里的内容复制到剪贴板,同时「Copy」按钮会变成「Done!」该按钮在 2 秒钟之后会重现变为「Copy」,这样,如果用户需要的话,可以重现点击该按钮进行复制。

ChatGPT 立刻给出了下面的代码,只需添加到你的 functions.php 文件即可。或者,你可以使用 Code Snippets 插件来实现(比直接修改 functions.php 更好,以后即使更换主题也不受影响)。此函数使用 JavaScript 来处理复制功能,还包括设置设置按钮样式的 CSS。

function add_copy_button_to_quotes() {
  ?>
  <style>
    .quote-wrapper {
      position: relative;
    }
    .copy-btn {
      position: absolute;
      bottom: 0;
      right: 0;
      background: #0073aa;
      border: none;
      border-radius: 4px;
      color: #ffffff;
      padding: 4px 8px;
      cursor: pointer;
      font-size: 12px;
      transition: background 0.3s;
    }
    .copy-btn:hover {
      background: #006799;
    }
  </style>
  <script>
    document.addEventListener('DOMContentLoaded', function() {
      // Get all quote elements
      const quotes = document.querySelectorAll('blockquote');

      // Iterate over quotes and add a "copy" button to each
      quotes.forEach(quote => {
        const wrapper = document.createElement('div');
        wrapper.classList.add('quote-wrapper');
        quote.parentNode.insertBefore(wrapper, quote);
        wrapper.appendChild(quote);

        const copyBtn = document.createElement('button');
        copyBtn.classList.add('copy-btn');
        copyBtn.textContent = 'Copy';
        wrapper.appendChild(copyBtn);

        // Add click event listener for the "copy" button
        copyBtn.addEventListener('click', () => {
          const tempTextArea = document.createElement('textarea');
          tempTextArea.value = quote.textContent;
          document.body.appendChild(tempTextArea);
          tempTextArea.select();
          document.execCommand('copy');
          document.body.removeChild(tempTextArea);
          copyBtn.textContent = 'Done!';

          // Reset the button text after 2 seconds
          setTimeout(() => {
            copyBtn.textContent = 'Copy';
          }, 2000);
        });
      });
    });
  </script>
  <?php
}
add_action('wp_footer', 'add_copy_button_to_quotes');

此函数在文章中搜索 <blockquote> 元素,并为每个 blockquote 添加一个 container、放置一个「Copy」按钮。 当用户单击该按钮时,它会将 blockquote 内的文本复制到他们的剪贴板,而按钮文本将变为「Done!」,2 秒之后变回「Copy」。

某些 <blockquote> 里可能还有 <cite> 标签(通常用来注名引言的作者),在我们的案例中,这部分内容并不需要复制,因此,我们要求 ChatGPT 排除 <cite> 标签内的内容。新代码如下。

function add_copy_button_to_quotes() {
  ?>
  <style>
    .quote-wrapper {
      position: relative;
    }
    .copy-btn {
      position: absolute;
      bottom: 0;
      right: 0;
      background: #0073aa;
      border: none;
      border-radius: 4px;
      color: #ffffff;
      padding: 4px 8px;
      cursor: pointer;
      font-size: 12px;
      transition: background 0.3s;
    }
    .copy-btn:hover {
      background: #006799;
    }
  </style>
  <script>
    document.addEventListener('DOMContentLoaded', function() {
      // Get all quote elements
      const quotes = document.querySelectorAll('blockquote');

      // Iterate over quotes and add a "copy" button to each
      quotes.forEach(quote => {
        const wrapper = document.createElement('div');
        wrapper.classList.add('quote-wrapper');
        quote.parentNode.insertBefore(wrapper, quote);
        wrapper.appendChild(quote);

        const copyBtn = document.createElement('button');
        copyBtn.classList.add('copy-btn');
        copyBtn.textContent = 'Copy';
        wrapper.appendChild(copyBtn);

        // Add click event listener for the "copy" button
        copyBtn.addEventListener('click', () => {
          // Create a clone of the quote to remove <cite> without affecting the original
          const quoteClone = quote.cloneNode(true);
          const cite = quoteClone.querySelector('cite');
          if (cite) {
            cite.remove();
          }

          const tempTextArea = document.createElement('textarea');
          tempTextArea.value = quoteClone.textContent;
          document.body.appendChild(tempTextArea);
          tempTextArea.select();
          document.execCommand('copy');
          document.body.removeChild(tempTextArea);
          copyBtn.textContent = 'Done!';

          // Reset the button text after 2 seconds
          setTimeout(() => {
            copyBtn.textContent = 'Copy';
          }, 2000);
        });
      });
    });
  </script>
  <?php
}
add_action('wp_footer', 'add_copy_button_to_quotes');

新版本在复制 blockquote 内容之前先创建了一份副本,如果 blockquote 包含 <cite> 标签,它会从克隆中删除这部分内容,这样既可做到复制时排除 <cite> 标签的内容、又不会影响 blockquote 的正本。

如果您还想将「Copy」按钮添加到 code 代码块,请使用以下代码。

function add_copy_button_to_content() {
  ?>
  <style>
    .content-wrapper {
      position: relative;
      display: inline-block;
    }
    .copy-btn {
      position: absolute;
      bottom: 0;
      right: 0;
      background: #0073aa;
      border: none;
      border-radius: 4px;
      color: #ffffff;
      padding: 4px 8px;
      cursor: pointer;
      font-size: 12px;
      transition: background 0.3s;
    }
    .copy-btn:hover {
      background: #006799;
    }
  </style>
  <script>
    document.addEventListener('DOMContentLoaded', function() {
      // Get all quote and code elements
      const contentElements = document.querySelectorAll('blockquote, code');

      // Iterate over content elements and add a "copy" button to each
      contentElements.forEach(content => {
        const wrapper = document.createElement('div');
        wrapper.classList.add('content-wrapper');
        content.parentNode.insertBefore(wrapper, content);
        wrapper.appendChild(content);

        const copyBtn = document.createElement('button');
        copyBtn.classList.add('copy-btn');
        copyBtn.textContent = 'Copy';
        wrapper.appendChild(copyBtn);

        // Add click event listener for the "copy" button
        copyBtn.addEventListener('click', () => {
          // Create a clone of the content to remove <cite> without affecting the original (only for blockquotes)
          let contentClone = content;
          if (content.tagName.toLowerCase() === 'blockquote') {
            contentClone = content.cloneNode(true);
            const cite = contentClone.querySelector('cite');
            if (cite) {
              cite.remove();
            }
          }

          const tempTextArea = document.createElement('textarea');
          tempTextArea.value = contentClone.textContent;
          document.body.appendChild(tempTextArea);
          tempTextArea.select();
          document.execCommand('copy');
          document.body.removeChild(tempTextArea);
          copyBtn.textContent = 'Done!';

          // Reset the button text after 2 seconds
          setTimeout(() => {
            copyBtn.textContent = 'Copy';
          }, 2000);
        });
      });
    });
  </script>
  <?php
}
add_action('wp_footer', 'add_copy_button_to_content');

更新后的功能函修改了选择器,会同时选择 blockquote 和 code 元素。其余逻辑保持不变。函数还新增加了一个条件,只删除 blockquote 里的 cite 标签内容,而不会删除 code 里的 cite 标签内容(不过这其实什么用)。