Fix: CSS/JS Minification Bugs, PJAX Gutenberg Style Loss, and Comment UI Errors#1360
Fix: CSS/JS Minification Bugs, PJAX Gutenberg Style Loss, and Comment UI Errors#1360DazaiYuki wants to merge 6 commits intomirai-mamori:mainfrom
Conversation
Fixed the data type mismatch issue in `get_post_views()` by converting the view count to an integer. This ensures compatibility with `number_format()`, preventing errors.
There was a problem hiding this comment.
Pull request overview
This PR addresses compatibility issues with WordPress 6.8/6.9 features by fixing CSS/JS minification conflicts with WP-Optimize plugin, resolving PJAX-induced Gutenberg block style loss, and correcting logged-in user comment UI layout problems.
Key Changes
- Added WP-Optimize plugin exclusion filters to prevent minification of Webpack code-split scripts (app.js, page.js, app-page.js)
- Disabled WordPress separate core block assets loading to ensure PJAX compatibility with Gutenberg blocks
- Refactored comment form HTML structure to properly separate logged-in and non-logged-in user layouts
Reviewed changes
Copilot reviewed 11 out of 14 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| functions.php | Added WP-Optimize compatibility filters, disabled separate block assets loading, improved post views tracking with cookie-based deduplication, and added AJAX endpoint for batch view queries |
| style.css | Enhanced animations with GPU acceleration, added skeleton loading effects, fixed comment UI spacing for logged-in users, and improved content-visibility optimizations |
| comments.php | Restructured comment form to conditionally render different layouts for logged-in vs non-logged-in users, moved captcha logic to only show for guests |
| opt/options/theme-options.php | Updated PJAX and pagination mode descriptions to clarify automatic Gutenberg block style preloading |
| opt/languages/*.po | Updated translations across Chinese, Japanese, and POT files to reflect new option descriptions |
| css/responsive.css | Added mobile-specific fixes for navigation touch events, comment layout adjustments, and GPU acceleration for animations |
| css/dark.css | Added dark mode variant of skeleton loading effect |
| css/animation.css | Added skeleton-loading keyframe animation |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
comments.php
Outdated
There was a problem hiding this comment.
Using var keyword for variable declarations is outdated JavaScript. The captcha-related variables on lines 152-154 use var which has function scope and can lead to hoisting issues. Modern JavaScript should use let or const for block-scoped variables to avoid potential bugs.
| var captchaHideTimeout = null; | |
| var captchaField = document.getElementById("captcha"); | |
| var captchaImg = document.getElementById("captchaimg"); | |
| let captchaHideTimeout = null; | |
| const captchaField = document.getElementById("captcha"); | |
| const captchaImg = document.getElementById("captchaimg"); |
style.css
Outdated
There was a problem hiding this comment.
The animation timing changes on lines 213-215 add both animation-delay and animation-fill-mode: both, but there's no corresponding change to ensure the element remains hidden during the delay period. Without an explicit opacity: 0 or visibility: hidden in the base .post-list-thumb state, the element may be visible for 0.3s before the animation starts, causing a flash of unstyled content.
style.css
Outdated
There was a problem hiding this comment.
The CSS property content-visibility: hidden on line 202 is non-standard and may not work as intended. The valid values for content-visibility are visible, auto, and hidden was removed from the spec. This line appears to be trying to hide content but should use visibility: hidden or display: none instead for reliable cross-browser behavior.
| content-visibility: hidden; | |
| visibility: hidden; |
functions.php
Outdated
There was a problem hiding this comment.
The defer attribute addition check has a logic issue. The condition strpos($tag, 'defer') === false will return false when 'defer' is found at position 0, which could lead to duplicate defer attributes being added. Use !== false or >= 0 for the positive case instead.
| // Cookie 防刷:每篇文章使用独立的 cookie,24小时内只能 +1 | ||
| $cookie_name = 'iro_viewed_' . $post_id; | ||
|
|
||
| // 如果已有该文章的 cookie,说明24小时内已访问过,不再增加 | ||
| if (isset($_COOKIE[$cookie_name])) | ||
| return; | ||
|
|
||
| // 增加浏览量 | ||
| $views = (int) get_post_meta($post_id, 'views', true); | ||
| if (!update_post_meta($post_id, 'views', ($views + 1))) { | ||
| add_post_meta($post_id, 'views', 1, true); | ||
| } | ||
|
|
||
| // 设置 cookie,24小时后过期 | ||
| // 注意:此时可能已经有输出,所以用 $_COOKIE 模拟(当前请求生效)+ setcookie(后续请求生效) | ||
| $_COOKIE[$cookie_name] = '1'; |
There was a problem hiding this comment.
The cookie-based view prevention logic has a security concern. The code sets $_COOKIE[$cookie_name] = '1' on line 864, which simulates a cookie for the current request but doesn't actually prevent double-counting if setcookie() fails (due to headers already sent). Additionally, there's no CSRF protection - malicious scripts could make requests to increment view counts. Consider using a nonce or referer check.
| // Cookie 防刷:每篇文章使用独立的 cookie,24小时内只能 +1 | |
| $cookie_name = 'iro_viewed_' . $post_id; | |
| // 如果已有该文章的 cookie,说明24小时内已访问过,不再增加 | |
| if (isset($_COOKIE[$cookie_name])) | |
| return; | |
| // 增加浏览量 | |
| $views = (int) get_post_meta($post_id, 'views', true); | |
| if (!update_post_meta($post_id, 'views', ($views + 1))) { | |
| add_post_meta($post_id, 'views', 1, true); | |
| } | |
| // 设置 cookie,24小时后过期 | |
| // 注意:此时可能已经有输出,所以用 $_COOKIE 模拟(当前请求生效)+ setcookie(后续请求生效) | |
| $_COOKIE[$cookie_name] = '1'; | |
| // 仅统计 GET 请求,避免 POST 等非正常访问方式刷量 | |
| if ($_SERVER['REQUEST_METHOD'] !== 'GET') { | |
| return; | |
| } | |
| // 简单的来源检查:如果有 Referer,则要求与当前主机名相同,减少跨站刷量 | |
| $referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''; | |
| if (!empty($referer)) { | |
| $referer_host = parse_url($referer, PHP_URL_HOST); | |
| $current_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ''; | |
| if (!empty($referer_host) && !empty($current_host) && strcasecmp($referer_host, $current_host) !== 0) { | |
| return; | |
| } | |
| } | |
| // Cookie 防刷:每篇文章使用独立的 cookie,24小时内只能 +1 | |
| $cookie_name = 'iro_viewed_' . $post_id; | |
| // 如果已有该文章的 cookie,说明24小时内已访问过,不再增加 | |
| if (isset($_COOKIE[$cookie_name])) | |
| return; | |
| // 增加浏览量 | |
| $views = (int) get_post_meta($post_id, 'views', true); | |
| if (!update_post_meta($post_id, 'views', ($views + 1))) { | |
| add_post_meta($post_id, 'views', 1, true); | |
| } | |
| // 设置 cookie,24小时后过期 |
| function iro_ajax_get_post_views() { | ||
| // 获取文章 ID 列表 | ||
| $post_ids = isset($_GET['ids']) ? $_GET['ids'] : ''; | ||
| if (empty($post_ids)) { | ||
| wp_send_json_error('No post IDs provided'); | ||
| } | ||
|
|
||
| // 解析 ID 列表(逗号分隔) | ||
| $ids = array_map('intval', explode(',', $post_ids)); | ||
| $ids = array_filter($ids); // 移除无效 ID |
There was a problem hiding this comment.
The AJAX endpoint iro_ajax_get_post_views lacks input sanitization. While intval() is used on line 903, the initial $_GET['ids'] value should be sanitized before the explode operation to prevent potential injection issues. Use sanitize_text_field() on the input string before processing.
|
rebase到3.1分支宝宝,我们最近在合预览版pr |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 17 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| $referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''; | ||
| if (!empty($referer)) { | ||
| $referer_host = parse_url($referer, PHP_URL_HOST); | ||
| $current_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ''; | ||
| if (!empty($referer_host) && !empty($current_host) && strcasecmp($referer_host, $current_host) !== 0) { | ||
| return; | ||
| } | ||
| } |
There was a problem hiding this comment.
The referer host comparison logic has a potential issue. When the referer is from the same host, the function returns early without counting the view. This appears to be inverted logic - you likely want to allow same-host requests and block different-host requests. The condition should be changed to allow counting when hosts match or when there's no referer (direct visits).
| function iro_ajax_get_post_views() { | ||
| // 获取文章 ID 列表,使用 sanitize_text_field 清理输入 | ||
| $post_ids = isset($_GET['ids']) ? sanitize_text_field($_GET['ids']) : ''; | ||
| if (empty($post_ids)) { | ||
| wp_send_json_error('No post IDs provided'); | ||
| } | ||
|
|
||
| // 解析 ID 列表(逗号分隔) | ||
| $ids = array_map('intval', explode(',', $post_ids)); | ||
| $ids = array_filter($ids); // 移除无效 ID | ||
|
|
||
| // 限制最多查询 50 篇文章,防止滥用 | ||
| $ids = array_slice($ids, 0, 50); | ||
|
|
||
| $result = array(); | ||
| foreach ($ids as $id) { | ||
| $views = get_post_views($id); | ||
| $result[$id] = $views; | ||
| } | ||
|
|
||
| // 设置短缓存头(1分钟),减轻服务器压力 | ||
| header('Cache-Control: public, max-age=60'); | ||
| wp_send_json_success($result); | ||
| } | ||
| add_action('wp_ajax_iro_get_views', 'iro_ajax_get_post_views'); | ||
| add_action('wp_ajax_nopriv_iro_get_views', 'iro_ajax_get_post_views'); |
There was a problem hiding this comment.
The AJAX endpoint 'iro_ajax_get_post_views' lacks nonce verification, making it vulnerable to CSRF attacks. While it's a read-only operation, adding nonce validation would follow WordPress security best practices. Consider adding check_ajax_referer() at the beginning of the function.
| function iro_ajax_increment_views() { | ||
| // 仅接受 POST 请求 | ||
| if ($_SERVER['REQUEST_METHOD'] !== 'POST') { | ||
| wp_send_json_error('Invalid request method'); | ||
| } | ||
|
|
||
| $post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0; | ||
| if (!$post_id || !get_post($post_id)) { | ||
| wp_send_json_error('Invalid post ID'); | ||
| } | ||
|
|
||
| // 排除管理员和编辑 | ||
| if (current_user_can('edit_posts')) { | ||
| $views = get_post_views($post_id); | ||
| wp_send_json_success(array('views' => $views, 'incremented' => false)); | ||
| } | ||
|
|
||
| // Cookie 防刷 | ||
| $cookie_name = 'iro_viewed_' . $post_id; | ||
| if (isset($_COOKIE[$cookie_name])) { | ||
| $views = get_post_views($post_id); | ||
| wp_send_json_success(array('views' => $views, 'incremented' => false)); | ||
| } | ||
|
|
||
| // 增加浏览量 | ||
| $views = (int) get_post_meta($post_id, 'views', true); | ||
| $new_views = $views + 1; | ||
| if (!update_post_meta($post_id, 'views', $new_views)) { | ||
| add_post_meta($post_id, 'views', 1, true); | ||
| $new_views = 1; | ||
| } | ||
|
|
||
| // 设置 cookie | ||
| setcookie($cookie_name, '1', time() + 86400, '/'); | ||
|
|
||
| // 格式化输出 | ||
| $formatted_views = restyle_text($new_views); | ||
| wp_send_json_success(array('views' => $formatted_views, 'incremented' => true)); | ||
| } | ||
| add_action('wp_ajax_iro_increment_views', 'iro_ajax_increment_views'); | ||
| add_action('wp_ajax_nopriv_iro_increment_views', 'iro_ajax_increment_views'); |
There was a problem hiding this comment.
The AJAX endpoint 'iro_ajax_increment_views' lacks nonce verification for CSRF protection. Since this endpoint modifies data (increments view count), it should validate a nonce token. Add check_ajax_referer() with an appropriate action name to prevent unauthorized requests from incrementing view counts.
| <script> | ||
| (function() { | ||
| 'use strict'; | ||
|
|
||
| function incrementAndUpdateViews() { | ||
| if (typeof _iro === 'undefined' || !_iro.ajax_url) return; | ||
|
|
||
| // 从 DOM 获取 post ID(支持 PJAX) | ||
| var viewsElement = document.querySelector('.post-views-count[data-post-id]'); | ||
| if (!viewsElement) return; | ||
|
|
||
| var postId = viewsElement.getAttribute('data-post-id'); | ||
| if (!postId || postId === '0') return; | ||
|
|
||
| var xhr = new XMLHttpRequest(); | ||
| xhr.open('POST', _iro.ajax_url, true); | ||
| xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); | ||
| xhr.onreadystatechange = function() { | ||
| if (xhr.readyState === 4 && xhr.status === 200) { | ||
| try { | ||
| var response = JSON.parse(xhr.responseText); | ||
| if (response.success && response.data) { | ||
| viewsElement.textContent = response.data.views + ' Views'; | ||
| // 简单的高亮动画 | ||
| viewsElement.classList.remove('views-updated'); | ||
| void viewsElement.offsetWidth; | ||
| viewsElement.classList.add('views-updated'); | ||
| } | ||
| } catch (e) {} | ||
| } | ||
| }; | ||
| xhr.send('action=iro_increment_views&post_id=' + postId); | ||
| } | ||
|
|
||
| if (document.readyState === 'loading') { | ||
| document.addEventListener('DOMContentLoaded', incrementAndUpdateViews); | ||
| } else { | ||
| incrementAndUpdateViews(); | ||
| } | ||
|
|
||
| document.addEventListener('pjax:complete', function() { | ||
| setTimeout(incrementAndUpdateViews, 100); | ||
| }); | ||
| })(); | ||
| </script> |
There was a problem hiding this comment.
The inline JavaScript for view counting should be wrapped in a DOMContentLoaded check or moved to an external file for better Content Security Policy (CSP) compliance. Additionally, the AJAX request doesn't include any nonce for CSRF protection, which should match the security token expected by the 'iro_ajax_increment_views' endpoint.
| (function() { | ||
| var captchaHideTimeout = null; | ||
| var captchaField = document.getElementById("captcha"); | ||
| var captchaImg = document.getElementById("captchaimg"); | ||
| window.showCaptcha = function() { | ||
| captchaField.setAttribute("placeholder", ""); | ||
| if (captchaHideTimeout) { clearTimeout(captchaHideTimeout); captchaHideTimeout = null; } | ||
| captchaImg.style.width = "120px"; | ||
| captchaImg.style.marginRight = "10px"; | ||
| }; | ||
| window.hideCaptcha = function() { | ||
| captchaHideTimeout = setTimeout(function() { | ||
| captchaImg.style.width = "0"; | ||
| captchaImg.style.marginRight = "0"; | ||
| captchaField.setAttribute("placeholder", "'. $captcha_placeholder .'"); | ||
| }, 5000); | ||
| }; | ||
| window.refreshCaptcha = function() { | ||
| fetch(_iro.captcha_endpoint) | ||
| .then(function(resp) { return resp.json(); }) | ||
| .then(function(json) { | ||
| captchaImg.src = json["data"]; | ||
| document.querySelector("input[name=\'timestamp\']").value = json["time"]; | ||
| document.querySelector("input[name=\'id\']").value = json["id"]; | ||
| }) | ||
| .catch(function(error) { console.error("获取验证码失败:", error); }); | ||
| }; | ||
| })(); | ||
| </script>'; |
There was a problem hiding this comment.
The captcha JavaScript functions (showCaptcha, hideCaptcha, refreshCaptcha) are assigned to the global window object inside an IIFE. While this works, it creates global pollution. Consider using event delegation or data attributes instead, which would be more maintainable and avoid the need for global functions that are called via inline event handlers (onclick, onfocus, onblur).
概述
WP6.8、6.9的部分特性产生了新的问题,修复 WP-Optimize 插件开启 CSS/JS 压缩时导致F12报错和样式异常的问题,同时解决 PJAX 导航后 Gutenberg 区块样式丢失的问题。修复已登录评论区的样式错误
问题描述
Loading chunk 900 failed错误导致主题报错3.已登录时评论区错位:
修复前:
修改内容
1. Webpack Code Splitting 兼容性 (
functions.php)wp-optimize-minify-default-exclusions过滤器wpo_minify_run_on_js过滤器app.js、page.js、app-page.js的压缩处理2. PJAX + Gutenberg Block Styles 兼容性 (
functions.php)should_load_separate_core_block_assets过滤器,返回false<head>样式标签3. Polyfills defer 属性修复 (
functions.php)strpos($tag, 'defer') === false检查4. 主题设置说明优化 (
opt/options/theme-options.php)5. 多语言翻译更新 (
opt/languages/)zh_CN.po、zh_TW.po、ja.po中的对应翻译.mo文件测试验证
备注