右下角弹窗教程

部署教程

将下方代码放置在主题目录下的function.php或者新建一个func.php文件

// 注册自定义 REST API 接口
function register_hot_comments_endpoint() {
    register_rest_route('myapi/v1', '/hot-comments', array(
        'methods' => 'GET',
        'callback' => 'get_hot_comments',
    ));
}

add_action('rest_api_init', 'register_hot_comments_endpoint');

function get_hot_comments() {
    $comments = get_comments(array(
        'number'  => 50,            // 获取50条最新评论
        'status'  => 'approve',
        'orderby' => 'comment_date',
        'order'   => 'DESC',
    ));

    $data = [];

    if (empty($comments)) {
        return new WP_REST_Response([], 200);
    }

    foreach ($comments as $comment) {
        $avatar_html = zib_get_data_avatar($comment->comment_author_email);
        preg_match('/src=["\'](\/\/[^"\']+)["\']/', $avatar_html, $matches);
        $avatar_url = !empty($matches[1]) ? 'https:' . $matches[1] : '';
        if (!$avatar_url) {
            $avatar_url = get_template_directory_uri() . '/img/avatar-default.png';
        }

        $comment_url = get_comment_link($comment->comment_ID);
        $user_url = get_author_posts_url($comment->user_id);

        $data[] = [
            'post_id'   => $comment->comment_post_ID,
            'author'    => $comment->comment_author,
            'content'   => $comment->comment_content,
            'avatar'    => $avatar_url,
            'url'       => get_permalink($comment->comment_post_ID),
            'comment_url' => $comment_url,
            'user_url'  => $user_url,
        ];
    }

    return new WP_REST_Response($data, 200);
}

如果只希望在首页显示,可以通过后台小工具 → 自定义 HTML,将代码放在首页的任何位置。

如果希望全站显示,则可以将代码放在主题设置中的自定义 HTML

<style>
  #wniui-popup-window {
    min-width: 300px;
    max-width: 500px;
    bottom: 20px;
    right: 20px;
    position: fixed;
    z-index: 1002;
    color: #363636;
    padding: 8px 16px;
    border-radius: 12px;
    transition: opacity 0.3s ease, transform 0.3s ease;
    background-color: rgba(255, 255, 255, 0.85);
    border: 1px solid #e3e8f7;
    max-height: 300px;
    opacity: 0;
    transform: translateY(20px);
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    transition: .3s;
    cursor: pointer;
  }

  #wniui-popup-window:hover {
    border: 1px solid #425AEF;
    transition: .3s;
  }

  #wniui-popup-window.wniui-show {
    opacity: 1;
    transform: translateY(0);
  }

  .wniui-popup-header {
    position: relative;
    display: flex;
    align-items: center;
  }

  .wniui-popup-title {
    font-size: 14px;
    font-weight: bold;
    background: #363636;
    color: #fff;
    padding: 4px 8px;
    border-radius: 4px;
    margin-right: 8px;
    transition: .3s;
  }

  .wniui-popup-title:hover {
    background-color: #423AEF;
    transition: .3s;
  }

  .wniui-popup-author {
    font-size: 14px;
    font-weight: 600;
    color: #363636;
    display: flex;
    justify-content: flex-start;
    align-items: center;
    cursor: pointer;
  }

  .wniui-popup-avatar {
    width: 25px;
    height: 25px;
    border-radius: 50%;
    margin-right: 6px;
    background-color: #f5f6f7;
  }

  .wniui-popup-window-divider {
    width: 100%;
    height: 1px;
    background: #e3e8f7;
    margin: 5px 0;
  }

  .wniui-popup-window-content {
    font-size: 15px;
    word-wrap: break-word;
    max-width: 450px;
    white-space: normal;
    text-overflow: ellipsis;
  }

  .wniui-popup-window-content p {
    margin: 0;
    padding: 0;
    line-height: 1.5;
  }

  @media screen and (max-width: 768px) {
    #wniui-popup-window {
      display: none !important;
    }
  }
  .wniui-popup-author span:hover{
    color:#425AEF;
    transition: .3s;
  }
  svg#popup-link:hover path {
    fill: #425AEF;
    transition: .3s;
  }
</style>

