queue( (int) $comment_id ); } } /** * Comment status changed. * * @param string $new_status New status. * @param string $old_status Old status. * @param \WP_Comment $comment Comment. */ public function on_transition( $new_status, $old_status, $comment ) { if ( 'approved' === $new_status && 'approved' !== $old_status && $comment instanceof \WP_Comment ) { $this->queue( (int) $comment->comment_ID ); } } /** * Queue a comment once (atomic via unique meta). * * @param int $comment_id Comment ID. */ private function queue( $comment_id ) { if ( ! $comment_id || ! add_comment_meta( $comment_id, '_replyping_queued', 1, true ) ) { return; } wp_schedule_single_event( time() + 10, self::HOOK, array( $comment_id, 0 ) ); } /** * Short hash of an email for the mailed-record. * * @param string $email Email. * @return string */ private function email_hash( $email ) { return substr( hash( 'sha256', strtolower( $email ) ), 0, 20 ); } /** * Cron: send one batch. * * @param int $comment_id Comment ID. * @param int $last_id Last subscription ID handled (cursor). */ public function process( $comment_id, $last_id = 0 ) { $comment_id = absint( $comment_id ); $last_id = absint( $last_id ); $comment = get_comment( $comment_id ); if ( ! $comment || '1' !== (string) $comment->comment_approved ) { return; } if ( ! in_array( $comment->comment_type, array( '', 'comment' ), true ) ) { return; } $post = get_post( (int) $comment->comment_post_ID ); if ( ! $post || 'publish' !== $post->post_status || '' !== $post->post_password ) { return; } $rows = Db::get_recipients( (int) $post->ID, (int) $comment->comment_parent, $last_id, self::BATCH_SIZE + 1 ); $has_more = count( $rows ) > self::BATCH_SIZE; $rows = array_slice( $rows, 0, self::BATCH_SIZE ); $cursor = $last_id; if ( $rows ) { $tail = end( $rows ); $cursor = (int) $tail->id; } $mailed = get_comment_meta( $comment_id, self::MAILED_KEY, true ); $mailed = is_array( $mailed ) ? $mailed : array(); $author = strtolower( trim( $comment->comment_author_email ) ); $list = array(); foreach ( $rows as $sub ) { $email = strtolower( $sub->email ); $hash = $this->email_hash( $email ); if ( $email === $author || isset( $mailed[ $hash ] ) ) { continue; } $mailed[ $hash ] = 1; $list[] = $sub; } $list = array_values( (array) apply_filters( 'replyping_notification_recipients', $list, $comment, $post ) ); // Record before sending so a crash cannot cause duplicates on retry. update_comment_meta( $comment_id, self::MAILED_KEY, $mailed ); foreach ( $list as $sub ) { Mailer::send_notification( $sub, $comment, $post ); } if ( $has_more ) { wp_schedule_single_event( time() + 30, self::HOOK, array( $comment_id, $cursor ) ); } } }