为Sakurairo主题添加自定义表情功能

您所在的位置:网站首页 push表情包 为Sakurairo主题添加自定义表情功能

为Sakurairo主题添加自定义表情功能

2024-07-16 15:05| 来源: 网络整理| 查看: 265

开篇

一年多前折腾Sakurairo主题的时候,写了一篇关于添加自定义表情文章:Sakurairo主题评论区增加表情包,将原神的表情包添加进评论表情里。又从kanokano那里拿了一些kano的表情包,一起加了进去,她真的好可爱!

当初折腾的时候也意识到了一个问题,维护更新很麻烦。每更新一次主题,就需要手动修改一次主题源代码,添加自定义表情的过程也异常繁琐,需要先把所有表情包的文件名构建成一个数组,再进行调用输出到评论区里。虽然当时写了一个小PHP脚本用来处理表情包文件,一来二去,还是感觉麻烦诸多。最后这个表情也没有继续再维护了。

当时我就想着,能不能给Sakurairo主题添加一个自定义表情的功能,让用户能够使用自定义的表情。奈何技术力有限,最终不了了之。

前几天有个群友提起这个事情,问我主题的自定义表情怎么做,之前参考我的那篇文章做好了,后面更新主题后就炸了,现在想整回来。我听着还挺开心,原来我写的文章还是有人看的啊,这大概就是价值被认可的快乐?

随后将以前做的那篇文章发给了TA,不知现在整得咋样了。

我重温了一遍这篇文章,评论区不乏赞扬之词,死去的记忆突然向我潮涌而来,又想起了折腾主题那段快乐的时光。

然后,我决定要给它画一个句号。

前置条件

我想起了一年多前的想法,想着要不试试就在今天把它实现吧!看了一遍源代码,发现主题的表情系统不算复杂,照猫画虎应该能够搞定。随即思考实现方案,有两点尤为重要:

需要有简单的使用方法 不能影响页面的加载性能

需要有简单的使用方法:如果一个功能使用起来很麻烦,用户肯定不愿去使用。比如需要输入一个包含表情包的数组,又或者手动输入文件名才能正常使用,这是相当反人类的。需要用户做的,只有一个输入文件夹名称的操作就够了。

不能影响页面的加载性能:如果启用了自定义表情功能,页面渲染时间增加了1秒钟,这绝对是一个灾难!性能优化是一门高深的学问,我不认为自己能做好。我希望能尽量让用户无感知渲染时间的增加。众所周知的是,不管对于哪个系统来说,遍历一个文件夹以及子文件夹下的所有文件,这个过程是非常耗时间的,尤其是在文件数量众多的情况下。所以表情文件应该按需遍历,好在WordPress的Transients API可以用来解决这一个问题。可以用Transients将遍历文件夹后的数据存储起来,这是一种临时的存储手段,类似于一个缓存。

开始创建

思路大致理清后,可以上手干活了。

设置选项说明

Sakurairo后台设置选项使用的是Codestar Framework框架,在文档的帮助下,还是比较容易上手的。一共4个设置选项,其中两个是可选项。

评论区表情

这个选项用于控制显示在评论区域面板的表情类别,该项目可多选。如果用户对内置的三种表情不感冒,或者想扩充表情类别,这时自定义表情功能就派上用场了。

如果4种表情都不勾选,则会关闭评论区面板上的表情输入功能,历史评论中的表情仍然能够正常显示,只是新的评论不能再添加表情。

自定义表情栏目名称

顾名思义,就是表情的类别名称,会显示在评论区域表情类别选择栏目上。

上图是以原神作为表情栏目名称

上图是以kano作为表情栏目名称

从最佳实践上看,在启用所有表情类别的情况下,4个汉字的栏目名称,可能会导致移动端横向空间不足。

如果你发现这一问题,这时需要做的是减少一个类别的启用或者缩短表情类别名称,以保证横向空间。桌面端宽度足够,未发现类似问题。

image-20230915030705571

自定义表情的路径

需要明确的是,受制于权限要求,主题能够访问到的文件夹是有限的,这里填入的必须是WordPress wp-content文件夹里uploads文件夹下的目录,填写相对路径。

假如表情文件夹的目录是:/web/site/kanochan.net/wp-content/uploads/smilies

那么需要填写的自定义表情路径是:/smilies

举一个例子:

假如你有一张表情图片可以通过这个URL访问:https://kanochan.net/wp-content/uploads/smilies/ys_bixin.png

