代码高亮插件Crayon Syntax Highlighter在PHP7.4报错解决办法

在新版的WordPress中,系统已经多次提示升级PHP,考虑到新版本更高效更安全,所以决定升级。

可是,升级完成后,网站出现大量报错,报错信息如下:

Warning: preg_replace(): Compilation failed: invalid range in character class at offset 4 in /var/www/wordpress/wp-content/plugins/crayon-syntax-highlighter/crayon_langs.class.php on line 340
 
Warning: preg_replace(): Compilation failed: invalid range in character class at offset 4 in /var/www/wordpress/wp-content/plugins/crayon-syntax-highlighter/crayon_langs.class.php on line 340
 
Warning: preg_replace(): Compilation failed: invalid range in character class at offset 4 in /var/www/wordpress/wp-content/plugins/crayon-syntax-highlighter/crayon_langs.class.php on line 340
 
Warning: preg_replace(): Compilation failed: invalid range in character class at offset 4 in /var/www/wordpress/wp-content/plugins/crayon-syntax-highlighter/crayon_langs.class.php on line 340
 
Warning: preg_replace(): Compilation failed: invalid range in character class at offset 4 in /var/www/wordpress/wp-content/plugins/crayon-syntax-highlighter/crayon_langs.class.php on line 340
 
Warning: preg_replace(): Compilation failed: invalid range in character class at offset 4 in /var/www/wordpress/wp-content/plugins/crayon-syntax-highlighter/crayon_langs.class.php on line 340
 
Warning: preg_replace(): Compilation failed: invalid range in character class at offset 4 in /var/www/wordpress/wp-content/plugins/crayon-syntax-highlighter/crayon_langs.class.php on line 340

继续阅读代码高亮插件Crayon Syntax Highlighter在PHP7.4报错解决办法

ubuntu 18.04完整安装配置WordPress 5.5.3并调优

$ sudo apt-get install apache2

$ sudo apt-get install mysql-server

$ sudo apt-get install mysql-client

$ sudo apt-get install php7.2

$ sudo apt-get install php-gd

$ sudo apt install php-mbstring

$ sudo apt install php-dom

# 如果使用了WP-Statistics统计插件,需要安装依赖
$ sudo apt-get install php7.2-curl

$ sudo apt-get install php7.2-bcmath

# PHP Zip支持,提高网络以及内存压缩工具,提升性能
$ sudo apt-get install php-zip

# PHP图像处理支持,imagick替代默认的GD图像处理,提升图像处理性能
$ sudo apt install php-imagick

# 默认imagick是不启用的,需要手工开启
$ sudo phpenmod imagick

$ sudo a2dismod mpm_prefork

$ sudo a2enmod mpm_event

$ sudo apt-get install libapache2-mod-fastcgi php7.2-fpm

$ sudo service php7.2-fpm restart

$ sudo a2enmod actions fastcgi alias proxy_fcgi

$ sudo apt-get install php-mysql

# 启用 Rewrite 模块,我们后续的WP Super Cache需要这个模块的支持
$ sudo a2enmod rewrite

$ sudo service apache2 restart

# 我们以root连接数据库,我们需要手工创建数据库,否则会出现如下错误:
# “我们能够连接到数据库服务器(这意味着您的用户名和密码正确),但未能选择wordpress数据库。”
$ mysql -u root -p -e "create database wordpress;" 

$ cd /var/www

$ sudo chown -R www-data:www-data wordpress

WordPress配置文件

<VirtualHost *:80>
	# The ServerName directive sets the request scheme, hostname and port that
	# the server uses to identify itself. This is used when creating
	# redirection URLs. In the context of virtual hosts, the ServerName
	# specifies what hostname must appear in the request's Host: header to
	# match this virtual host. For the default virtual host (this file) this
	# value is not decisive as it is used as a last resort host regardless.
	# However, you must set it for any further virtual host explicitly.
	#ServerName www.example.com

	ServerAdmin webmaster@localhost
	#DocumentRoot /var/www/html
	DocumentRoot /var/www/wordpress
	<Directory /var/www/wordpress>
		#Options Indexes FollowSymLinks MultiViews
		Options FollowSymLinks MultiViews
		AllowOverride All
