Created
July 24, 2025 21:25
-
-
Save obenland/58f04709da1b60dfe56bfa192b929f50 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * Plugin Name: ActivityPub Comment Debug Logger | |
| * Description: Debug logger for ActivityPub comment creation flow from Mastodon to WordPress | |
| * Version: 1.0.0 | |
| * | |
| * @package activitypub | |
| */ | |
| if ( ! defined( 'ABSPATH' ) ) { | |
| exit; | |
| } | |
| /** | |
| * Class ActivityPub_Comment_Debug_Logger | |
| */ | |
| class ActivityPub_Comment_Debug_Logger { | |
| private static $instance = null; | |
| private $log_prefix = '[AP-DEBUG]'; | |
| public static function get_instance() { | |
| if ( null === self::$instance ) { | |
| self::$instance = new self(); | |
| } | |
| return self::$instance; | |
| } | |
| private function __construct() { | |
| $this->init_hooks(); | |
| } | |
| /** | |
| * Initialize all debug hooks | |
| */ | |
| private function init_hooks() { | |
| // Only hook into Create activities and comment creation | |
| add_action( 'activitypub_inbox_create', array( $this, 'log_create_activity' ), 1, 3 ); | |
| add_action( 'wp_insert_comment', array( $this, 'log_comment_insertion' ), 1, 2 ); | |
| add_action( 'comment_post', array( $this, 'log_comment_created' ), 1, 3 ); | |
| // Hook into ActivityPub comment meta to confirm it's an AP comment | |
| add_action( 'add_comment_meta', array( $this, 'log_comment_meta' ), 1, 3 ); | |
| } | |
| /** | |
| * Log Create activity and check for potential failures | |
| */ | |
| public function log_create_activity( $user, $activity, $request ) { | |
| // Only log if this is a reply/comment | |
| if ( ! isset( $activity['object']['inReplyTo'] ) || empty( $activity['object']['inReplyTo'] ) ) { | |
| return; // Not a comment, skip logging | |
| } | |
| $this->log( '=== COMMENT CREATE ATTEMPT ===' ); | |
| // Check for duplicate first | |
| if ( function_exists( 'Activitypub\object_id_to_comment' ) ) { | |
| $existing_comment = \Activitypub\object_id_to_comment( $activity['object']['id'] ); | |
| if ( $existing_comment ) { | |
| $this->log( 'STOPPED: Duplicate comment exists (ID: ' . $existing_comment->comment_ID . ')' ); | |
| return; | |
| } | |
| } | |
| // Check if parent post exists | |
| $post_id = url_to_postid( $activity['object']['inReplyTo'] ); | |
| if ( ! $post_id ) { | |
| $this->log( 'STOPPED: Parent post not found for: ' . $activity['object']['inReplyTo'] ); | |
| return; | |
| } | |
| // Check if user is valid | |
| if ( ! is_object( $user ) || ! isset( $user->ID ) ) { | |
| $this->log( 'STOPPED: Invalid user object' ); | |
| return; | |
| } | |
| // Check for spam/disallowed content | |
| if ( function_exists( 'wp_check_comment_disallowed_list' ) ) { | |
| $author = $activity['actor'] ?? ''; | |
| $content = isset( $activity['object']['content'] ) ? strip_tags( $activity['object']['content'] ) : ''; | |
| if ( wp_check_comment_disallowed_list( $author, '', $content, '', '', '' ) ) { | |
| $this->log( 'STOPPED: Content flagged as spam/disallowed' ); | |
| return; | |
| } | |
| } | |
| $this->log( 'PROCEEDING: All checks passed, attempting comment creation' ); | |
| } | |
| /** | |
| * Log comment insertion result | |
| */ | |
| public function log_comment_insertion( $comment_id, $comment ) { | |
| if ( $comment_id && ! is_wp_error( $comment_id ) ) { | |
| $this->log( 'SUCCESS: Comment inserted with ID ' . $comment_id ); | |
| } else { | |
| $this->log( 'FAILED: Comment insertion failed - ' . ( is_wp_error( $comment_id ) ? $comment_id->get_error_message() : 'unknown error' ) ); | |
| } | |
| } | |
| /** | |
| * Log comment creation completion | |
| */ | |
| public function log_comment_created( $comment_id, $approved, $commentdata ) { | |
| $status = ( $approved === 1 ) ? 'approved' : ( $approved === 0 ? 'pending' : 'other' ); | |
| $this->log( 'COMPLETED: Comment ' . $comment_id . ' created (' . $status . ')' ); | |
| } | |
| /** | |
| * Log ActivityPub metadata - confirms it's an AP comment | |
| */ | |
| public function log_comment_meta( $comment_id, $meta_key, $meta_value ) { | |
| if ( $meta_key === 'protocol' && $meta_value === 'activitypub' ) { | |
| $this->log( 'CONFIRMED: Comment ' . $comment_id . ' is ActivityPub comment' ); | |
| } | |
| } | |
| /** | |
| * Main logging function | |
| */ | |
| private function log( $message ) { | |
| $timestamp = current_time( 'Y-m-d H:i:s' ); | |
| $formatted_message = sprintf( | |
| '%s %s [%s] %s', | |
| $timestamp, | |
| $this->log_prefix, | |
| $this->get_caller_info(), | |
| $message | |
| ); | |
| error_log( $formatted_message ); | |
| // Also log to a specific file if WP_DEBUG_LOG is enabled. | |
| if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) { | |
| $log_file = WP_CONTENT_DIR . '/activitypub-debug.log'; | |
| error_log( $formatted_message . PHP_EOL, 3, $log_file ); | |
| } | |
| } | |
| /** | |
| * Get caller information for better debugging | |
| */ | |
| private function get_caller_info() { | |
| $trace = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 4 ); | |
| // Find the first caller that's not this class. | |
| for ( $i = 1; $i < count( $trace ); $i++ ) { | |
| if ( isset( $trace[ $i ]['class'] ) && __CLASS__ !== $trace[ $i ]['class'] ) { | |
| $class = $trace[ $i ]['class']; | |
| $function = $trace[ $i ]['function'] ?? ''; | |
| return $class . '::' . $function; | |
| } elseif ( ! isset( $trace[ $i ]['class'] ) ) { | |
| $function = $trace[ $i ]['function'] ?? ''; | |
| $file = isset( $trace[ $i ]['file'] ) ? basename( $trace[ $i ]['file'] ) : ''; | |
| return $file . '::' . $function; | |
| } | |
| } | |
| return 'unknown'; | |
| } | |
| } | |
| // Initialize the debug logger only for ActivityPub inbox POST requests. | |
| add_action( | |
| 'rest_api_init', | |
| function () { | |
| // Only run on POST requests to ActivityPub inbox endpoints. | |
| if ( 'POST' === $_SERVER['REQUEST_METHOD'] ) { | |
| $request_uri = $_SERVER['REQUEST_URI'] ?? ''; | |
| if ( strpos( $request_uri, '/inbox' ) !== false && | |
| ( strpos( $request_uri, '/wp-json/activitypub/' ) !== false || strpos( $request_uri, '/activitypub/' ) !== false ) ) { | |
| ActivityPub_Comment_Debug_Logger::get_instance(); | |
| } | |
| } | |
| }, | |
| 5 | |
| ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment