去年开发了一款站长社区的 WordPress 主题,主题君用纯代码做了 WordPres 用户积分系统,答应过宁总要把教程写出来的,今天算是有时间整理了。
首先声明:核心代码搬运了 ashuwp 的教程,然后自己集成了一些自己的代码,代码比较复杂,没有一定基础的朋友不要轻易尝试。
整理思路:
1. 需要准备两个数据表。
(1) 积分动态表,用来记录所有用户的积分增减情况。
(2) 用户积分总表,用来记录用户的积分总量,当然用户积分总数可以记录到 usermeta 数据表中,所以这个表不是必须的。
2. 后台需要 3 个页面。
(1) 积分动态,从“积分动态表”中获取数据,展示用户积分动态。
(2) 用户积分,从“用户积分表”中获取数据,方便查看用户的积分总量。
(3) 积分增减页面,用于给用户增减积分。
下面教程开始吧:
1. 积分动态表 points_activity 中的字段有 id,用户 id,积分(异动数),描述,余额,时间。
2. 用户积分表 points 中的字段就两个:用户 id,积分数。
//在第一次启用主题时执行。
function ashuwp_load_theme() {
global $pagenow;
if ( is_admin() && 'themes.php' == $pagenow && isset( $_GET['activated'] ) ){
ashuwp_points_install();
}
}
add_action( 'load-themes.php', 'ashuwp_load_theme' );
//新建数据表points_activity和points
function ashuwp_points_install(){
global $wpdb;
$table_name = $wpdb->prefix . 'points_activity'; //积分动态表
$table_name2 = $wpdb->prefix . 'points'; //积分汇总表
$charset_collate = $wpdb->get_charset_collate();
if( $wpdb->get_var("SHOW TABLES LIKE '$table_name'") != $table_name ) :
$sql = " CREATE TABLE `".$table_name."` (
`id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`user_id` BIGINT(40),
`points` INT NOT NULL,
`description` longtext,
`balance` INT NOT NULL,
`date` DATETIME NOT NULL
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
endif;
if( $wpdb->get_var("SHOW TABLES LIKE '$table_name2'") != $table_name2 ) :
$sql2 = " CREATE TABLE `".$table_name2."` (
`user_id` BIGINT(40) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`points` INT NOT NULL
) $charset_collate;";
dbDelta($sql2);
endif;
}
//根据用户id获取某个用户的积分数
function ashuwp_get_user_points($user_id){
global $wpdb;
$user = get_user_by('ID', $user_id);
if(!$user){
return 0;
}
$points_table = $wpdb->prefix . 'points';
$sql = "select points from ".$points_table." where user_id={$user_id}";
$result = $wpdb->get_var($sql);
if(!$result){
return 0;
}else{
return $result;
}
}
//更新(新增)用户积分.
function ashuwp_update_user_points($user_id, $new_points){
global $wpdb;
$user = get_user_by('ID', $user_id);
if(!$user){
$msg = array(
'state' => 'error',
'msg' => 'User Error',
);
return $msg;
}
if( !is_numeric($new_points)|| $new_points<0){
$msg = array(
'state' => 'error',
'msg' => 'Points not number or points error',
);
return $msg;
}
$points_table = $wpdb->prefix . 'points';
$points_exist = $wpdb->get_var( "select count(*) from {$points_table} where user_id='{$user_id}'" );
if($points_exist){
$sql = "update {$points_table} set points='{$new_points}' where user_id='{$user_id}'";
}else{
$sql = "insert into {$points_table} ( user_id, points ) values( '{$user_id}', '{$new_points}' )";;
}
$result = $wpdb->query($sql);
if($result){
$msg = array(
'state' => 'succeed',
'msg' => 'Points Updated.',
);
return $msg;
}else{
$msg = array(
'state' => 'error',
'msg' => 'Points update failed.',
);
return $msg;
}
}
//从用户积分表获取数据,后台积分汇总页面需要获取数据。
function ashuwp_get_points( $args=array() ){
global $wpdb;
$defaults = array(
'per_page' => '50',
'paged' => '1',
);
$args = wp_parse_args( $args, $defaults );
$page = (int)$args['paged'];
$per_page = (int)$args['per_page'];
if(!$page){
$page = 1;
}
if(!$per_page){
$per_page = 50;
}
$begin = $per_page*($page-1);
$end = $per_page*$page;
$points_table = $wpdb->prefix . 'points';
$sql = "select * from $points_table order by user_id asc limit $begin,$end";
$results = $wpdb->get_results($sql,'ARRAY_A');
return $results;
}
//统计数据条数,后台积分汇总页面需要获取数据。
function ashuwp_count_points(){
global $wpdb;
$points_table = $wpdb->prefix . 'points';
$sql = "select count(*) from $points_table";
$results = $wpdb->get_var($sql);
return $results;
}
然后是对积分动态表的操作仅需要增加即可,不需要删除。
/*增加入一条积分动态*/
function ashuwp_add_points_activity( $args=array() ){
global $wpdb;
$defaults = array(
'user_id' => '',
'action' => '',
'points' => '',
'description' => '',
'date' => ''
);
$args = wp_parse_args( $args, $defaults );
//判断用户id是否合法
$user = get_user_by('ID', $args['user_id']);
if(!$user){
$msg = array(
'state' => 'error',
'msg' => 'User Error',
);
return $msg;
}
//仅增加和减少两种操作。
if( !in_array( $args['action'], array( 'add', 'reduce' ) )){
$msg = array(
'state' => 'error',
'msg' => 'Operate Error',
);
return $msg;
}
//检测积分异动数是否合法
if( !is_int($args['points']) ){
$msg = array(
'state' => 'error',
'msg' => 'Points Error',
);
return $msg;
}
//处理描述
$args['description'] = sanitize_text_field($args['description']);
//处理异动数,和计算余额
$old_points = (int)ashuwp_get_user_points($args['user_id']);
if($args['action']=='add'){
$balance = $old_points+$args['points'];
$change = $args['points'];
if($balance!=$old_points){
//将新余额更新到用户积分表。
$update = ashuwp_update_user_points($args['user_id'],$balance);
}
}
if($args['action']=='reduce'){
$balance = $old_points-$args['points'];
$change = -$args['points']; //若是减少,数据库中保存为负数。
if($balance!=$old_points){
$update = ashuwp_update_user_points($args['user_id'],$balance);
}
}
if( ($balance!=$old_points) && $update['state'] != 'succeed' ){
$msg = array(
'state' => 'error',
'msg' => $update['msg'],
);
return $msg;
}
$table_name = $wpdb->prefix . 'points_activity';
//插入数据
$args['date'] = date( "Y-m-d H:i:s", time());
$sql = "insert into $table_name ( user_id, points, description, balance, date ) values( '{$args['user_id']}', '{$change}', '{$args['description']}', '{$balance}', '{$args['date']}' )";
$result = $wpdb->query($sql);
if($result){
$msg = array(
'state' => 'succeed',
'msg' => 'succeed!',
);
return $msg;
}else{
//若动态插入失败,将用户积分表回滚。
ashuwp_update_user_points($args['user_id'],$old_points);
$msg = array(
'state' => 'error',
'msg' => 'Insert Error',
);
return $msg;
}
}
/*从积分动态表中获取数据,后台页面中需要。
* 需支持条件查询方便后台管理。
*/
function ashuwp_get_points_activity( $args=array() ){
global $wpdb;
$defaults = array(
'user_id' => '',
'per_page' => '50',
'paged' => '1',
'action' => ''
);
$args = wp_parse_args( $args, $defaults );
//处理页码
$page = (int)$args['paged'];
$per_page = (int)$args['per_page'];
if(!$page){
$page = 1;
}
if(!$per_page){
$per_page = 50;
}
$begin = $per_page*($page-1);
$end = $per_page*$page;
$table_name = $wpdb->prefix . 'points_activity';
$sql = "select * from $table_name where 1=1 ";
//查询用户id
if($args['user_id']!=''){
$user_id = (int)$args['user_id'];
$sql .= "and user_id='{$user_id}' ";
}
//查询操作种类
if( in_array( $args['action'], array( 'add', 'reduce', 'remain' ) ) ){
if($args['action']=='add'){
$sql .= "and points>0 ";
}
if($args['action']=='reduce'){
$sql .= "and points<0 ";
}
if($args['action']=='remain'){
$sql .= "and points=0 ";
}
}
$sql .= "order by id desc limit $begin,$end";
$results = $wpdb->get_results($sql,'ARRAY_A');
return $results;
}
/*统计积分动态的记录数
* 加入统计条件方便后台管理
*/
function ashuwp_count_points_activity( $args=array() ){
global $wpdb;
$defaults = array(
'user_id' => '',
'action' => ''
);
$args = wp_parse_args( $args, $defaults );
$table_name = $wpdb->prefix . 'points_activity';
$sql = "select count(*) from $table_name where 1=1 ";
//统计用户
if($args['user_id']!=''){
$user_id = (int)$args['user_id'];
$sql .= "and user_id='{$user_id}' ";
}
//统计操作
if( in_array( $args['action'], array( 'add', 'reduce', 'remain' ) ) ){
if($args['action']=='add'){
$sql .= "and points>0 ";
}
if($args['action']=='reduce'){
$sql .= "and points<0 ";
}
if($args['action']=='remain'){
$sql .= "and points=0 ";
}
}
$results = $wpdb->get_var($sql);
return $results;
}
1. 积分动态页面。
后台页面设计到 class-wp-list-table 类的应用,就不一一加注释了。
if(!class_exists('WP_List_Table')) {
require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
}
class Ashuwp_Points_Activity_Table extends WP_List_Table {
function __construct(){
parent::__construct( array(
'singular' => 'Points Activity',
'plural' => 'Points Activity',
'ajax' => false
) );
}
function column_default( $item, $column_name ) {
switch ( $column_name ){
case 'id':
case 'user':
case 'points':
case 'balance':
case 'description':
case 'date':
return $item[ $column_name ];
default:
return print_r($item,true);
}
}
function get_columns() {
$columns = array(
'id' => 'ID',
'user' => 'User',
'points' => 'Points',
'balance' => 'Balance',
'description' => 'Description',
'date' => 'Date',
);
return $columns;
}
function format_activity( $datas ) {
$return_datas = array();
foreach( $datas as $data ){
$user = get_user_by('id', $data['user_id']);
$item_array = array();
$item_array['id'] = $data['id'];
$item_array['user'] = $user->user_login;
if($data['points']<0){
$item_array['points'] = '<span class="reduce">'.$data['points'].'</span>';
}elseif($data['points']>0){
$item_array['points'] = '<span class="add">+'.$data['points'].'</span>';
}else{
$item_array['points'] = '<span class="remain">'.$data['points'].'</span>';
}
$item_array['description'] = $data['description'];
$item_array['balance'] = $data['balance'];
$item_array['date'] = $data['date'];
$return_datas[] = $item_array;
}
return $return_datas;
}
function prepare_items() {
$this->_column_headers = $this->get_column_info();
$per_page = $this->get_items_per_page( 'customers_per_page', 50 );
$current_page = $this->get_pagenum();
$total_items = 0;
$args = array(
'per_page' => $per_page,
'paged' => $current_page,
);
if( isset( $_GET['user_name'] ) && !empty( trim($_GET['user_name']) ) ){
$user = get_user_by( 'login', trim($_GET['user_name']) );
if( !empty($user)){
$args['user_id'] = $user->ID;
}
}
if( isset( $_GET['action_name'] ) && !empty( trim($_GET['action_name']) ) ){
if( in_array( $_GET['action_name'], array( 'add', 'reduce', 'remain' ) ) ){
$args['action'] = $_GET['action_name'];
}
}
$total_items = ashuwp_count_points_activity($args);
$datas = ashuwp_get_points_activity($args);
$this->items = $this->format_activity($datas);
$this->set_pagination_args( array(
'total_items' => $total_items,
'per_page' => $per_page,
'total_pages' => ceil($total_items/$per_page)
) );
}
}
class ashuwp_points_activity_admin {
static public $instance;
public $points_activity_obj;
private function __construct(){
add_filter( 'set-screen-option', array( $this, 'set_screen' ), 10, 3 );
add_action( 'admin_menu', array( $this, 'ashuwp_points_activity_menu') );
}
private function __clone() {
}
function ashuwp_points_activity_menu() {
//svg图
$dollor_ico = '';
//建立积分动态页面
$hook = add_menu_page( 'Points Activity', 'Points Activity', 'manage_options', 'points_activity', array(&$this, 'points_activity_list'),'data:image/svg+xml;base64,'.$dollor_ico, 9);
add_action( "load-$hook", array( $this, 'screen_option' ) );
}
function set_screen( $status, $option, $value ) {
return $value;
}
function screen_option() {
$option = 'per_page';
$args = array(
'label' => 'Customers',
'default' => 30,
'option' => 'customers_per_page'
);
add_screen_option( $option, $args );
$this->points_activity_obj = new Ashuwp_Points_Activity_Table();
}
function points_activity_list(){
$all = ashuwp_count_points_activity();
$points_add = ashuwp_count_points_activity( array( 'action'=>'add' ) );
$points_reduce = ashuwp_count_points_activity( array( 'action'=>'reduce' ) );
$points_remain = ashuwp_count_points_activity( array( 'action'=>'remain' ) );
?>
<div class="wrap">
<h1 class="wp-heading-inline">Points Activity</h1>
<a href="<?php echo admin_url( 'admin.php?page=points_activity_add' ); ?>" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="page-title-action">Add/Reduce</a>
<?php
if ( ! empty( $_GET['user_name'] ) ) {
printf( '<span class="subtitle">' . __('Search results for “%s”') . '</span>', esc_html( $_GET['user_name'] ) );
}
?>
<hr class="wp-header-end">
<ul class="subsubsub">
<?php
if( !empty( $_GET['action_name'] ) && in_array( trim($_GET['action_name']), array( 'add', 'reduce', 'remain' ) ) ){
$now = trim($_GET['action_name']);
}else{
$now = 'all';
}
$current = 'class="current"';
?>
<li class="all"><a <?php if($now=='all'){ echo $current; } ?> href="<?php echo admin_url( 'admin.php?page=points_activity' ); ?>" rel="external nofollow" >All<span class="count">(<?php echo $all; ?>)</span></a> |</li>
<li class="add"><a <?php if($now=='add'){ echo $current; } ?> href="<?php echo admin_url( 'admin.php?page=points_activity&action_name=add' ); ?>" rel="external nofollow" >Add<span class="count">(<?php echo $points_add; ?>)</span></a> |</li>
<li class="reduce"><a <?php if($now=='reduce'){ echo $current; } ?> href="<?php echo admin_url( 'admin.php?page=points_activity&action_name=reduce' ); ?>" rel="external nofollow" >Reduce<span class="count">(<?php echo $points_reduce; ?>)</span></a> |</li>
<li class="remain"><a <?php if($now=='remain'){ echo $current; } ?> href="<?php echo admin_url( 'admin.php?page=points_activity&action_name=remain' ); ?>" rel="external nofollow" >Remain<span class="count">(<?php echo $points_remain; ?>)</span></a></li>
</ul>
<form id="points-activity-filter" method="get" action="">
<style>
th.column-id,
td.column-id,
th.column-user,
td.column-user,
th.column-points,
td.column-points,
th.column-balance,
td.column-balance {
width:10%;
}
.column-points .add {
color:#46b450;
}
.column-points .reduce {
color:#e74c3c;
}
</style>
<p class="search-box">
<label class="screen-reader-text" for="code-search-input">User Search</label>
<input type="search" id="code-search-input" name="user_name" value="" />
<?php submit_button( 'Search', 'button', false, false, array('id' => 'search-submit') ); ?>
<input type="hidden" name="page" value="points_activity" />
</p>
<?php
$this->points_activity_obj->prepare_items();
$this->points_activity_obj->display();
?>
</form>
</div>
<?php
}
public static function get_instance() {
if ( ! isset( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
}
ashuwp_points_activity_admin::get_instance();
2. 用户积分页面
与积分动态页面类似,用户积分页面也需要用表格展示,也不一一注释。
if(!class_exists('WP_List_Table')) {
require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
}
class Ashuwp_User_Points_Table extends WP_List_Table {
function __construct(){
parent::__construct( array(
'singular' => 'User Points',
'plural' => 'User Points',
'ajax' => false
) );
}
function column_default( $item, $column_name ) {
switch ( $column_name ){
case 'user_id':
case 'user_login':
case 'points':
return $item[ $column_name ];
default:
return print_r($item,true);
}
}
function get_columns() {
$columns = array(
'user_id' => 'User ID',
'user_login' => 'User Name',
'points' => 'Points',
);
return $columns;
}
function format_datas( $datas ) {
$return_datas = array();
foreach( $datas as $data ){
$user = get_user_by('id', $data['user_id']);
$item_array = array();
$item_array['user_id'] = $data['user_id'];
$item_array['user_login'] = $user->user_login;
$item_array['points'] = $data['points'];
$return_datas[] = $item_array;
}
return $return_datas;
}
function prepare_items() {
$this->_column_headers = $this->get_column_info();
$per_page = $this->get_items_per_page( 'customers_per_page', 50 );
$current_page = $this->get_pagenum();
$total_items = 0;
$args = array(
'per_page' => $per_page,
'paged' => $current_page,
);
$total_items = ashuwp_count_points();
$datas = ashuwp_get_points($args);
$this->items = $this->format_datas($datas);
$this->set_pagination_args( array(
'total_items' => $total_items,
'per_page' => $per_page,
'total_pages' => ceil($total_items/$per_page)
) );
}
}
class ashuwp_user_points_admin {
static public $instance;
public $user_points_obj;
private function __construct(){
add_filter( 'set-screen-option', array( $this, 'set_screen' ), 10, 3 );
add_action( 'admin_menu', array( $this, 'ashuwp_user_points_menu') );
}
private function __clone() {
}
function ashuwp_user_points_menu() {
$hook = add_submenu_page('points_activity', 'User Points', 'User Points', 'manage_options', 'user_points', array(&$this, 'user_points'));
add_action( "load-$hook", array( $this, 'screen_option' ) );
}
function set_screen( $status, $option, $value ) {
return $value;
}
function screen_option() {
$option = 'per_page';
$args = array(
'label' => 'Customers',
'default' => 30,
'option' => 'customers_per_page'
);
add_screen_option( $option, $args );
$this->user_points_obj = new Ashuwp_User_Points_Table();
}
function user_points(){
$all = ashuwp_count_points();
?>
<div class="wrap">
<h1 class="wp-heading-inline">User Points</h1>
<a href="<?php echo admin_url( 'admin.php?page=points_activity_add' ); ?>" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="page-title-action">Add/Reduce</a>
<hr class="wp-header-end">
<ul class="subsubsub">
<li class="all"><a class="current" href="<?php echo admin_url( 'admin.php?page=user_points' ); ?>" rel="external nofollow" rel="external nofollow" >All<span class="count">(<?php echo $all; ?>)</span></a></li>
</ul>
<form id="points-activity-filter" method="get">
<?php
$this->user_points_obj->prepare_items();
$this->user_points_obj->display();
?>
</form>
</div>
<?php
}
public static function get_instance() {
if ( ! isset( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
}
ashuwp_user_points_admin::get_instance();
3. 积分增减页面
if(!class_exists('WP_List_Table')) {
require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
}
class Ashuwp_User_Points_Table extends WP_List_Table {
function __construct(){
parent::__construct( array(
'singular' => 'User Points',
'plural' => 'User Points',
'ajax' => false
) );
}
function column_default( $item, $column_name ) {
switch ( $column_name ){
case 'user_id':
case 'user_login':
case 'points':
return $item[ $column_name ];
default:
return print_r($item,true);
}
}
function get_columns() {
$columns = array(
'user_id' => 'User ID',
'user_login' => 'User Name',
'points' => 'Points',
);
return $columns;
}
function format_datas( $datas ) {
$return_datas = array();
foreach( $datas as $data ){
$user = get_user_by('id', $data['user_id']);
$item_array = array();
$item_array['user_id'] = $data['user_id'];
$item_array['user_login'] = $user->user_login;
$item_array['points'] = $data['points'];
$return_datas[] = $item_array;
}
return $return_datas;
}
function prepare_items() {
$this->_column_headers = $this->get_column_info();
$per_page = $this->get_items_per_page( 'customers_per_page', 50 );
$current_page = $this->get_pagenum();
$total_items = 0;
$args = array(
'per_page' => $per_page,
'paged' => $current_page,
);
$total_items = ashuwp_count_points();
$datas = ashuwp_get_points($args);
$this->items = $this->format_datas($datas);
$this->set_pagination_args( array(
'total_items' => $total_items,
'per_page' => $per_page,
'total_pages' => ceil($total_items/$per_page)
) );
}
}
class ashuwp_user_points_admin {
static public $instance;
public $user_points_obj;
private function __construct(){
add_filter( 'set-screen-option', array( $this, 'set_screen' ), 10, 3 );
add_action( 'admin_menu', array( $this, 'ashuwp_user_points_menu') );
}
private function __clone() {
}
function ashuwp_user_points_menu() {
$hook = add_submenu_page('points_activity', 'User Points', 'User Points', 'manage_options', 'user_points', array(&$this, 'user_points'));
add_action( "load-$hook", array( $this, 'screen_option' ) );
}
function set_screen( $status, $option, $value ) {
return $value;
}
function screen_option() {
$option = 'per_page';
$args = array(
'label' => 'Customers',
'default' => 30,
'option' => 'customers_per_page'
);
add_screen_option( $option, $args );
$this->user_points_obj = new Ashuwp_User_Points_Table();
}
function user_points(){
$all = ashuwp_count_points();
?>
<div class="wrap">
<h1 class="wp-heading-inline">User Points</h1>
<a href="<?php echo admin_url( 'admin.php?page=points_activity_add' ); ?>" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="page-title-action">Add/Reduce</a>
<hr class="wp-header-end">
<ul class="subsubsub">
<li class="all"><a class="current" href="<?php echo admin_url( 'admin.php?page=user_points' ); ?>" rel="external nofollow" rel="external nofollow" >All<span class="count">(<?php echo $all; ?>)</span></a></li>
</ul>
<form id="points-activity-filter" method="get">
<?php
$this->user_points_obj->prepare_items();
$this->user_points_obj->display();
?>
</form>
</div>
<?php
}
public static function get_instance() {
if ( ! isset( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
}
ashuwp_user_points_admin::get_instance();
在遇到某个操作比如:充值成功、购买成功、发表评论,执行 ashuwp_add_points_activity 函数即可。
范例一:充值成功增加积分。
//准备参数
$user_id = 1; //用户id
$points = 10; //积分数
$desc = '充值:'.$points;
$args = array(
'user_id' => $user_id,
'action' => 'add', //增加
'points' => $points,
'description' => $desc,
);
$chognzhi = ashuwp_add_points_activity($args);
本教程的思路、代码仅供参考,代码为阿树从实际项目中剥离而来,在代码处理过程中,不敢保证不出错,特别是如果遇到有两个连续的 empty 请自行删除一个。
专业提供WordPress主题安装、深度汉化、加速优化等各类网站建设服务,详询在线客服!