那么你需要填写的自定义表情路径是:/smilies

再举一个例子:

假如你的文件夹结构如下所示,表情文件放置在smilies文件夹里

uploads └─ sakurairo_vision └─ @2.4 └─ smilies ├─ kanopng │ ├─ kano_awsl.png │ ├─ kano_biezaiyi.png │ └─ kano_bixin.png ├─ yspng │ ├─ ys_aaaaaa.png │ ├─ ys_anxiang.png │ └─ ys_anzhongguancha.png ├─ ys_yiwen.png ├─ ys_zhenjing.png └─ ys_zuomeng.png

那么需要填写的自定义表情路径是:/sakurairo_vision/@2.4/smilies

其它一些注意事项:

表情文件夹里可以建立子文件夹,方便对表情进行归类存放 表情文件夹(包括子文件夹)下所有文件的文件名,都不能存在重名(即使是扩展名不同) 支持的文件格式有:jpg、jpeg、png、 gif、 svg、 avif、webp,其他的文件格式,都不会被收录进表情列表中 建议表情图片的长宽像素比例为1:1、像素80px * 80px以上,可以带来更好的展示效果 自定义表情代理地址

即常说的CDN地址,本地服务器的目录结构与CDN服务器的目录结构需要一致,否则会404。以下是一个示例:

假如你本地服务器上的表情文件URL是这样的:https://kanochan.net/wp-content/uploads/smilies/ys_bixin.png

你将smilies表情文件夹放到了CDN服务器,获取到的文件路径是这样的:https://cdn.kanochan.net/smilies/ys_bixin.png

那么你需要填入的自定义表情代理地址是:https://contents.kanochan.net

更新自定义表情列表

这个小功能藏在设置选项的介绍里。

image-20230915035154317

基于性能考虑,自定义表情列表一旦建立后,主题就会将其缓存,除非手动更新,否则列表是不会变化的。这个特性带来了一个问题,若是我增加了一些表情包,如何进行列表更新?

更新的原理不复杂,清除已缓存的Transients即可。最初我打算在后台设置面板添加一个按钮,点击后可以通过AJAX来清除Transients,并返回清除结果。可是看了好久Codestar Framework文档,也没能做出来,这是一个不足之处,在看文档的大佬有啥想法吗,恳请指点一二。

当然也可以通过Transients Manager插件清除指定的Transients。但是通过安装插件解决这个问题,与“简单”的理念背道而驰,增加用户的使用门槛,自然不在考虑范围。

退而求次,Codestar Framework的选项描述是可以加入超链接的,可以利用这个功能通过GET调用函数来达到清除指定Transients的目的。当然需要限制在管理员页面,并且验证用户权限。就我个人体验来说,属于能用,但算不上不友好,将就着用吧。

function update_custom_smilies_list() { if (!is_admin() || !current_user_can('manage_options')) { return; } if (!isset($_GET['update_custom_smilies'])) { return; } $transient_name = sanitize_key($_GET['update_custom_smilies']); if ($transient_name === 'true') { delete_transient("custom_smilies_list"); $custom_smilies_list = get_custom_smilies_list(); $much = count($custom_smilies_list); echo '自定义表情列表更新完成!总共有' . $much . '个表情。'; } } update_custom_smilies_list();

点击更新自定义表情列表的超链接后,会跳转到一个新建页面,展示处理结果。因为过程中不涉及到用户手动输入参数,故省去了一些异常处理。

image-20230915135441806

当然这个页面也可以输出一个精美的HTML,列出目前所有的自定义表情,但感觉没什么必要去做。

一些注意事项:

每次更改了自定义表情文件夹后,都需要更新列表 可以在自定义表情文件夹里的任何地方随意添加表情,但添加完一定要记得更新列表,否则新加入的表情会不显示,被删除的表情会404。 添加自定义表情后,我不建议进行删除某个表情图片的操作,除非迫不得已。 更改本地自定义表情文件夹后,如果启用了CDN代理,需要把本地的更改的文件同步到CDN服务器中,保证文件结构一致。 设置选项源代码

语言还没有进行国际化,为了方便理解,先填了中文。