#		Apache 2.2 
#		FCGIWrapper /usr/bin/php5-cgi .php
#		AddHandler fcgid-script .php
#               Options ExecCGI SymLinksIfOwnerMatch
#		Apache 2.4.10
		<FilesMatch \.php$>	
			SetHandler "proxy:unix:/run/php/php7.2-fpm.sock|fcgi://localhost"
		</FilesMatch>
		Order allow,deny
		allow from all
	</Directory>

	# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
	# error, crit, alert, emerg.
	# It is also possible to configure the loglevel for particular
	# modules, e.g.
	#LogLevel info ssl:warn

	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined

	# For most configuration files from conf-available/, which are
	# enabled or disabled at a global level, it is possible to
	# include a line for only one particular virtual host. For example the
	# following line enables the CGI configuration for this host only
	# after it has been globally disabled with "a2disconf".
	#Include conf-available/serve-cgi-bin.conf
</VirtualHost>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

启用`Apache2`的`cache`,`expire`,`gzip`模块,加强服务器性能

$ sudo a2enmod cache

$ sudo a2enmod expires

$ sudo a2enmod deflate

$ sudo service apache2 restart

PHP-FPM进程数的设定,提高响应速度,解决页面加载时候缓慢的问题(如果感觉打开页面缓慢,建议调整下面的配置,这种情况尤其在访问量不大的时候会出现短暂的耗时增大,原因就是php进程被临时创建导致延迟增大

# 增大最大并发进程数量,默认为5 根据需要增大
$ sudo sed -i "s/^pm.max_children = 5/pm.max_children = 20/g" /etc/php/7.2/fpm/pool.d/www.conf

# 增大系统启动初始化的进程数量,默认为 1 根据需要增大
$ sudo sed -i "s/^pm.start_servers = 1/pm.start_servers = 10/g" /etc/php/7.2/fpm/pool.d/www.conf

# 增大保留的最低空闲进程数量,默认为 2 根据需要增大
$ sudo sed -i "s/^pm.min_spare_servers = 2/pm.min_spare_servers = 10/g" /etc/php/7.2/fpm/pool.d/www.conf

# 增大保留的最高空闲进程数量,默认为 3 根据需要增大
$ sudo sed -i "s/^pm.max_spare_servers = 3/pm.max_spare_servers = 20/g" /etc/php/7.2/fpm/pool.d/www.conf

# 配置进程在处理多少个请求之后就退出,避免某些操作导致内存泄漏,及时进行资源回收操作
$ sudo sed -i "s/^#pm.max_requests = 500/pm.max_requests = 5000/g" /etc/php/7.2/fpm/pool.d/www.conf

启用PHP7的opcache配置

######避免PHP信息暴露在http头中
expose_php = Off

######在关闭display_errors后开启PHP错误日志(路径在php-fpm.conf中配置)
log_errors = On

######开启opcache
[opcache]
; Determines if Zend OPCache is enabled
;opcache.enable=0
opcache.enable=1

; The OPcache shared memory storage size.
;opcache.memory_consumption=128
opcache.memory_consumption=256

; The maximum number of keys (scripts) in the OPcache hash table.
; Only numbers between 200 and 1000000 are allowed.
;opcache.max_accelerated_files=10000
opcache.max_accelerated_files=1000000

; When disabled, you must reset the OPcache manually or restart the
; webserver for changes to the filesystem to take effect.
;opcache.validate_timestamps=1
opcache.validate_timestamps=3000

重启服务

$ sudo service php7.2-fpm restart

参考链接


WP Statistics插件在开启缓存功能后无法统计访问量

WP Statistics插件在开启缓存功能后无法统计访问量。

跟踪发现统计访问量使用的url返回401错误,如下:

https://www.mobibrw.com/wp-json/wpstatistics/v1/hit?_=1603432478&_wpnonce=1b5c35aa31&wp_statistics_hit_rest=yes&ua=Mozilla/5.0%20(Macintosh;%20Intel%20Mac%20OS%20X%2010_15_7)%20AppleWebKit/605.1.15%20(KHTML,%20like%20Gecko)%20Version/14.0%20Safari/605.1.15&url=https://www.mobibrw.com/2020/27156&referred=

Failed to load resource: the server responded with a status of 401 (Unauthorized)

比较奇怪的是,如果此时用户登陆,那么反倒不返回任何错误了。

继续阅读WP Statistics插件在开启缓存功能后无法统计访问量

WordPress隐藏前台登录用户名

最近在查看`Limit Login Attempts`日志的时候,发现大量的登陆尝试,关键是登陆使用的用户名是正确的。感到很奇怪,用户名是如何泄漏的呢?

网上搜寻了一下,发现原来用户名是被`WordPress`主动泄漏出来的。

`WordPress`鼠标点击前台用户名,浏览器就会跳转到 https://www.mobibrw.com/author/username 这个链接,这样一来就直接暴露了登陆用户名,哪怕你已经在前台使用了昵称。这是个很大的安全隐患!

后台登陆用户名也可以这样查看到:https://www.mobibrw.com/?author=1,多用户的可以把 1 变为 2、3、4、5 等,就可以在地址栏查看到各个用户名。

为了避免暴露登陆用户名,我们需要配置禁止用户名显示。我们需要在当前使用的主题的`functions.php`中增加如下函数

<?php
/////////////////////隐藏用户名信息相关/////////////////////

  // 隐藏用户名
  add_filter('author_link', function($link, $author_id, $author_nicename){
    $author  = get_userdata($author_id);
  
    if(sanitize_title($author->user_login) == $author_nicename){
      global $wp_rewrite;
      $link  = $wp_rewrite->get_author_permastruct();
      $link  = str_replace('%author%', $author_id, $link);
      $link  = home_url(user_trailingslashit($link));
    }
    return $link;
  }, 10, 3);

  // 原作者页直接404
  add_action('pre_get_posts',  function($wp_query) {
    if($wp_query->is_main_query() && $wp_query->is_author()) {
      if($author_name = $wp_query->get('author_name')){
        $author_name = sanitize_title_for_query($author_name);
        $author = get_user_by('slug', $author_name);
        if($author) {
          if(sanitize_title($author->user_login) == $author->user_nicename){
            $wp_query->set_404();
          }
        } else {
          if(is_numeric($author_name)) {
            $wp_query->set('author_name', '');
            $wp_query->set('author', $author_name);
          }
        }
      }
    }
  });

  //修改body_class
  add_filter('body_class', function($classes) {
    if(is_author()) {
      global $wp_query;
      $author = $wp_query->get_queried_object();
      if(sanitize_title($author->user_login) == $author->user_nicename) {
        $author_class = 'author-'.sanitize_html_class($author->user_nicename, $author->ID);
        $classes = array_diff($classes, [$author_class]);
      }
    }
    return $classes;
  });

  //修改comment_class
  add_filter('comment_class', function ($classes) {
    foreach($classes as $key => $class) {
      if(strstr($class, 'comment-author-')) {
        unset($classes[$key]);
      }
    }
    return $classes;
  });

  //禁用 REST API 过滤部分端点
  //解决通过 https://www.mobibrw.com/wp-json/wp/v2/users 获取用户列表的问题
  add_filter( 'rest_endpoints', function( $endpoints ){
    if ( isset( $endpoints['/wp/v2/users'] ) ) {
        unset( $endpoints['/wp/v2/users'] );
    }
    if ( isset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] ) ) {
        unset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] );
    }
    return $endpoints;
  });

