Plugin Directory

Changeset 3467027


Ignore:
Timestamp:
02/22/2026 05:48:35 PM (2 weeks ago)
Author:
kraftbj
Message:

Update to version 1.0.1 from GitHub

Location:
fediboost
Files:
8 edited
1 copied

Legend:

Unmodified
Added
Removed
  • fediboost/tags/1.0.1/fediboost.php

    r3460488 r3467027  
    44 * Plugin URI: https://github.com/kraftbj/fediboost
    55 * Description: Automatically boost WordPress posts on connected Mastodon accounts when published via ActivityPub.
    6  * Version: 1.0.0
     6 * Version: 1.0.1
    77 * Requires at least: 6.9
    88 * Requires PHP: 7.4
     
    5151
    5252// Define plugin constants.
    53 define( 'FEDIBOOST_VERSION', '1.0.0' );
     53define( 'FEDIBOOST_VERSION', '1.0.1' );
    5454define( 'FEDIBOOST_PLUGIN_FILE', __FILE__ );
    5555define( 'FEDIBOOST_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
     
    7373 *
    7474 * FediBoost\Boost::init_hooks():
    75  *   wp_after_insert_post (priority 50) → on_post_publish()
    76  *   fediboost_boost_post (cron)        → execute_boost()
     75 *   wp_after_insert_post (priority 50)              → on_post_publish()
     76 *   activitypub_outbox_processing_complete           → on_federation_complete()
     77 *   fediboost_boost_post (cron)                      → execute_boost()
    7778 *
    7879 * FediBoost\Admin::init_hooks():
     
    134135function fediboost_deactivate() {
    135136    // Clear all scheduled boost events.
    136     wp_clear_scheduled_hook( 'fediboost_boost_post' );
     137    wp_unschedule_hook( 'fediboost_boost_post' );
    137138
    138139    // Remove the ActivityPub notice flag.
  • fediboost/tags/1.0.1/includes/class-boost.php

    r3460482 r3467027  
    3535
    3636    /**
    37      * Boost delay in seconds (30 seconds to allow ActivityPub federation).
     37     * Boost delay in seconds after ActivityPub federation completes.
    3838     *
    3939     * @since 1.0.0
     
    4242     */
    4343    const BOOST_DELAY = 30;
     44
     45    /**
     46     * Fallback delay in seconds when the ActivityPub federation hook does not fire.
     47     *
     48     * @since 1.0.1
     49     *
     50     * @var int
     51     */
     52    const FALLBACK_DELAY = 300;
    4453
    4554    /**
     
    8493        add_action( 'wp_after_insert_post', array( $this, 'on_post_publish' ), 50, 4 );
    8594
     95        /*
     96         * Hook into ActivityPub federation completion to schedule boost after federation.
     97         * Relies on the activitypub_outbox_processing_complete action, added in ActivityPub 5.4.0.
     98         * If this hook is unavailable (older plugin version or plugin inactive), the fallback
     99         * scheduled in on_post_publish() will handle the boost instead.
     100         */
     101        add_action( 'activitypub_outbox_processing_complete', array( $this, 'on_federation_complete' ), 10, 4 );
     102
    86103        // Register cron hook handler.
    87104        add_action( self::CRON_HOOK, array( $this, 'execute_boost' ) );
     
    90107    /**
    91108     * Handle post publish event.
     109     *
     110     * Marks the post as pending boost and schedules a fallback. The primary boost
     111     * scheduling happens in on_federation_complete() after ActivityPub has finished
     112     * federating the post.
    92113     *
    93114     * @since 1.0.0
     
    137158        }
    138159
    139         // Schedule the boost.
     160        // Store a transient mapping the ActivityPub URL to this post ID so we can
     161        // identify it when the activitypub_outbox_processing_complete hook fires.
     162        $activitypub_url = $activitypub->get_activitypub_url( $post );
     163
     164        if ( ! $activitypub_url ) {
     165            $this->log_info( 'No ActivityPub URL available, skipping boost', array( 'post_id' => $post_id ) );
     166            return;
     167        }
     168
     169        set_transient( 'fediboost_pending_' . md5( $activitypub_url ), $post_id, HOUR_IN_SECONDS );
     170
     171        // Schedule a fallback boost in case the ActivityPub federation hook doesn't fire.
     172        $this->schedule_fallback_boost( $post_id );
     173    }
     174
     175    /**
     176     * Handle ActivityPub federation completion.
     177     *
     178     * Fires after the ActivityPub plugin has finished sending a post to all follower
     179     * inboxes. Cancels the fallback boost and reschedules the boost relative to
     180     * federation completion rather than post publish time.
     181     *
     182     * @since 1.0.1
     183     *
     184     * @param array  $inboxes         Target inbox URLs.
     185     * @param string $json            The ActivityPub Activity JSON.
     186     * @param int    $actor_id        The actor user ID.
     187     * @param int    $outbox_item_id  The outbox item post ID.
     188     */
     189    public function on_federation_complete( $inboxes, $json, $actor_id, $outbox_item_id ) {
     190        // Only process Create activities (new posts, not updates or deletes).
     191        $type = get_post_meta( $outbox_item_id, '_activitypub_activity_type', true );
     192
     193        if ( ! $type ) {
     194            // Fall back to parsing the activity JSON if meta is unavailable.
     195            $activity = json_decode( $json, true );
     196
     197            if ( ! is_array( $activity ) ) {
     198                return;
     199            }
     200
     201            $type = isset( $activity['type'] ) ? $activity['type'] : '';
     202        }
     203
     204        if ( 'Create' !== $type ) {
     205            return;
     206        }
     207
     208        // Get the ActivityPub object URL from outbox item meta.
     209        $object_id = get_post_meta( $outbox_item_id, '_activitypub_object_id', true );
     210
     211        if ( empty( $object_id ) ) {
     212            // Fall back to parsing the activity JSON.
     213            if ( ! isset( $activity ) ) {
     214                $activity = json_decode( $json, true );
     215            }
     216
     217            if ( ! is_array( $activity ) ) {
     218                return;
     219            }
     220
     221            $object    = isset( $activity['object'] ) ? $activity['object'] : array();
     222            $object_id = isset( $object['id'] ) ? $object['id'] : '';
     223        }
     224
     225        if ( empty( $object_id ) ) {
     226            return;
     227        }
     228
     229        // Look up the pending boost transient to find the WordPress post ID.
     230        $transient_key = 'fediboost_pending_' . md5( $object_id );
     231        $post_id       = get_transient( $transient_key );
     232
     233        if ( ! $post_id ) {
     234            return;
     235        }
     236
     237        $this->log_info(
     238            'Federation complete, rescheduling boost',
     239            array(
     240                'post_id'        => $post_id,
     241                'outbox_item_id' => $outbox_item_id,
     242            )
     243        );
     244
     245        // Clean up the pending transient.
     246        delete_transient( $transient_key );
     247
     248        // Cancel the fallback boost.
     249        $this->unschedule_boost( $post_id );
     250
     251        // Schedule the boost for the configured delay after federation completes.
    140252        $this->schedule_boost( $post_id );
    141253    }
     
    185297
    186298    /**
     299     * Schedule a fallback boost with a longer delay.
     300     *
     301     * Used as a safety net in case the activitypub_outbox_processing_complete hook
     302     * does not fire (e.g., older ActivityPub plugin version). If the federation hook
     303     * fires first, it will cancel this fallback and reschedule with the normal delay.
     304     *
     305     * @since 1.0.1
     306     *
     307     * @param int $post_id The post ID to boost.
     308     * @return bool True if scheduled, false on failure.
     309     */
     310    public function schedule_fallback_boost( $post_id ) {
     311        // Check if already scheduled (prevent duplicates).
     312        if ( wp_next_scheduled( self::CRON_HOOK, array( $post_id ) ) ) {
     313            $this->log_info( 'Fallback boost already scheduled', array( 'post_id' => $post_id ) );
     314            return false;
     315        }
     316
     317        /**
     318         * Filters the fallback delay in seconds before a boost is executed when the
     319         * ActivityPub federation completion hook does not fire.
     320         *
     321         * @since 1.0.1
     322         *
     323         * @param int $delay Fallback delay in seconds. Default 300 (5 minutes).
     324         */
     325        $delay          = apply_filters( 'fediboost_fallback_delay', self::FALLBACK_DELAY );
     326        $scheduled_time = time() + $delay;
     327
     328        $result = wp_schedule_single_event( $scheduled_time, self::CRON_HOOK, array( $post_id ) );
     329
     330        if ( false === $result ) {
     331            $this->log_error( 'Failed to schedule fallback boost', array( 'post_id' => $post_id ) );
     332            return false;
     333        }
     334
     335        $this->log_info(
     336            'Fallback boost scheduled',
     337            array(
     338                'post_id'        => $post_id,
     339                'scheduled_time' => $scheduled_time,
     340                'delay'          => $delay,
     341            )
     342        );
     343
     344        return true;
     345    }
     346
     347    /**
     348     * Unschedule a pending boost for a post.
     349     *
     350     * @since 1.0.1
     351     *
     352     * @param int $post_id The post ID.
     353     */
     354    private function unschedule_boost( $post_id ) {
     355        $timestamp = wp_next_scheduled( self::CRON_HOOK, array( $post_id ) );
     356
     357        if ( $timestamp ) {
     358            wp_unschedule_event( $timestamp, self::CRON_HOOK, array( $post_id ) );
     359            $this->log_info( 'Cancelled previous boost schedule', array( 'post_id' => $post_id ) );
     360        }
     361    }
     362
     363    /**
    187364     * Execute boost for a post on all connected accounts.
    188365     *
     
    209386        $activitypub     = ActivityPub::get_instance();
    210387        $activitypub_url = $activitypub->get_activitypub_url( $post );
     388
     389        // Clean up any stale pending boost transient (fallback path).
     390        if ( $activitypub_url ) {
     391            delete_transient( 'fediboost_pending_' . md5( $activitypub_url ) );
     392        }
    211393
    212394        if ( false === $activitypub_url ) {
  • fediboost/tags/1.0.1/readme.txt

    r3460488 r3467027  
    55Tested up to: 6.9
    66Requires PHP: 7.4
    7 Stable tag: 1.0.0
     7Stable tag: 1.0.1
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    7878= fediboost_boost_delay =
    7979
    80 Delay in seconds between post publication and the boost action. Default: 30.
     80Delay in seconds after ActivityPub federation completes before the boost is executed. This delay is only used when the federation completion hook fires successfully. Default: 30.
    8181
    8282**Parameters:**
     
    8787
    8888`add_filter( 'fediboost_boost_delay', function( $delay ) {
    89     // Wait 2 minutes before boosting.
     89    // Wait 2 minutes after federation before boosting.
    9090    return 120;
     91} );`
     92
     93= fediboost_fallback_delay =
     94
     95Delay in seconds before a boost is executed when the ActivityPub federation completion hook does not fire. This acts as a safety net for older versions of the ActivityPub plugin that do not support the `activitypub_outbox_processing_complete` hook. If the federation hook fires first, the fallback is cancelled and `fediboost_boost_delay` is used instead. Default: 300 (5 minutes).
     96
     97**Parameters:**
     98
     99* `$delay` (int) — The fallback delay in seconds.
     100
     101**Example:**
     102
     103`add_filter( 'fediboost_fallback_delay', function( $delay ) {
     104    // Wait 10 minutes in the fallback path.
     105    return 600;
    91106} );`
    92107
     
    152167== Changelog ==
    153168
     169= 1.0.1 =
     170* Delay boost scheduling until after ActivityPub federation completes
     171* Add fallback boost scheduling for older ActivityPub versions
     172
    154173= 1.0.0 =
    155174* Initial release
  • fediboost/tags/1.0.1/uninstall.php

    r3460482 r3467027  
    8585    )
    8686);
     87
     88// Delete transients with fediboost_pending_ prefix (pending boost markers).
     89// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Required for transient cleanup by prefix
     90$wpdb->query(
     91    $wpdb->prepare(
     92        "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s OR option_name LIKE %s",
     93        $wpdb->esc_like( '_transient_fediboost_pending_' ) . '%',
     94        $wpdb->esc_like( '_transient_timeout_fediboost_pending_' ) . '%'
     95    )
     96);
  • fediboost/trunk/fediboost.php

    r3460488 r3467027  
    44 * Plugin URI: https://github.com/kraftbj/fediboost
    55 * Description: Automatically boost WordPress posts on connected Mastodon accounts when published via ActivityPub.
    6  * Version: 1.0.0
     6 * Version: 1.0.1
    77 * Requires at least: 6.9
    88 * Requires PHP: 7.4
     
    5151
    5252// Define plugin constants.
    53 define( 'FEDIBOOST_VERSION', '1.0.0' );
     53define( 'FEDIBOOST_VERSION', '1.0.1' );
    5454define( 'FEDIBOOST_PLUGIN_FILE', __FILE__ );
    5555define( 'FEDIBOOST_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
     
    7373 *
    7474 * FediBoost\Boost::init_hooks():
    75  *   wp_after_insert_post (priority 50) → on_post_publish()
    76  *   fediboost_boost_post (cron)        → execute_boost()
     75 *   wp_after_insert_post (priority 50)              → on_post_publish()
     76 *   activitypub_outbox_processing_complete           → on_federation_complete()
     77 *   fediboost_boost_post (cron)                      → execute_boost()
    7778 *
    7879 * FediBoost\Admin::init_hooks():
     
    134135function fediboost_deactivate() {
    135136    // Clear all scheduled boost events.
    136     wp_clear_scheduled_hook( 'fediboost_boost_post' );
     137    wp_unschedule_hook( 'fediboost_boost_post' );
    137138
    138139    // Remove the ActivityPub notice flag.
  • fediboost/trunk/includes/class-boost.php

    r3460482 r3467027  
    3535
    3636    /**
    37      * Boost delay in seconds (30 seconds to allow ActivityPub federation).
     37     * Boost delay in seconds after ActivityPub federation completes.
    3838     *
    3939     * @since 1.0.0
     
    4242     */
    4343    const BOOST_DELAY = 30;
     44
     45    /**
     46     * Fallback delay in seconds when the ActivityPub federation hook does not fire.
     47     *
     48     * @since 1.0.1
     49     *
     50     * @var int
     51     */
     52    const FALLBACK_DELAY = 300;
    4453
    4554    /**
     
    8493        add_action( 'wp_after_insert_post', array( $this, 'on_post_publish' ), 50, 4 );
    8594
     95        /*
     96         * Hook into ActivityPub federation completion to schedule boost after federation.
     97         * Relies on the activitypub_outbox_processing_complete action, added in ActivityPub 5.4.0.
     98         * If this hook is unavailable (older plugin version or plugin inactive), the fallback
     99         * scheduled in on_post_publish() will handle the boost instead.
     100         */
     101        add_action( 'activitypub_outbox_processing_complete', array( $this, 'on_federation_complete' ), 10, 4 );
     102
    86103        // Register cron hook handler.
    87104        add_action( self::CRON_HOOK, array( $this, 'execute_boost' ) );
     
    90107    /**
    91108     * Handle post publish event.
     109     *
     110     * Marks the post as pending boost and schedules a fallback. The primary boost
     111     * scheduling happens in on_federation_complete() after ActivityPub has finished
     112     * federating the post.
    92113     *
    93114     * @since 1.0.0
     
    137158        }
    138159
    139         // Schedule the boost.
     160        // Store a transient mapping the ActivityPub URL to this post ID so we can
     161        // identify it when the activitypub_outbox_processing_complete hook fires.
     162        $activitypub_url = $activitypub->get_activitypub_url( $post );
     163
     164        if ( ! $activitypub_url ) {
     165            $this->log_info( 'No ActivityPub URL available, skipping boost', array( 'post_id' => $post_id ) );
     166            return;
     167        }
     168
     169        set_transient( 'fediboost_pending_' . md5( $activitypub_url ), $post_id, HOUR_IN_SECONDS );
     170
     171        // Schedule a fallback boost in case the ActivityPub federation hook doesn't fire.
     172        $this->schedule_fallback_boost( $post_id );
     173    }
     174
     175    /**
     176     * Handle ActivityPub federation completion.
     177     *
     178     * Fires after the ActivityPub plugin has finished sending a post to all follower
     179     * inboxes. Cancels the fallback boost and reschedules the boost relative to
     180     * federation completion rather than post publish time.
     181     *
     182     * @since 1.0.1
     183     *
     184     * @param array  $inboxes         Target inbox URLs.
     185     * @param string $json            The ActivityPub Activity JSON.
     186     * @param int    $actor_id        The actor user ID.
     187     * @param int    $outbox_item_id  The outbox item post ID.
     188     */
     189    public function on_federation_complete( $inboxes, $json, $actor_id, $outbox_item_id ) {
     190        // Only process Create activities (new posts, not updates or deletes).
     191        $type = get_post_meta( $outbox_item_id, '_activitypub_activity_type', true );
     192
     193        if ( ! $type ) {
     194            // Fall back to parsing the activity JSON if meta is unavailable.
     195            $activity = json_decode( $json, true );
     196
     197            if ( ! is_array( $activity ) ) {
     198                return;
     199            }
     200
     201            $type = isset( $activity['type'] ) ? $activity['type'] : '';
     202        }
     203
     204        if ( 'Create' !== $type ) {
     205            return;
     206        }
     207
     208        // Get the ActivityPub object URL from outbox item meta.
     209        $object_id = get_post_meta( $outbox_item_id, '_activitypub_object_id', true );
     210
     211        if ( empty( $object_id ) ) {
     212            // Fall back to parsing the activity JSON.
     213            if ( ! isset( $activity ) ) {
     214                $activity = json_decode( $json, true );
     215            }
     216
     217            if ( ! is_array( $activity ) ) {
     218                return;
     219            }
     220
     221            $object    = isset( $activity['object'] ) ? $activity['object'] : array();
     222            $object_id = isset( $object['id'] ) ? $object['id'] : '';
     223        }
     224
     225        if ( empty( $object_id ) ) {
     226            return;
     227        }
     228
     229        // Look up the pending boost transient to find the WordPress post ID.
     230        $transient_key = 'fediboost_pending_' . md5( $object_id );
     231        $post_id       = get_transient( $transient_key );
     232
     233        if ( ! $post_id ) {
     234            return;
     235        }
     236
     237        $this->log_info(
     238            'Federation complete, rescheduling boost',
     239            array(
     240                'post_id'        => $post_id,
     241                'outbox_item_id' => $outbox_item_id,
     242            )
     243        );
     244
     245        // Clean up the pending transient.
     246        delete_transient( $transient_key );
     247
     248        // Cancel the fallback boost.
     249        $this->unschedule_boost( $post_id );
     250
     251        // Schedule the boost for the configured delay after federation completes.
    140252        $this->schedule_boost( $post_id );
    141253    }
     
    185297
    186298    /**
     299     * Schedule a fallback boost with a longer delay.
     300     *
     301     * Used as a safety net in case the activitypub_outbox_processing_complete hook
     302     * does not fire (e.g., older ActivityPub plugin version). If the federation hook
     303     * fires first, it will cancel this fallback and reschedule with the normal delay.
     304     *
     305     * @since 1.0.1
     306     *
     307     * @param int $post_id The post ID to boost.
     308     * @return bool True if scheduled, false on failure.
     309     */
     310    public function schedule_fallback_boost( $post_id ) {
     311        // Check if already scheduled (prevent duplicates).
     312        if ( wp_next_scheduled( self::CRON_HOOK, array( $post_id ) ) ) {
     313            $this->log_info( 'Fallback boost already scheduled', array( 'post_id' => $post_id ) );
     314            return false;
     315        }
     316
     317        /**
     318         * Filters the fallback delay in seconds before a boost is executed when the
     319         * ActivityPub federation completion hook does not fire.
     320         *
     321         * @since 1.0.1
     322         *
     323         * @param int $delay Fallback delay in seconds. Default 300 (5 minutes).
     324         */
     325        $delay          = apply_filters( 'fediboost_fallback_delay', self::FALLBACK_DELAY );
     326        $scheduled_time = time() + $delay;
     327
     328        $result = wp_schedule_single_event( $scheduled_time, self::CRON_HOOK, array( $post_id ) );
     329
     330        if ( false === $result ) {
     331            $this->log_error( 'Failed to schedule fallback boost', array( 'post_id' => $post_id ) );
     332            return false;
     333        }
     334
     335        $this->log_info(
     336            'Fallback boost scheduled',
     337            array(
     338                'post_id'        => $post_id,
     339                'scheduled_time' => $scheduled_time,
     340                'delay'          => $delay,
     341            )
     342        );
     343
     344        return true;
     345    }
     346
     347    /**
     348     * Unschedule a pending boost for a post.
     349     *
     350     * @since 1.0.1
     351     *
     352     * @param int $post_id The post ID.
     353     */
     354    private function unschedule_boost( $post_id ) {
     355        $timestamp = wp_next_scheduled( self::CRON_HOOK, array( $post_id ) );
     356
     357        if ( $timestamp ) {
     358            wp_unschedule_event( $timestamp, self::CRON_HOOK, array( $post_id ) );
     359            $this->log_info( 'Cancelled previous boost schedule', array( 'post_id' => $post_id ) );
     360        }
     361    }
     362
     363    /**
    187364     * Execute boost for a post on all connected accounts.
    188365     *
     
    209386        $activitypub     = ActivityPub::get_instance();
    210387        $activitypub_url = $activitypub->get_activitypub_url( $post );
     388
     389        // Clean up any stale pending boost transient (fallback path).
     390        if ( $activitypub_url ) {
     391            delete_transient( 'fediboost_pending_' . md5( $activitypub_url ) );
     392        }
    211393
    212394        if ( false === $activitypub_url ) {
  • fediboost/trunk/readme.txt

    r3460488 r3467027  
    55Tested up to: 6.9
    66Requires PHP: 7.4
    7 Stable tag: 1.0.0
     7Stable tag: 1.0.1
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    7878= fediboost_boost_delay =
    7979
    80 Delay in seconds between post publication and the boost action. Default: 30.
     80Delay in seconds after ActivityPub federation completes before the boost is executed. This delay is only used when the federation completion hook fires successfully. Default: 30.
    8181
    8282**Parameters:**
     
    8787
    8888`add_filter( 'fediboost_boost_delay', function( $delay ) {
    89     // Wait 2 minutes before boosting.
     89    // Wait 2 minutes after federation before boosting.
    9090    return 120;
     91} );`
     92
     93= fediboost_fallback_delay =
     94
     95Delay in seconds before a boost is executed when the ActivityPub federation completion hook does not fire. This acts as a safety net for older versions of the ActivityPub plugin that do not support the `activitypub_outbox_processing_complete` hook. If the federation hook fires first, the fallback is cancelled and `fediboost_boost_delay` is used instead. Default: 300 (5 minutes).
     96
     97**Parameters:**
     98
     99* `$delay` (int) — The fallback delay in seconds.
     100
     101**Example:**
     102
     103`add_filter( 'fediboost_fallback_delay', function( $delay ) {
     104    // Wait 10 minutes in the fallback path.
     105    return 600;
    91106} );`
    92107
     
    152167== Changelog ==
    153168
     169= 1.0.1 =
     170* Delay boost scheduling until after ActivityPub federation completes
     171* Add fallback boost scheduling for older ActivityPub versions
     172
    154173= 1.0.0 =
    155174* Initial release
  • fediboost/trunk/uninstall.php

    r3460482 r3467027  
    8585    )
    8686);
     87
     88// Delete transients with fediboost_pending_ prefix (pending boost markers).
     89// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Required for transient cleanup by prefix
     90$wpdb->query(
     91    $wpdb->prepare(
     92        "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s OR option_name LIKE %s",
     93        $wpdb->esc_like( '_transient_fediboost_pending_' ) . '%',
     94        $wpdb->esc_like( '_transient_timeout_fediboost_pending_' ) . '%'
     95    )
     96);
Note: See TracChangeset for help on using the changeset viewer.