array( 'id' => 'smilies_list', 'type' => 'button_set', 'title' => '评论区表情', 'desc' => __('选择要在评论区输入框显示的表情,全不选为关闭评论输入框表情功能。','sakurairo_csf'), 'multiple' => true, 'options' => array( 'bilibili' => 'BILIBILI表情', 'tieba' => '贴吧表情', 'yanwenzi' => '颜文字', 'custom' => '自定义表情', ), 'default' => array( 'bilibili', 'tieba', 'yanwenzi' ) ), array( 'id' => 'smilies_name', 'type' => 'text', 'title' => '自定义表情栏目名称', 'desc' => __('建议输入少于4个汉字长度,以免引起移动端兼容异常。','sakurairo_csf'), 'dependency' => array( 'smilies_list', 'any', 'custom', '', 'true' ), 'default' => 'custom' ), array( 'id' => 'smilies_dir', 'type' => 'text', 'title' => '自定义表情的路径', 'desc' => __('点击这里更新表情包列表。具体用法参考:','sakurairo_csf'), 'dependency' => array( 'smilies_list', 'any', 'custom', '', 'true' ) ), array( 'id' => 'smilies_proxy', 'type' => 'text', 'title' => '自定义表情代理地址', 'desc' => __('填写表情图片的CDN地址,留空则不启用CDN代理功能。','sakurairo_csf'), 'dependency' => array( array('smilies_list', 'any', 'custom', '', 'true' ), array('smilies_dir', '!=', '', '', 'true') ), ), 评论区面板

这个似乎没啥好介绍的。