// -- END ---------------------------------------- 
?>

参考链接


WordPress中判断用户是不是管理员

自定义`WordPress`插件的时候,需要判断当前用户的角色是不是网站管理员,如果是管理员的情况下才允许使用插件功能,否则禁止使用。

对于自定义主题的情况,可以使用如下代码:

function is_administrator() {
  // wp_get_current_user函数仅限在主题的functions.php中使用
  $currentUser = wp_get_current_user();

  if(!empty($currentUser->roles) && in_array('administrator', $currentUser->roles)) 
    return True;  // 是管理员
  else
    return False;  // 非管理员
}

对于自定义插件的情况,可以使用如下代码:

function is_administrator() {
  if( is_user_logged_in() ) {
    //用户已登录,检查用户角色
    global $current_user;
    if((!empty($current_user)) && (!empty($current_user->roles)) && in_array('administrator', $current_user->roles)) 
      return True;  // 是管理员
  }
  return False;  // 非管理员
}

更简单的代码如下:

function is_administrator() {
  if( current_user_can( 'manage_options' ) ) { return True; }
  return False;  // 非管理员
}

参考连接


Synology(群晖)常见的配置项以及命令项

Apache2.2 相关配置与常见命令

# 目录相同链接位置 /usr/local/etc/apache22/conf/httpd22.conf
$ sudo vim /volume1/@appstore/Apache2.2/usr/local/etc/apache22/conf/httpd22.conf

