proceed( $options['map'] );
} else {
if ( isset( $options['lastSched'] ) && $options['lastSched'] && isset( $options['nSched'] ) && 1 < absint( $options['nSched'] ) ) {
$now = time();
$n = absint( $options['nSched'] );
$ts = absint( $options['lastSched'] ) + ( 3600 * 24 * $n );
if ( $now >= $ts ) {
$ts += ( 3600 * 24 * $n );
while ( $now > $ts ) {
// in case the site was down for a long priod - otherwise task might be ran every day
$ts =+ ( 3600 * 24 * $n );
}
$options['lastSched'] = $ts;
update_option( self::optname, $options );
$this->proceed( $options['map'] );
}
}
}
}
/**
* return an human readable version of the next cleaning task occurence date
*/
public function next_sched_readable() {
$options = get_option( self::optname, array() );
if ( !isset( $options['period'] ) ) return 'N/A';
switch( $options['period'] ) {
case 'hourly':
case 'daily':
case 'twicedaily':
$ts = wp_next_scheduled( self::taskname );
if ( $ts ) {
$d = date_create( '@' . $ts, new DateTimeZone( 'UTC' ) );
return $d->format( get_option( 'date_format' ) ) . ' ' . $d->format( get_option( 'time_format' ) ) . ' UTC';
}
break;
case 'custom':
if ( isset( $options['lastSched'] ) && $options['lastSched'] && isset( $options['nSched'] ) && 1 < absint( $options['nSched'] ) ) {
$ts = absint( $options['lastSched'] ) + ( 3600 * 24 * absint( $options['nSched'] ) );
$d = date_create( '@' . $ts, new DateTimeZone( 'UTC' ) );
return $d->format( get_option( 'date_format' ) ) . ' ' . $d->format( get_option( 'time_format' ) ) . ' UTC';
}
break;
case 'none':
default:
return 'N/A';
}
return 'N/A';
}
/**
* AJAX callback - save schedules
*/
public function save_sched() {
if ( false === wp_verify_nonce( $_POST['nonce'], 'ancc' ) ) die;
if ( !current_user_can( 'moderate_comments' ) ) die;
if ( !isset( $_POST['args'] ) ) die;
$args = array();
parse_str( $_POST['args'], $args );
if ( !isset( $args['period'] ) || empty( $args['period'] ) ) die;
switch ( $args['period'] ) {
case 'default':
$freq = ( in_array( $args['period-default'], array( 'hourly', 'daily', 'twicedaily' ) ) )? $args['period-default'] : 'daily';
$ts = new DateTime( 'now', new DateTimeZone( 'UTC' ) );
if ( 'hourly' == $freq ) {
$_ts = absint( $ts->format( 'U' ) ) + 60;
} else {
$ts->setTime( 23, 59, 59 );
$_ts = absint( $ts->format( 'U' ) );
}
if ( wp_next_scheduled( self::taskname ) ) {
wp_clear_scheduled_hook( self::taskname );
}
wp_schedule_event( $_ts, $freq, self::taskname );
$options = get_option( self::optname, array() );
$options['lastSched'] = false;
$options['nSched'] = false;
$options['period'] = $freq;
update_option( self::optname, $options );
break;
case 'custom':
$n = absint( $args['custom-n'] );
if ( 2 > $n ) $n = 2;
$h = absint( $args['custom-h'] );
$m = absint( $args['custom-m'] );
if ( 0 > $h || 23 < $h ) $h = 12;
if ( 0 > $m || 59 < $m ) $m = 30;
$ts = new DateTime( 'tomorrow', new DateTimeZone( 'UTC' ) );
$ts->setTime( $h, $m );
$_ts = absint( $ts->format( 'U' ) );
if ( wp_next_scheduled( self::taskname ) ) {
wp_clear_scheduled_hook( self::taskname );
}
wp_schedule_event( $_ts, 'daily', self::taskname );
$options = get_option( self::optname, array() );
$options['lastSched'] = $_ts;
$options['nSched'] = $n;
$options['hSched'] = $h;
$options['mSched'] = $m;
$options['period'] = 'custom';
update_option( self::optname, $options );
break;
case 'disabled':
wp_clear_scheduled_hook( self::taskname );
$options = get_option( self::optname, array() );
$options['lastSched'] = false;
$options['nSched'] = false;
$options['period'] = 'none';
update_option( self::optname, $options );
break;
default:
}
header( 'Content-Type: application/json' );
echo json_encode( array(
'status' => true,
'msg' => ancc__( 'Settings saved.' ),
'nextRun' => $this->next_sched_readable(),
) );
die;
}
/**
* AJAX callback - save status/actions map
*/
public function save_map() {
if ( false === wp_verify_nonce( $_POST['nonce'], 'ancc' ) ) die;
if ( !current_user_can( 'moderate_comments' ) ) die;
$map = array(
'pending' => 'ignore',
'spam' => 'delete',
'trash' => 'ignore',
);
if ( isset( $_POST['spam'] ) && in_array( $_POST['spam'], array( 'ignore', 'delete' ) ) ) $map['spam'] = $_POST['spam'];
if ( isset( $_POST['trash'] ) && in_array( $_POST['trash'], array( 'ignore', 'delete' ) ) ) $map['trash'] = $_POST['trash'];
if ( isset( $_POST['pending'] ) && in_array( $_POST['pending'], array( 'ignore', 'delete', 'trash' ) ) ) $map['pending'] = $_POST['pending'];
$options = get_option( self::optname, array() );
$options = array( 'map' => $map ) + $options;
update_option( self::optname, $options );
header( 'Content-Type: application/json' );
echo json_encode( array(
'status' => true,
'msg' => ancc__( 'Settings saved.' ),
) );
die;
}
/**
* AJAX callback - clean immediatly
*/
public function immediate_clean() {
if ( false === wp_verify_nonce( $_POST['nonce'], 'ancc' ) ) die;
if ( !current_user_can( 'moderate_comments' ) ) die;
$map = array();
if ( isset( $_POST['spam'] ) ) $map['spam'] = $_POST['spam'];
if ( isset( $_POST['trash'] ) ) $map['trash'] = $_POST['trash'];
if ( isset( $_POST['pending'] ) ) $map['pending'] = $_POST['pending'];
$result = $this->proceed( $map );
header( 'Content-TYpe: application/json' );
$stats = array(
'lastTrash' => $result['trash'],
'lastDelete' => $result['delete'],
'lastIgnore' => $result['ignore'],
'lastExec' => time(),
);
$options = get_option( self::optname, array() );
$new_options = $stats + $options;
update_option( self::optname, $new_options );
$stats['execDate'] = date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) . ' \U\T\C', $stats['lastExec'] );
$response = array(
'status' => true,
'stats' => $stats,
);
if ( 0 == $result['totalRows'] ) {
$response['msg'] = __( 'No comment to delete', 'ancc' );
} else {
$response['msg'] = sprintf(
__( 'Done. %s: %s, %s: %s, %s: %s', 'ancc' ),
_n( 'Deleted', 'Deleted', $result['delete'], 'ancc' ),
'' . $result['delete'] . '',
_n( 'Moved to trash', 'Moved to trash', $result['trash'], 'ancc' ),
'' . $result['trash'] . '',
_n( 'Ignored', 'Ignored', $result['ignore'], 'ancc' ),
'' . $result['ignore'] . ''
);
}
echo json_encode( $response );
die;
}
/**
* perform all the DB operations
*/
private function proceed( $_map = array() ) {
$affected_rows = array(
'trash' => 0,
'delete' => 0,
'ignore' => 0,
);
$status = array(
'pending' => '0',
'spam' => 'spam',
'trash' => 'trash',
);
$total_row = 0;
global $wpdb;
$map = array();
foreach ( $_map as $i => $j ) {
if ( 'pending' != $i ) $map[$i] = $j;
}
// move 'pending' at the end of the array to avoid it being processed twice (trash then delete)
if ( isset( $_map['pending'] ) ) $map['pending'] = $_map['pending'];
foreach ( $map as $key => $action ) {
if ( 'spam' == $key && 'trash' == $action ) continue;
if ( 'trash' == $key && 'trash' == $action ) continue;
if ( array_key_exists( $key, $status ) && array_key_exists( $action, $affected_rows ) ) {
$_comments_ids = $wpdb->get_col( "SELECT comment_id FROM {$wpdb->comments} WHERE comment_approved = '{$status[$key]}'" );
if ( !empty( $_comments_ids ) ) {
if ( 'trash' == $action ) {
// only for unapproved comments
$comments_ids = implode( ',', array_map( 'intval', $_comments_ids ) );
$count = $wpdb->query( "UPDATE {$wpdb->comments} SET comment_approved = 'trash' WHERE comment_id IN ( $comments_ids )" );
if ( false !== $count ) {
$affected_rows['trash'] += $count;
$total_row += $count;
}
// set comments meta data
if ( 20 < count( $_comments_ids ) ) {
// if there is too much comments, split the array into smaller chunks - avoid troubles with low end server configs
$chunks = array_chunk( $_comments_ids, 20 );
foreach ( $chunks as $_ids ) {
$values = $this->trash_meta_fields( $_ids );
$values = implode( ',', $values );
$wpdb->query( "INSERT INTO {$wpdb->commentmeta} (`comment_id`, `meta_key`, `meta_value`) VALUES $values" );
}
} else {
$values = $this->trash_meta_fields( $_comments_ids );
$values = implode( ',', $values );
$wpdb->query( "INSERT INTO {$wpdb->commentmeta} (`comment_id`, `meta_key`, `meta_value`) VALUES $values" );
}
} elseif( 'delete' == $action ) {
$comments_ids = implode( ',', array_map( 'intval', $_comments_ids ) );
$count = $wpdb->query( "DELETE FROM {$wpdb->comments} WHERE comment_id IN ( $comments_ids )" );
$wpdb->query( "DELETE FROM {$wpdb->commentmeta} WHERE comment_id IN ( $comments_ids )" );
if ( false !== $count ) {
$affected_rows['delete'] += $count;
$total_row += $count;
}
} else {
$affected_rows['ignore'] += count( $_comments_ids );
}
}
}
}
if ( $total_row ) {
$wpdb->query( "OPTIMIZE TABLE {$wpdb->comments}" );
$wpdb->query( "OPTIMIZE TABLE {$wpdb->commentmeta}" );
}
return $affected_rows + array( 'totalRows' => $total_row );
}
/**
* prepare the value to insert in commentmeta for comments moved to trash
*/
private function trash_meta_fields( $ids = array() ) {
$result = array();
$time = (string)time();
foreach ( $ids as $id ) {
$result[] = "($id,'_wp_trash_meta_status','0'),($id,'_wp_trash_meta_time','$time')";
}
return $result;
}
/**
* initialisation
*/
public function init() {
$this->comment_status = array(
'pending' => ancc_x( 'Pending', 'comment status' ),
'spam' => ancc_x( 'Spam', 'verb' ),
'trash' => ancc_x( 'Trash', 'attachment filter' ),
);
$this->comment_action = array(
'delete' => ancc__( 'Permanently Delete Comment' ),
'trash' => ancc__( 'Move to Trash' ),
'ignore' => __( 'Ignore', 'meva' ),
);
}
/**
* print JS variables on admin pages
*/
public function print_scripts() {
$scr = get_current_screen();
if( $scr->id == $this->hook ) {
$ancc = array(
'settings' => get_option( self::optname, new stdClass() ),
'nonce' => wp_create_nonce( 'ancc' ),
'adminUrl' => admin_url(),
);
?>hook ) {
wp_register_script( 'ancc', ANCC_URL . 'assets/ancc.js', array( 'jquery' ), null );
wp_localize_script( 'ancc', 'anccLocale', array(
'unknownError' => __( 'An unknown error occurred', 'ancc' ),
) );
wp_enqueue_script( 'ancc' );
wp_enqueue_style( 'ancc', ANCC_URL . 'assets/ancc.css', array(), null );
}
}
/**
* add the admin page in menu
*/
public function admin_menu() {
$this->hook = add_comments_page( __( 'Comments Cleaner', 'ancc' ), __( 'Cleaner' ), 'moderate_comments', 'ancc', array( $this, 'admin_page' ) );
}
/**
* admin page callback
*/
public function admin_page() {
include ANCC_PATH . 'inc/admin-page.php';
}
/**
* load the plugin's text domain
*/
public function load_textdomain() {
load_plugin_textdomain( 'wpcc', false, WPCC_PATH . '/languages' );
}
public static function instance() {
if ( null === self::$instance ) {
self::$instance = new self;
}
return self::$instance;
}
}
ancc::instance();