$smilies_panel = ''; $bilibili_smilies = ''; $tieba_smilies = ''; $menhera_smilies = ''; $custom_smilies = ''; $bilibili_push_smilies = ''; $tieba_push_smilies = ''; $menhera_push_smilies = ''; $custom_push_smilies = ''; $smilies_list = iro_opt('smilies_list'); if ($smilies_list) { if (in_array('bilibili', $smilies_list)) { $bilibili_smilies = 'bilibili~'; $bilibili_push_smilies = '' . push_bili_smilies() . ''; } if (in_array('tieba', $smilies_list)) { $tieba_smilies = 'Tieba'; $tieba_push_smilies = '' . push_tieba_smilies() . ''; } if (in_array('yanwenzi', $smilies_list)) { $menhera_smilies = '(=・ω・=)'; $menhera_push_smilies = '' . push_emoji_panel() . ''; } if (in_array('custom', $smilies_list)) { $custom_smilies = ' '. iro_opt('smilies_name') .''; $custom_push_smilies = '' . push_custom_smilies() . ''; } switch ($smilies_list[0]) { case "bilibili" : $bilibili_smilies = 'bilibili~'; $bilibili_push_smilies = '' . push_bili_smilies() . ''; break; case "tieba" : $tieba_smilies = 'Tieba'; $tieba_push_smilies = '' . push_tieba_smilies() . ''; break; case "yanwenzi" : $menhera_smilies = '(=・ω・=)'; $menhera_push_smilies = '' . push_emoji_panel() . ''; break; case "custom" : $custom_smilies = ' '. iro_opt('smilies_name') .''; $custom_push_smilies = '' . push_custom_smilies() . ''; break; } $smilies_panel = '

' . __("Click me OωO", "sakurairo")/*戳我试试 OωO*/ . ' ' . __("Woooooow ヾ(≧∇≦*)ゝ", "sakurairo")/*嘿嘿嘿 ヾ(≧∇≦*)ゝ*/ . '

'. $bilibili_smilies .' '. $tieba_smilies .' '. $menhera_smilies .' '. $custom_smilies .' ' . $bilibili_push_smilies . ' ' . $tieba_push_smilies . ' ' . $menhera_push_smilies . ' ' . $custom_push_smilies . ' '; }; 获取自定义表情列表 /** * 通过文件夹获取自定义表情列表,使用Transients来存储获得的列表,除非手动清除,数据永不过期。 * 数据格式如下: * Array * ( * [0] => Array * ( * [path] => C:\xampp\htdocs\wordpress/wp-content/uploads/sakurairo_vision/@2.4/smilies\bilipng\emoji_2233_chijing.png * [little_path] => /sakurairo_vision/@2.4/smilies\bilipng\emoji_2233_chijing.png * [file_url] => http://192.168.233.174/wordpress/wp-content/uploads/sakurairo_vision/@2.4/smilies\bilipng\emoji_2233_chijing.png * [name] => emoji_2233_chijing.png * [base_name] => emoji_2233_chijing * [extension] => png * ) * ... * ) * * @return array */ function get_custom_smilies_list() { $custom_smilies_list = get_transient("custom_smilies_list"); // 检查Transient缓存 if ($custom_smilies_list !== false) { return $custom_smilies_list; // 缓存存在,返回缓存数据 } $custom_smilies_list = array(); $custom_smilies_dir = iro_opt('smilies_dir'); if (!$custom_smilies_dir) { return $custom_smilies_list; // 用户没有输入自定义表情路径,返回空数组 } $custom_smilies_extension = ['jpg', 'jpeg', 'png', 'gif', 'svg', 'avif','webp']; // 限制文件类型 $custom_smilies_path = wp_get_upload_dir()['basedir'] . $custom_smilies_dir; if (!is_dir($custom_smilies_path)) { return $custom_smilies_list; // 拼接出来的路径不是一个文件夹,返回空数组 } $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($custom_smilies_path), RecursiveIteratorIterator::LEAVES_ONLY); // 迭代自定义表情目录文件 foreach ($files as $file) { if ($file->isFile()) { $file_name = $file->getFilename(); //完整的文件名 $file_base_name = pathinfo($file_name, PATHINFO_FILENAME); // 基本文件名 $file_extension = pathinfo($file_name, PATHINFO_EXTENSION); // 文件扩展名 $file_path = $file->getPathname(); // 文件绝对路径 $file_little_path = str_replace(wp_get_upload_dir()['basedir'], '' , $file_path); // 文件相对路径,相对于uploads文件夹 $file_url = wp_get_upload_dir()['baseurl'] . $file_little_path; // 本地文件的URL路径 if (in_array($file_extension, $custom_smilies_extension)) { // 限制文件类型 $custom_smilies_list[] = array( // 存储数据 'path' => $file_path, 'little_path' => $file_little_path, 'file_url' => $file_url, 'name' => $file_name, 'base_name' => $file_base_name, 'extension' => $file_extension ); } } } set_transient("custom_smilies_list", $custom_smilies_list); // 配置Transient缓存 return $custom_smilies_list; } 输出表情列表

这个是照着Sakurairo的表情系统写的,将数据循环写入即可。

$custom_smiliestrans = array(); /** * 输出表情列表 * */ function push_custom_smilies() { global $custom_smiliestrans; // 用于替换评论、文章中的表情符号 $custom_smilies_panel = ''; // 用于输出到评论区表情面板 $custom_smilies_list = get_custom_smilies_list(); if (!$custom_smilies_list) { $custom_smilies_panel = 'File does not exist!'; return $custom_smilies_panel; // 空数组,在评论表情面板提示文件不存在 } $custom_smilies_cdn = iro_opt('smilies_proxy'); foreach ($custom_smilies_list as $smiley) { if ($custom_smilies_cdn) { $smiley_url = $custom_smilies_cdn . $smiley['little_path']; //构建表情文件CDN地址 } else { $smiley_url = $smiley['file_url']; } $custom_smilies_panel = $custom_smilies_panel . ''; $custom_smiliestrans['{{' . $smiley['base_name'] . '}}'] = ''; } return $custom_smilies_panel; } 替换评论、文章中的表情符号 /** * 替换评论、文章中的表情符号 * */ function custom_smilies_filter($content) { push_custom_smilies(); global $custom_smiliestrans; $content = str_replace(array_keys($custom_smiliestrans), $custom_smiliestrans, $content); return $content; } add_filter('the_content', 'custom_smilies_filter'); add_filter('comment_text', 'custom_smilies_filter'); JS端的配合

Sakurairo主题的JavaScript位于:Sakurairo_Scripts

image-20230915145950665

JS端修改的不多,只是做了一个判断,防止表情面板不完全选择输出时产生报错。

const motionEles = [".bili", ".menhera", ".tieba", ".custom"]; function motionSwitch(ele) { for (let i = 0; i < motionEles.length; i++) { let smilies = document.querySelector(motionEles[i] + '-bar'); if (smilies !== null) { smilies.classList.remove('on-hover'); document.querySelector(motionEles[i] + '-container').style.display = 'none'; } } document.querySelector(ele + '-bar').classList.add("on-hover"); document.querySelector(ele + '-container').style.display = 'block'; } 最后 源代码

这个功能预计会在2.6.3版本中合并到Sakurairo里

ea4bf2fe88a2e1888491e6bfa21db4d40e865d9a

bcdc8b0fbcb0b7e6bb077c8de8ebea0c37469f64

参考资料 Codestar Framework Documentation WordPress Developer Resources PHP 手册 ChatGPT 提供了许多帮助


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3