# 重启 Apache2.2,有时候重启无效,此时请重启服务器
$ sudo /usr/syno/bin/synopkg restart httpd2.2

# 查看访问日志
$ sudo tail -f /var/log/httpd/apache22-access_log

# 查看错误日志
$ sudo tail -f /var/log/httpd/apache22-error_log

# DSM 7.x 查看错误日志
$ sudo tail -f /var/packages/Apache2.2/var/log/apache22-error_log

Apache2.4 相关配置与常见命令

# 目录相同链接位置 /usr/local/etc/apache24/conf/httpd24.conf
$ sudo vim /volume1/@appstore/Apache2.4/usr/local/etc/apache24/conf/httpd24.conf

# 重启 Apache2.4,有时候重启无效,此时请重启服务器
$ sudo /usr/syno/bin/synopkg restart httpd2.4

# 查看访问日志
$ sudo tail -f /var/log/httpd/apache24-access_log

# 查看错误日志
$ sudo tail -f /var/log/httpd/apache24-error_log

# DSM 7.x 查看错误日志
$ sudo tail -f /var/packages/Apache2.4/var/log/apache24-error_log

Nginx 相关配置与常见命令

# nginx 配置文件
$ sudo vim /etc/nginx/nginx.conf

# nginx 配置信息存储位置
$ sudo ls /usr/local/etc/nginx/conf.d

# 重启nginx
$ sudo synoservicecfg --restart nginx

# 查看日志
$ sudo tail -f /var/log/nginx/error.log

Web Station 相关配置与常见命令

# 默认网页服务器根目录

/volume1/web

继续阅读Synology(群晖)常见的配置项以及命令项

WordPress修改数据库返回数据

有个简单需求,就是 `Wordpress` 多个网站同步数据的情况下,根据网站域名的不同,修改数据库返回的数据。

实现这个的需求就是在当前 `Wordpress` 主题下的 `functions.php` 中实现 `the_post` 拦截函数,在数据库返回的数之后,进行替换。

例子如下:

function replace_serv_domain($post) {
    $local_addr = $_SERVER['SERVER_ADDR'];
    if ('10.105.114.251' == $local_addr) { 
        // 替换服务器的访问地址信息
        $post->post_content = str_ireplace('mobibrw.com', 'miniab.com', $post->post_content);
    }
    return $post;
}
add_action('the_post', 'replace_serv_domain');

这个替换过程只能针对没有使用 `WP Super Cache` 进行缓存的情况,如果已经使用 `WP Super Cache` 进行缓存,那么很可能导致没有及时生效。

如果只是需要替换域名,那么只需要在 wp-config.php 中定义 WP_HOME/WP_SITEURL 两个变量即可实现域名覆盖。

示例参考代码如下:

$HTTP_TYPE = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? 'https://' : 'http://';   

$HOME = $HTTP_TYPE.$_SERVER['HTTP_HOST'].'/wordpress'; #获取当前访问的域名
$SIT_URL = $HTTP_TYPE.$_SERVER['HTTP_HOST'].'/wordpress';

#$HOME = $HTTP_TYPE.$_SERVER['HTTP_HOST'];
#$SIT_URL = $HTTP_TYPE.$_SERVER['HTTP_HOST'];	

define('WP_HOME', $HOME);
define('WP_SITEURL', $SIT_URL);

参考链接


阿里云从ubuntu16.04.5升级到ubuntu 18.04.3后调整PHP 7.0到PHP 7.2

目前使用的阿里云服务器是通过参考 阿里云ECS ubuntu 14.04.5 LTS升级到ubuntu 16.04.2 LTS 升级上来的。