<div id="wniui-popup-window" class="wniui-show-popup-window" style="cursor: pointer;">
  <div class="wniui-popup-header">
    <span class="wniui-popup-title">热评</span>
    <span class="wniui-popup-author"></span>
    <svg id="popup-link" style="transition: .3s; cursor: pointer;display: flex; position: absolute;right:0px;" t="1740280523955" class="icon" viewbox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
      p-id="22033" xmlns:xlink="http://www.w3.org/1999/xlink" width="30" height="30">
      <path
        d="M512.1 137.8c-206.4 0-373.7 167.3-373.7 373.7s167.3 373.7 373.7 373.7 373.7-167.3 373.7-373.7-167.3-373.7-373.7-373.7zM721 508.5L589.2 647c-9.9 10.4-27.4 3.4-27.4-11v-90.9h-1.4c-130.9 0-239.1 58.4-259.2 134.7h-2.3c12.8-133.2 125-237.4 261.5-237.4 0.5 0 0.9 0.1 1.4 0.1V359c0-14.4 17.5-21.4 27.4-11L721 486.6c5.8 6.2 5.8 15.8 0 21.9z"
        fill="#231815" p-id="22034"></path>
    </svg>
  </div>
  <div class="wniui-popup-window-divider"></div>
  <div class="wniui-popup-window-content">
  </div>
</div>



<script>
  class CommentPopup {
    constructor(config) {
      this.config = {
        displayTime: 5000,
        fadeTime: 300,
        retryInterval: 3000,
        apiUrl: 'https://你的域名/wp-json/myapi/v1/hot-comments',
        emojiPath: 'https://你的域名/wp-content/themes/zibll/img/smilies/',
        defaultAvatar: 'https://你的域名/wp-content/themes/zibll/img/avatar-default.png',
        ...config
      };
      
      this.popupTimer = null;
      this.retryTimer = null;
      this.commentData = [];
      this.currentCommentUrl = '';
      
      this.popup = document.getElementById('wniui-popup-window');
      this.bindEvents();
    }

    async init() {
      try {
        await this.fetchComments();
        this.showRandomComment();
      } catch (error) {
        console.error('Failed to fetch comments:', error);
        this.scheduleRetry();
      }
    }

    async fetchComments() {
      const response = await fetch(this.config.apiUrl);
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
      this.commentData = await response.json();
    }

    scheduleRetry() {
      this.retryTimer = setTimeout(() => this.init(), this.config.retryInterval);
    }

    showRandomComment() {
      if (this.commentData.length === 0) return;
      
      const post = this.commentData[Math.floor(Math.random() * this.commentData.length)];
      const content = this.sanitizeContent(decodeURIComponent(post.content));
      
      if (!content) return;

      const data = {
        avatar: post.avatar || this.config.defaultAvatar,
        author: post.author,
        content,
        postUrl: post.url,
        commentUrl: post.comment_url,
        authorUrl: post.user_url || '#'
      };

      this.updatePopup(data);
    }

    sanitizeContent(content) {
      return content.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
    }

    updatePopup(data) {
      clearTimeout(this.popupTimer);
      this.popup.classList.remove('wniui-show');
      this.currentCommentUrl = data.commentUrl;

      setTimeout(() => {
        this.renderPopupContent(data);
        this.popup.classList.add('wniui-show');
        this.scheduleNextComment();
      }, this.config.fadeTime);
    }

    renderPopupContent(data) {
      const authorElement = this.popup.querySelector('.wniui-popup-author');
      authorElement.innerHTML = `
        <img class="wniui-popup-avatar" src="${data.avatar}" alt="avatar" loading="lazy">
        <span onclick="window.location.href='${data.authorUrl}'">${data.author}</span>
      `;
      this.popup.querySelector('.wniui-popup-window-content').innerHTML = `<p>${data.content}</p>`;
    }

    scheduleNextComment() {
      this.popupTimer = setTimeout(() => {
        this.hidePopup();
        this.showRandomComment();
      }, this.config.displayTime);
    }

    hidePopup() {
      this.popup.classList.remove('wniui-show');
    }

    handlePopupClick = (event) => {
      if (event.target.closest('svg#popup-link') || !event.target.closest('.wniui-popup-author')) {
        if (this.currentCommentUrl) {
          window.location.href = this.currentCommentUrl;
        }
      }
    }

    bindEvents() {
      this.popup.addEventListener('click', this.handlePopupClick);
      
      let touchStartY = 0;
      this.popup.addEventListener('touchstart', (e) => {
        touchStartY = e.touches[0].clientY;
      });

      this.popup.addEventListener('touchmove', (e) => {
        const touchDiff = e.touches[0].clientY - touchStartY;
        if (touchDiff > 50) {
          this.hidePopup();
        }
      });
    }

    destroy() {
      clearTimeout(this.popupTimer);
      clearTimeout(this.retryTimer);
      this.popup.removeEventListener('click', this.handlePopupClick);
    }
  }

  const commentPopup = new CommentPopup({
    displayTime: 5000,
    fadeTime: 300,
    retryInterval: 3000
  });

  commentPopup.init();

  window.addEventListener('unload', () => {
    commentPopup.destroy();
  });
</script>

 

请登录后发表评论

    没有回复内容

最近访客
通知图标

欢迎访问春晓的视界