升级之后,默认情况下,依旧使用的是 `ubuntu 16.04.5` 自带的 `PHP 7.0` ,然而 `ubuntu 18.04.3` 系统自带的是 `PHP 7.2` 。我们希望在升级之后的系统上,能启用比较新版本的 `PHP 7.2` 。

其实更关键的是,在 `ubuntu 18.04.3` 系统上, `PHP 7.0` 相关的部分附加组件,比如 `PHP7.0-CURL` 已经没办法通过源安装了 ,安全补丁相关的更新估计也不能及时提供。另外就是较新版本的 `PHP 7.2` 在性能上有不错的提升。

执行如下切换命令(PHP-FPM模式):

$ sudo apt-get install php7.2-fpm

# 备份配置文件
$ sudo mv /etc/php/7.2/fpm/php.ini /etc/php/7.2/fpm/php.ini.bak

# 拷贝配置文件
$ sudo cp /etc/php/7.0/fpm/php.ini /etc/php/7.2/fpm/php.ini

$ sudo systemctl disable php7.0-fpm

# 调整Apache与PHP-FPM通信的端口
$ sudo sed -i "s/php7.0-fpm.sock/php7.2-fpm.sock/g" /etc/apache2/sites-enabled/*.conf

# 禁用旧服务
$ sudo service php7.0-fpm stop

#重启服务
$ sudo service php7.2-fpm restart

$ sudo service apache2 restart

# 如果使用了WP-Statistics统计插件,需要安装依赖
$ sudo apt-get install php7.2-curl
 
$ sudo apt-get install php7.2-bcmath

网站响应速度有明显的提升,以前的卡顿表现明显改善。

参考链接


代码实现WordPress评论回复自动发邮件的功能

评论邮件通知的方法:

对于服务器上需要使用SMTP验证的,需要使用PHPMailer替代默认的WordPress默认的Mail发送邮件时配置SMTP相关信息,如下:

function mailer_config(PHPMailer $mailer){
  $mailer->IsSMTP();
  $mailer->Host = "smtp.sina.com"; // your SMTP server
  $mailer->Port = 465;
  $mailer->SMTPDebug = 0; // write 0 if you don't want to see client/server communication in page
  $mailer->CharSet = "UTF-8";
	
  $wp_email = get_bloginfo ('admin_email');
  /////下面是一些服务器要求的配置
  $mailer->SMTPAuth = true;                      // 允许 SMTP 认证 
  // 如果是用网站的管理员邮箱地址 ,可以如下代码
  $mailer->Username = $wp_email;
  // $mailer->Username = '邮箱用户名';                // SMTP 用户名  即邮箱的用户名 
  // 这里强烈建议使用授权码而不是密码进行认证,授权码可以提供比较高的安全保护
  $mailer->Password = '密码或者授权码';             // SMTP 密码  部分邮箱是授权码(例如163邮箱/新浪邮箱) 
  $mailer->SMTPSecure = 'ssl';                    // 允许 TLS 或者SSL协议 
  //Content
  $mailer->isHTML(true);                         // 是否以HTML文档格式发>送  发送后客户端可直接显示对应HTML内容

  //网站发出的邮件,最好都存档一下
  // $mailer->addCC($wp_email);                // 添加抄送人  
  // $mailer->addCC($wp_email);               // 添加多个抄送人  
  // $mailer->ConfirmReadingTo = $wp_email;   // 添加发送回执邮件地址,即当收件人打开邮件后,会询问是否发生回执  
  $mailer->addBCC($wp_email);  // 秘密抄送到指定邮箱
}
add_action( 'phpmailer_init', 'mailer_config', 10, 1);

注意,目前测试在WordPress 5.8版本,上述的代码会诱发异常

Got error 'PHP message: PHP Fatal error:  Uncaught TypeError: Argument 1 passed to mailer_config() must be an instance of PHPMailer, instance of PHPMailer\\PHPMailer\\PHPMailer given

解决方法为注释掉函数的类型(PHPMailer)声明,如下:

function mailer_config(/*PHPMailer*/ $mailer){
  $mailer->IsSMTP();
  $mailer->Host = "smtp.sina.com"; // your SMTP server
  $mailer->Port = 465;
  $mailer->SMTPDebug = 0; // write 0 if you don't want to see client/server communication in page
  $mailer->CharSet = "UTF-8";
	
  $wp_email = get_bloginfo ('admin_email');
  /////下面是一些服务器要求的配置
  $mailer->SMTPAuth = true;                      // 允许 SMTP 认证 
  // 如果是用网站的管理员邮箱地址 ,可以如下代码
  $mailer->Username = $wp_email;
  // $mailer->Username = '邮箱用户名';                // SMTP 用户名  即邮箱的用户名 
  // 这里强烈建议使用授权码而不是密码进行认证,授权码可以提供比较高的安全保护
  $mailer->Password = '密码或者授权码';             // SMTP 密码  部分邮箱是授权码(例如163邮箱/新浪邮箱) 
  $mailer->SMTPSecure = 'ssl';                    // 允许 TLS 或者SSL协议 
  //Content
  $mailer->isHTML(true);                         // 是否以HTML文档格式发>送  发送后客户端可直接显示对应HTML内容

  //网站发出的邮件,最好都存档一下
  // $mailer->addCC($wp_email);                // 添加抄送人  
  // $mailer->addCC($wp_email);               // 添加多个抄送人  
  // $mailer->ConfirmReadingTo = $wp_email;   // 添加发送回执邮件地址,即当收件人打开邮件后,会询问是否发生回执  
  $mailer->addBCC($wp_email);  // 秘密抄送到指定邮箱
}
add_action( 'phpmailer_init', 'mailer_config', 10, 1);

1.所有回复都发送邮件通知

登陆博客后台,点击“外观”选项卡下的“编辑”选项进入主题编辑界面,在functions.php文件中的<?php和?>之间添加以下函数即可:

/* comment_mail_notify v1.0 by willin kan. (所有回复都发邮件) */
function comment_mail_notify($comment_id) {
  $comment = get_comment($comment_id);
  $parent_id = $comment->comment_parent ? $comment->comment_parent : '';
  $spam_confirmed = $comment->comment_approved;
  if (($parent_id != '') && ($spam_confirmed != 'spam')) {
    /* 对于没有自己邮件服务器的个人网站来说,
       如果需要使用站长自己的邮箱地址发送,
       那么邮箱头必须是登陆账号的邮箱地址,
       否则邮箱服务器(比如新浪)会拒绝发送邮件,
       报错返回邮箱地址跟登陆地址不一致
    */
    $wp_email = get_bloginfo ('admin_email');    
    // $wp_email = 'no-reply@' . preg_replace('#^www\.#', '', strtolower($_SERVER['SERVER_NAME'])); //e-mail 发出点, no-reply 可改为可用的 e-mail.
    $to = trim(get_comment($parent_id)->comment_author_email);
    $subject = '您在 [' . get_option("blogname") . '] 的留言有了回复';
    $message = '
    <div style="background-color:#eef2fa; border:1px solid #d8e3e8; color:#111; padding:0 15px; -moz-border-radius:5px; -webkit-border-radius:5px; -khtml-border-radius:5px;">
      <p>' . trim(get_comment($parent_id)->comment_author) . ', 您好!</p>
      <p>您曾在《' . get_the_title($comment->comment_post_ID) . '》的留言:<br />'
       . trim(get_comment($parent_id)->comment_content) . '</p>
      <p>' . trim($comment->comment_author) . ' 给您的回复:<br />'
       . trim($comment->comment_content) . '<br /></p>
      <p>您可以 <a href="'.get_comment_link($comment).'">点击</a> 查看完整內容</p>
      <p>欢迎再度光临 <a href="'.home_url().'">'.get_option('blogname').'</a></p>
      <p>(此邮件由系统自动发送,请勿回复.)</p>
    </div>';
    $from = "From: \"" . get_option('blogname') . "\" <$wp_email>";
    $headers = "$from\nContent-Type: text/html; charset=" . get_option('blog_charset') . "\n";
    wp_mail( $to, $subject, $message, $headers );
    //echo 'mail to ', $to, '<br/> ' , $subject, $message; // for testing
  }
}
add_action('comment_post', 'comment_mail_notify');
// -- END ----------------------------------------

2.让访客自己选择是否邮件通知

在functions.php文件中的<?php和?>之间添加以下函数,该函数将会在评论框底部生成要不要收回复通知的选项(与主题有关)

/* 开始*/
function comment_mail_notify($comment_id) {
  $admin_notify = '1'; // admin 要不要收回复通知 ( '1'=要 ; '0'=不要 )
  $admin_email = get_bloginfo ('admin_email'); // $admin_email 可改为你指定的 e-mail.
  $comment = get_comment($comment_id);
  $comment_author_email = trim($comment->comment_author_email);
  $parent_id = $comment->comment_parent ? $comment->comment_parent : '';
  global $wpdb;
  if ($wpdb->query("Describe {$wpdb->comments} comment_mail_notify") == '')
    $wpdb->query("ALTER TABLE {$wpdb->comments} ADD COLUMN comment_mail_notify TINYINT NOT NULL DEFAULT 0;");
  if (($comment_author_email != $admin_email && isset($_POST['comment_mail_notify'])) || ($comment_author_email == $admin_email && $admin_notify == '1'))
    $wpdb->query("UPDATE {$wpdb->comments} SET comment_mail_notify='1' WHERE comment_ID='$comment_id'");
  $notify = $parent_id ? get_comment($parent_id)->comment_mail_notify : '0';
  $spam_confirmed = $comment->comment_approved;
  if ($parent_id != '' && $spam_confirmed != 'spam' && $notify == '1') {
    /* 对于没有自己邮件服务器的个人网站来说,
       如果需要使用站长自己的邮箱地址发送,
       那么邮箱头必须是登陆账号的邮箱地址,
       否则邮箱服务器(比如新浪)会拒绝发送邮件,
       报错返回邮箱地址跟登陆地址不一致
    */
    $wp_email = get_bloginfo ('admin_email');     
    // $wp_email = 'no-reply@' . preg_replace('#^www\.#', '', strtolower($_SERVER['SERVER_NAME'])); // e-mail 发出点, no-reply 可改为可用的 e-mail.
    $to = trim(get_comment($parent_id)->comment_author_email);
    $subject = '您在 [' . get_option("blogname") . '] 的留言有了回复';
    $message = '
    <div style="background-color:#eef2fa; border:1px solid #d8e3e8; color:#111; padding:0 15px; -moz-border-radius:5px; -webkit-border-radius:5px; -khtml-border-radius:5px;">
      <p>' . trim(get_comment($parent_id)->comment_author) . ', 您好!</p>
      <p>您曾在《' . get_the_title($comment->comment_post_ID) . '》的留言:<br />'
       . trim(get_comment($parent_id)->comment_content) . '</p>
      <p>' . trim($comment->comment_author) . ' 给您的回复:<br />'
       . trim($comment->comment_content) . '<br /></p>
      <p>您可以 <a href="'.get_comment_link($comment).'">点击</a> 查看完整內容</p>
      <p>欢迎再度光临 <a href="'.home_url().'">'.get_option('blogname').'</a></p>
      <p>(此邮件由系统自动发送,请勿回复.)</p>
    </div>';
    $from = "From: \"" . get_option('blogname') . "\" <$wp_email>";
    $headers = "$from\nContent-Type: text/html; charset=" . get_option('blog_charset') . "\n";
    wp_mail( $to, $subject, $message, $headers );
    //echo 'mail to ', $to, '<br/> ' , $subject, $message; // for testing
  }
}
add_action('comment_post', 'comment_mail_notify');

/* 自动加勾选栏 */
function add_checkbox() {
  echo '<input type="checkbox" name="comment_mail_notify" id="comment_mail_notify" value="comment_mail_notify" checked="checked" style="margin-left:20px;" /><label for="comment_mail_notify">有人回复时邮件通知我</label>';
}
add_action('comment_form', 'add_checkbox');

3.让博客管理员决定什么情况下发邮件

继续阅读代码实现WordPress评论回复自动发邮件的功能

关于WordPress中提示has_cap的问题

WordPress 中不同用户等级拥有不同的操作权限,这给我们的网站安全提供了很大的保障。在 WordPress 2.0 以前,WP 插件中使用数字(用户等级)来标识不同的权限级别。这显然让程序的可阅读性大打折扣。所以从 WordPress 2.0 开始就启用了新的权限标识符号,使用有具体含义的英文字符串,同时保留原来的那一套表示方法。很多插件作者并没有采用新的权限表示方式,因而在开启 WordPress 的调试模式后,用户会看到警告。

>英文版本的警告类似于,

Notice: has_cap was called with an argument that is deprecated since version 2.0! Usage of user levels by plugins and themes is deprecated. Use roles and capabilities instead. in ......\wp-includes\functions.php on line 2998

为了安全,上面的语句中隐去了绝对路径而代之以省略号。

中文版本的警告类似于,

Notice: 自 2.0 版本起,已不建议给 has_cap 传入一个参数!插件和主题中,用户等级的使用已不被支持。请换用角色和权限。 in ....../wp-includes/functions.php on line 2998

可以看到,只是“不建议”,并不是完全不能用了。

要解决这个问题,只需要将插件(也许还包括某些主题)中用到的权限声明的表示方式替换为新的方式就可以了。

1. 定位需要改写的语句

首先要定位到需要改写的语句,这是个比较麻烦的任务。

从上面的警告信息中并不能直接知道是哪个文件调用了 functions.php 中的 has_cap 函数。所以这里只是给个思路,无法给出明确的方法。

对于插件,一般是因为插件需要在 WordPress 的管理后台创建插件的设置页面时进行权限声明的。比如在 WordPress Revision 插件中遇到的情况就是这样。出现这种情况的标志性语句是,

add_options_page

只要在插件源文件中搜索 add_options_page 关键词即可定位。

如果不是这种情况,那就可以挨个儿禁用 WP 中的插件,同时刷新页面以确定是否是当前插件造成的。如果恰好发现该警告信息不再提示了,就说明是当前的插件。然后在该插件的源文件中去找相关的语句。

另外,还可以通过在 WP 后台中操作时出现错误提示的路径信息来缩小检查范围。如果有什么需要,可以留言咨询。

2. 改写表达方式

如果定位到了出问题的 PHP 语句,改写表达方式就很简单了。下面一节介绍了 WordPress 中新旧角色权限表达方式的对比。只需要将原来的表示用户级别的数字改成新的表示权限的字符串就可以了。

例如,原来的 PHP 语句为,

add_options_page('Delete-Revision', 'Delete-Revision',8, basename(__FILE__), 'my_options_delete_revision');

该语句因为要在 WordPress 后台添加一个插件的“选项”页面,因而需要用到 WordPress 中的第 8 级权限。查到对应的新的权限字符串为 'manage_options'。对应修改为,

add_options_page('Delete-Revision', 'Delete-Revision', 'manage_options', basename(__FILE__), 'my_options_delete_revision');

只需要改其中那个数字 8,别的不需要动。

应该注意的是,根据 PHP 的规则,传递的参数如果是整型数字,可以不用加单引号,但是改成字符串之后,我们需要用英文半角的单引号将该字符串包起来。

3. 新旧权限表示方式对照

WordPress Codex 中有关于旧版本数字式用户级别和新的字符串式权限声明的详细说明可供参考。

在数字式用户级别页面的 3.12 User Level Capability Table 表格中列出了 11 个用户级别对应的权限。而在字符串式权限声明页面中 3.8 Capability vs. Role Table 一节里列举了所有权限字符串所代表的权限级别(对应于超级管理员、管理员等)。

原先的数字式级别与新的字符串式权限之间并不是一一对应的。具体应该将数字换成哪个字符串需要仔细斟酌。可能还需要根据在本文第 1 小节中定位出的 PHP 语句来辅助判断。原则上,权限在够用的前提下越小越好

例如,前面的例子中需要增加 options 页面,那肯定是管理员级别的权限。增加 options 页面的目的就是保存该插件的设置信息,这些信息是需要写入到 WordPress 数据库的 options 表中的。所以,可以确定为 manage_options 这个字符串。

在 Capabilities 一节中详细解释了各个字符串所代表的操作权限的范围。而在 User Levels 一节中则给出了旧式数字用户等级所对应的权限范围,方便缩小查找权限字符串的范围。8-10 级对应于管理员,3-7 级对应于编辑,2 级是作者,1 级是贡献者,0 级是权限最低的订阅者。

参考链接


关于 WP 中提示 has_cap 的问题