Plugin Directory

Changeset 3002715


Ignore:
Timestamp:
11/28/2023 12:25:19 PM (2 years ago)
Author:
janboddez
Message:

Update to version 0.10.0 from GitHub

Location:
indieblocks
Files:
26 edited
1 copied

Legend:

Unmodified
Added
Removed
  • indieblocks/tags/0.10.0/blocks/facepile/block.json

    r2961482 r3002715  
    2929                "fontSize": true
    3030            }
     31        },
     32        "spacing": {
     33            "margin": ["top", "bottom"],
     34            "padding": false,
     35            "blockGap": false
    3136        }
    3237    }
  • indieblocks/tags/0.10.0/blocks/link-preview/class-link-preview-block.php

    r2993569 r3002715  
    6868
    6969            if ( ! empty( $card['thumbnail'] ) ) :
    70                 // Check if file still exists.
    71                 $upload_dir = wp_upload_dir();
    72                 $file_path  = str_replace( $upload_dir['baseurl'], $upload_dir['basedir'], $card['thumbnail'] );
    73 
    74                 if ( is_file( $file_path ) ) :
    75                     ?>
    76                     <img src="<?php echo esc_url_raw( $card['thumbnail'] ); ?>" width="90" height="90" alt="">
    77                     <?php
    78                 endif;
     70                ?>
     71                <img src="<?php echo esc_url_raw( $card['thumbnail'] ); ?>" width="90" height="90" alt="">
     72                <?php
    7973            endif;
    8074
  • indieblocks/tags/0.10.0/includes/class-parser.php

    r2993569 r3002715  
    8484
    8585        if ( empty( $mf2 ) ) {
     86            $fragment = wp_parse_url( $this->url, PHP_URL_FRAGMENT );
     87            if ( ! empty( $fragment ) ) {
     88                // If the URL contains a fragment, parse only the corresponding
     89                // page section.
     90                // @todo: Do this for `$this->dom`, too?
     91                $xpath = new \DOMXPath( $this->dom );
     92
     93                foreach ( $xpath->query( "//*[@id='$fragment']" ) as $el ) {
     94                    $content = $this->dom->saveHTML( $el );
     95                    break;
     96                }
     97            }
     98
    8699            $mf2 = Mf2\parse( $content, $this->url );
    87100            set_transient( 'indieblocks:mf2:' . $hash, $mf2, 3600 );
    88101        }
    89102
    90         $this->mf2 = Mf2\parse( $content, $this->url );
     103        $this->mf2 = $mf2;
    91104    }
    92105
     
    297310        if ( ! empty( $this->mf2['items'][0]['properties']['content'][0]['html'] ) ) {
    298311            return $this->mf2['items'][0]['properties']['content'][0]['html'];
     312        } elseif ( ! empty( $this->mf2['items'][0]['properties']['content'][0]['text'] ) ) {
     313            return $this->mf2['items'][0]['properties']['content'][0]['text'];
     314        } elseif ( ! empty( $this->mf2['items'][0]['properties']['content'][0] && is_string( $this->mf2['items'][0]['properties']['content'][0] ) ) ) {
     315            return $this->mf2['items'][0]['properties']['content'][0];
    299316        }
    300317
  • indieblocks/tags/0.10.0/includes/class-plugin.php

    r2993569 r3002715  
    1212     * Plugin version.
    1313     */
    14     const PLUGIN_VERSION = '0.9.1';
     14    const PLUGIN_VERSION = '0.10.0';
    1515
    1616    /**
  • indieblocks/tags/0.10.0/includes/class-theme-mf2.php

    r2993569 r3002715  
    178178        $processor->add_class( 'h-card u-author' );
    179179
    180         if ( ! empty( $instance->attributes['avatarSize'] ) ) {
     180        if ( ! empty( $instance->attributes['avatarSize'] ) && ! empty( $instance->attributes['showAvatar'] ) ) {
    181181            $processor->next_tag( 'img' );
    182182            $processor->add_class( 'u-photo' );
     
    481481        }
    482482
    483         $upload_dir = wp_upload_dir();
    484         $file_path  = str_replace( $upload_dir['baseurl'], $upload_dir['basedir'], $url );
    485 
    486         if ( ! is_file( $file_path ) ) {
    487             return null;
    488         }
    489 
    490483        $width  = (int) ( ! empty( $args['width'] ) ? $args['width'] : 96 );
    491484        $height = (int) ( ! empty( $args['height'] ) ? $args['height'] : 96 );
  • indieblocks/tags/0.10.0/includes/class-webmention-parser.php

    r2961482 r3002715  
    6363        if ( ! empty( $published ) ) {
    6464            $commentdata['comment_date']     = get_date_from_gmt( $published, 'Y-m-d H:i:s' );
    65             $commentdata['comment_date_gmt'] = date( 'Y-m-d H:i:s', strtotime( $published ) );
    66         }
    67 
    68         $commentdata['comment_meta']['indieblocks_webmention_source'] = esc_url_raw( $parser->get_url() ?: $source ); // phpcs:ignore WordPress.PHP.DisallowShortTernary.Found
     65            $commentdata['comment_date_gmt'] = date( 'Y-m-d H:i:s', strtotime( $published ) ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
     66        }
     67
     68        $commentdata['comment_meta']['indieblocks_webmention_source'] = esc_url_raw( $parser->get_url() ?: $source ); // phpcs:ignore Universal.Operators.DisallowShortTernary.Found
    6969
    7070        $hentry_kind = $parser->get_type();
  • indieblocks/tags/0.10.0/includes/class-webmention-receiver.php

    r2993569 r3002715  
    103103
    104104        $table_name  = $wpdb->prefix . 'indieblocks_webmentions';
    105         $webmentions = $wpdb->get_results( "SELECT id, source, post_id, ip, created_at FROM $table_name WHERE status = 'draft' LIMIT 5" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
     105        $webmentions = $wpdb->get_results( "SELECT id, source, target, post_id, ip, created_at FROM $table_name WHERE status = 'draft' LIMIT 5" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    106106
    107107        if ( empty( $webmentions ) || ! is_array( $webmentions ) ) {
     
    131131                            'key'     => 'indieblocks_webmention_source',
    132132                            'compare' => '=',
    133                             'value'   => esc_url( $webmention->source ),
     133                            'value'   => esc_url_raw( $webmention->source ),
     134                        ),
     135                        array(
     136                            'key'     => 'indieblocks_webmention_target',
     137                            'compare' => 'EXISTS',
     138                        ),
     139                        array(
     140                            'key'     => 'indieblocks_webmention_target',
     141                            'compare' => '=',
     142                            'value'   => esc_url_raw( $webmention->target ),
    134143                        ),
    135144                    ),
     
    205214            $host = wp_parse_url( $webmention->source, PHP_URL_HOST );
    206215
     216            // Look for a target URL fragment (and possible parent comment).
     217            $fragment = wp_parse_url( $webmention->target, PHP_URL_FRAGMENT );
     218            if ( ! empty( $fragment ) && preg_match( '~^comment-\d+$~', $fragment ) ) {
     219                $parent = get_comment( str_replace( 'comment-', '', str_replace( 'comment-', '', $fragment ) ) );
     220            }
     221
    207222            // Some defaults.
    208223            $commentdata = array(
     
    213228                'comment_author_IP'    => $webmention->ip,
    214229                'comment_content'      => __( '&hellip; commented on this.', 'indieblocks' ),
    215                 'comment_parent'       => 0,
     230                'comment_parent'       => ! empty( $parent ) && $webmention->post_id === $parent->comment_post_ID ? $parent->comment_ID : 0,
    216231                'user_id'              => 0,
    217232                'comment_date'         => $webmention->created_at,
     
    220235                'comment_meta'         => array(
    221236                    'indieblocks_webmention_source' => esc_url_raw( $webmention->source ),
     237                    'indieblocks_webmention_target' => esc_url_raw( $webmention->target ),
    222238                ),
    223239            );
     
    371387
    372388            // Delete file.
    373             if ( is_file( $file_path ) ) {
    374                 wp_delete_file( $file_path );
    375             }
    376 
    377             // Delete reference in database.
    378             delete_comment_meta( $comment_id, 'indieblocks_webmention_avatar' );
     389            wp_delete_file( $file_path );
     390
     391            // Delete _all_ references to this file (i.e., not just this
     392            // comment's meta field).
     393            global $wpdb;
     394
     395            $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
     396                $wpdb->prepare(
     397                    "DELETE FROM $wpdb->commentmeta WHERE meta_key = %s AND meta_value = %s",
     398                    'indieblocks_webmention_avatar',
     399                    esc_url_raw( $url )
     400                )
     401            );
    379402        }
    380403
  • indieblocks/tags/0.10.0/includes/class-webmention-sender.php

    r2993569 r3002715  
    1818     * callback function queued in the background.
    1919     *
    20      * @param string  $new_status New post status.
    21      * @param string  $old_status Old post status.
    22      * @param WP_Post $post       Post object.
    23      */
    24     public static function schedule_webmention( $new_status, $old_status, $post ) {
    25         if ( wp_is_post_revision( $post->ID ) || wp_is_post_autosave( $post->ID ) ) {
    26             return;
    27         }
    28 
    29         /* @see https://github.com/WordPress/gutenberg/issues/15094#issuecomment-1021288811. */
    30         if ( ! empty( $_REQUEST['meta-box-loader'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    31             // Avoid scheduling (or posting, in case of no delay) webmentions
    32             // more than once.
    33             return;
     20     * @param int                  $obj_id     Post or comment ID.
     21     * @param \WP_Post|\WP_Comment $obj        Post or comment object.
     22     * @param mixed                $deprecated Used to be the post object, now deprecated.
     23     */
     24    public static function schedule_webmention( $obj_id, $obj = null, $deprecated = null ) {
     25        if ( null !== $deprecated ) {
     26            _deprecated_argument( 'post', '0.10.0', 'Passing a third argument to `\IndieBlocks\Webmention_Sender::schedule_webmention()` is deprecated.' );
    3427        }
    3528
     
    3932        }
    4033
    41         if ( 'publish' !== $new_status ) {
     34        if ( 'comment_post' === current_filter() ) {
     35            $obj = get_comment( $obj_id );
     36        }
     37
     38        if ( $obj instanceof \WP_Post ) {
     39            if ( 'publish' !== $obj->post_status ) {
     40                // Do not send webmention on delete/unpublish, for now.
     41                return;
     42            }
     43
     44            /* @see https://github.com/WordPress/gutenberg/issues/15094#issuecomment-1021288811. */
     45            if ( ! empty( $_REQUEST['meta-box-loader'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
     46                // Avoid scheduling (or posting, in case of no delay) webmentions
     47                // more than once.
     48                return;
     49            }
     50
     51            if ( wp_is_post_revision( $obj->ID ) || wp_is_post_autosave( $obj->ID ) ) {
     52                return;
     53            }
     54
     55            if ( ! in_array( $obj->post_type, Webmention::get_supported_post_types(), true ) ) {
     56                return;
     57            }
     58        } elseif ( '1' !== $obj->comment_approved ) {
    4259            // Do not send webmention on delete/unpublish, for now.
    4360            return;
    4461        }
    4562
    46         if ( ! in_array( $post->post_type, Webmention::get_supported_post_types(), true ) ) {
    47             return;
    48         }
    49 
    50         // Fetch our post's HTML.
    51         $html = apply_filters( 'the_content', $post->post_content );
    52 
    53         // Scan it for outgoing links.
    54         $urls = static::find_outgoing_links( $html );
    55 
    56         // Parse in targets that may have been there previously, but don't delete
    57         // them, yet.
    58         $history = get_post_meta( $post->ID, '_indieblocks_webmention_history', true );
     63        $urls = array();
     64
     65        if ( $obj instanceof \WP_Post ) {
     66            // Fetch our post's HTML.
     67            $html = apply_filters( 'the_content', $obj->post_content );
     68
     69            // Scan it for outgoing links.
     70            $urls = static::find_outgoing_links( $html );
     71        } elseif ( ! empty( $obj->comment_parent ) ) {
     72            // Add in the parent's, if any, Webmention source.
     73            $source = get_comment_meta( $obj->comment_parent, 'indieblocks_webmention_source', true );
     74            if ( ! empty( $source ) ) {
     75                $urls[] = $source;
     76            }
     77        }
     78
     79        // Parse in targets that may have been there previously, but don't
     80        // delete them, yet.
     81        $history = get_meta( $obj, '_indieblocks_webmention_history' );
     82
    5983        if ( ! empty( $history ) && is_array( $history ) ) {
    60             $urls = array_unique( array_merge( $urls, $history ) );
    61         }
    62 
    63         if ( empty( $urls ) || ! is_array( $urls ) ) {
     84            $urls = array_merge( $urls, $history );
     85        }
     86
     87        if ( empty( $urls ) ) {
    6488            // Nothing to do. Bail.
    6589            return;
    6690        }
    6791
     92        $urls     = array_unique( $urls );
    6893        $schedule = false;
    6994
     
    91116
    92117                // Schedule sending out the actual webmentions.
    93                 error_log( "[Indieblocks/Webmention] Scheduling webmention for post {$post->ID}." ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
    94                 wp_schedule_single_event( time() + $delay, 'indieblocks_webmention_send', array( $post->ID ) );
    95 
    96                 add_post_meta( $post->ID, '_indieblocks_webmention', 'scheduled', true ); // Does not affect existing values.
     118                if ( $obj instanceof \WP_Post ) {
     119                    error_log( "[Indieblocks/Webmention] Scheduling webmention for post {$obj->ID}." ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
     120                } else {
     121                    error_log( "[Indieblocks/Webmention] Scheduling webmention for comment {$obj->comment_ID}." ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
     122                }
     123
     124                add_meta( $obj, '_indieblocks_webmention', 'scheduled' );
     125                wp_schedule_single_event( time() + $delay, 'indieblocks_webmention_send', array( $obj ) );
    97126            } else {
    98127                // Send inline (although retries will be scheduled as always).
    99                 static::send_webmention( $post->ID );
     128                static::send_webmention( $obj );
    100129            }
    101130        }
     
    106135     * a post.
    107136     *
    108      * @param int $post_id Post ID.
    109      */
    110     public static function send_webmention( $post_id ) {
    111         $post = get_post( $post_id );
    112 
    113         if ( 'publish' !== $post->post_status ) {
    114             // Do not send webmentions on delete/unpublish, for now.
    115             return;
    116         }
    117 
    118         if ( ! in_array( $post->post_type, Webmention::get_supported_post_types(), true ) ) {
    119             // This post type doesn't support Webmention.
    120             return;
    121         }
    122 
    123         // Fetch our post's HTML.
    124         $html = apply_filters( 'the_content', $post->post_content );
    125 
    126         // Scan it for outgoing links, again, as things might have changed.
    127         $urls = static::find_outgoing_links( $html );
    128 
    129         // Parse in (and then forget) targets that may have been there before.
     137     * @param \WP_Post|\WP_Comment $obj Post or comment object.
     138     */
     139    public static function send_webmention( $obj ) {
     140        if ( $obj instanceof \WP_Post ) {
     141            if ( 'publish' !== $obj->post_status ) {
     142                // Do not send webmention on delete/unpublish, for now.
     143                return;
     144            }
     145
     146            if ( ! in_array( $obj->post_type, Webmention::get_supported_post_types(), true ) ) {
     147                // This post type doesn't support Webmention.
     148                return;
     149            }
     150        } elseif ( '1' !== $obj->comment_approved ) {
     151            return;
     152        }
     153
     154        $urls = array();
     155
     156        if ( $obj instanceof \WP_Post ) {
     157            // Fetch our post's HTML.
     158            $html = apply_filters( 'the_content', $obj->post_content );
     159
     160            // Scan it for outgoing links.
     161            $urls = static::find_outgoing_links( $html );
     162        } elseif ( ! empty( $obj->comment_parent ) ) {
     163            // Add in the parent's, if any, Webmention source.
     164            $source = get_comment_meta( $obj->comment_parent, 'indieblocks_webmention_source', true );
     165            if ( ! empty( $source ) ) {
     166                $urls[] = $source;
     167            }
     168        }
     169
     170        // Parse in (_and_ then forget) targets that may have been there before.
    130171        // This also means that "historic" targets are excluded from retries!
    131172        // Note that we _also_ retarget pages that threw an error or we
    132173        // otherwise failed to reach previously. Both are probably acceptable.
    133         $history = get_post_meta( $post->ID, '_indieblocks_webmention_history', true );
    134         delete_post_meta( $post->ID, '_indieblocks_webmention_history' );
     174        $history = get_meta( $obj, '_indieblocks_webmention_history' );
     175        delete_meta( $obj, '_indieblocks_webmention_history' );
     176
    135177        if ( ! empty( $history ) && is_array( $history ) ) {
    136             $urls = array_unique( array_merge( $urls, $history ) );
    137         }
    138 
    139         if ( empty( $urls ) || ! is_array( $urls ) ) {
     178            $urls = array_merge( $urls, $history );
     179        }
     180
     181        if ( empty( $urls ) ) {
    140182            // One or more links must've been removed. Nothing to do. Bail.
    141183            return;
    142184        }
    143185
     186        $urls = array_unique( $urls );
     187
    144188        // Fetch whatever Webmention-related stats we've got for this post.
    145         $webmention = get_post_meta( $post->ID, '_indieblocks_webmention', true );
     189        $webmention = get_meta( $obj, '_indieblocks_webmention' );
    146190
    147191        if ( empty( $webmention ) || ! is_array( $webmention ) ) {
     
    157201            if ( empty( $endpoint ) || false === wp_http_validate_url( $endpoint ) ) {
    158202                // Skip.
     203                error_log( '[Indieblocks/Webmention] Could not find a Webmention endpoint for target ' . esc_url_raw( $url ) . '.' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
    159204                continue;
    160205            }
     
    190235                array(
    191236                    'body' => array(
    192                         'source' => get_permalink( $post->ID ),
     237                        'source' => $obj instanceof \WP_Post ? get_permalink( $obj->ID ) : get_comment_link( $obj->comment_ID ),
    193238                        'target' => $url,
    194239                    ),
     
    196241            );
    197242
    198             if ( is_wp_error( $response ) ) {
     243            if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) >= 500 ) {
    199244                // Something went wrong.
    200245                error_log( '[Indieblocks/Webmention] Error trying to send a webmention to ' . esc_url_raw( $endpoint ) . ': ' . $response->get_error_message() ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
     246                error_log( print_r( $response, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log,WordPress.PHP.DevelopmentFunctions.error_log_print_r
    201247
    202248                $webmention[ $hash ]['retries'] = $retries + 1;
    203                 update_post_meta( $post->ID, '_indieblocks_webmention', $webmention );
     249
     250                update_meta( $obj, '_indieblocks_webmention', $webmention );
    204251
    205252                // Schedule a retry in 5 to 15 minutes.
    206                 wp_schedule_single_event( time() + wp_rand( 300, 900 ), 'indieblocks_webmention_send', array( $post->ID ) );
    207 
    208                 continue;
    209             } elseif ( wp_remote_retrieve_response_code( $response ) >= 500 ) {
    210                 // Something went wrong.
    211                 error_log( '[Indieblocks/Webmention] Error trying to send a webmention to ' . esc_url_raw( $endpoint ) . '.' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
    212                 error_log( print_r( $response, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log,WordPress.PHP.DevelopmentFunctions.error_log_print_r
    213 
    214                 $webmention[ $hash ]['retries'] = $retries + 1;
    215                 update_post_meta( $post->ID, '_indieblocks_webmention', $webmention );
    216 
    217                 // Schedule a retry in 5 to 15 minutes.
    218                 wp_schedule_single_event( time() + wp_rand( 300, 900 ), 'indieblocks_webmention_send', array( $post->ID ) );
     253                wp_schedule_single_event( time() + wp_rand( 300, 900 ), 'indieblocks_webmention_send', array( $obj ) );
    219254
    220255                continue;
     
    228263        }
    229264
    230         update_post_meta( $post->ID, '_indieblocks_webmention', $webmention );
     265        update_meta( $obj, '_indieblocks_webmention', $webmention );
    231266    }
    232267
     
    463498
    464499        $post = get_post( $post_id );
    465         static::schedule_webmention( $post->post_status, $post->post_status, $post );
     500        static::schedule_webmention( $post_id, $post );
    466501
    467502        wp_die();
  • indieblocks/tags/0.10.0/includes/class-webmention.php

    r2993569 r3002715  
    2424
    2525        add_action( 'add_meta_boxes', array( Webmention_Sender::class, 'add_meta_box' ) );
    26         add_action( 'transition_post_status', array( Webmention_Sender::class, 'schedule_webmention' ), 10, 3 );
     26
     27        foreach ( static::get_supported_post_types() as $post_type ) {
     28            add_action( "publish_{$post_type}", array( Webmention_Sender::class, 'schedule_webmention' ), 10, 2 );
     29        }
     30
     31        // When a comment is first inserted into the database.
     32        add_action( 'comment_post', array( Webmention_Sender::class, 'schedule_webmention' ) ); // Pass only one argument (the comment ID) to `Webmention_Sender::schedule_webmention()`!
     33        // When a comment is approved. Or a previously approved comment updated.
     34        add_action( 'comment_approved_comment', array( Webmention_Sender::class, 'schedule_webmention' ), 10, 2 );
     35
    2736        add_action( 'indieblocks_webmention_send', array( Webmention_Sender::class, 'send_webmention' ) );
    2837
  • indieblocks/tags/0.10.0/includes/functions.php

    r2993569 r3002715  
    3939 */
    4040function debug_log( $item ) {
    41     error_log( print_r( $item, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log,WordPress.PHP.DevelopmentFunctions.error_log_print_r
     41    error_log( is_string( $item ) ? $item : print_r( $item, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log,WordPress.PHP.DevelopmentFunctions.error_log_print_r
    4242}
    4343
     
    283283            }
    284284        } else {
    285             debug_log( '[IndieBlocks] Could not reisize ' . $file_path . ': ' . $image->get_error_message() . '.' );
     285            debug_log( '[IndieBlocks] Could not resize ' . $file_path . ': ' . $image->get_error_message() . '.' );
    286286        }
    287287
     
    376376    return $facepile_comments;
    377377}
     378
     379/**
     380 * Get post or comment meta.
     381 *
     382 * @param  \WP_Post|\WP_Comment $obj      Post or comment.
     383 * @param  string               $meta_key The meta key.
     384 * @return string                         The meta value (or an empty) string.
     385 */
     386function get_meta( $obj, $meta_key ) {
     387    if ( $obj instanceof \WP_Post ) {
     388        return get_post_meta( $obj->ID, $meta_key, true );
     389    }
     390
     391    if ( $obj instanceof \WP_Comment ) {
     392        return get_comment_meta( $obj->comment_ID, $meta_key, true );
     393    }
     394
     395    return '';
     396}
     397
     398/**
     399 * Update post or comment meta.
     400 *
     401 * @param  \WP_Post|\WP_Comment $obj        Post or comment.
     402 * @param  string               $meta_key   The meta key.
     403 * @param  mixed                $meta_value The value.
     404 */
     405function add_meta( $obj, $meta_key, $meta_value ) {
     406    if ( $obj instanceof \WP_Post ) {
     407        add_post_meta( $obj->ID, $meta_key, $meta_value );
     408    }
     409
     410    if ( $obj instanceof \WP_Comment ) {
     411        add_comment_meta( $obj->comment_ID, $meta_key, $meta_value );
     412    }
     413}
     414
     415/**
     416 * Update post or comment meta.
     417 *
     418 * @param  \WP_Post|\WP_Comment $obj        Post or comment.
     419 * @param  string               $meta_key   The meta key.
     420 * @param  mixed                $meta_value The value.
     421 */
     422function update_meta( $obj, $meta_key, $meta_value ) {
     423    if ( $obj instanceof \WP_Post ) {
     424        update_post_meta( $obj->ID, $meta_key, $meta_value );
     425    }
     426
     427    if ( $obj instanceof \WP_Comment ) {
     428        update_comment_meta( $obj->comment_ID, $meta_key, $meta_value );
     429    }
     430}
     431
     432/**
     433 * Delete post or comment meta.
     434 *
     435 * @param  \WP_Post|\WP_Comment $obj      Post or comment.
     436 * @param  string               $meta_key The meta key.
     437 */
     438function delete_meta( $obj, $meta_key ) {
     439    if ( $obj instanceof \WP_Post ) {
     440        delete_post_meta( $obj->ID, $meta_key );
     441    }
     442
     443    if ( $obj instanceof \WP_Comment ) {
     444        delete_comment_meta( $obj->comment_ID, $meta_key );
     445    }
     446}
  • indieblocks/tags/0.10.0/indieblocks.php

    r2993569 r3002715  
    99 * License URI:       http://www.gnu.org/licenses/gpl-3.0.html
    1010 * Text Domain:       indieblocks
    11  * Version:           0.9.1
     11 * Version:           0.10.0
    1212 * Requires at least: 6.2
    1313 * GitHub Plugin URI: https://github.com/janboddez/indieblocks
  • indieblocks/tags/0.10.0/languages/indieblocks.pot

    r2993569 r3002715  
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: IndieBlocks 0.9.1\n"
     5"Project-Id-Version: IndieBlocks 0.10.0\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/indieblocks\n"
    77"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
     
    1010"Content-Type: text/plain; charset=UTF-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "POT-Creation-Date: 2023-11-08T20:41:32+00:00\n"
     12"POT-Creation-Date: 2023-11-26T22:12:55+01:00\n"
    1313"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    14 "X-Generator: WP-CLI 2.6.0\n"
     14"X-Generator: WP-CLI 2.9.0\n"
    1515"X-Domain: indieblocks\n"
    1616
     
    165165#: includes/class-options-handler.php:376
    166166#: includes/class-options-handler.php:479
    167 #: includes/class-webmention-receiver.php:288
    168 #: includes/class-webmention-sender.php:372
     167#: includes/class-webmention-receiver.php:304
     168#: includes/class-webmention-sender.php:416
    169169msgid "Webmention"
    170170msgstr ""
     
    548548msgstr ""
    549549
    550 #: includes/class-webmention-receiver.php:214
     550#: includes/class-webmention-receiver.php:229
    551551msgid "&hellip; commented on this."
    552552msgstr ""
    553553
    554 #: includes/class-webmention-receiver.php:307
     554#: includes/class-webmention-receiver.php:323
    555555msgid "Source"
    556556msgstr ""
    557557
    558 #: includes/class-webmention-receiver.php:310
     558#: includes/class-webmention-receiver.php:326
    559559#: blocks/context/block.js:67
    560560msgid "Type"
    561561msgstr ""
    562562
    563 #: includes/class-webmention-receiver.php:314
     563#: includes/class-webmention-receiver.php:330
    564564msgid "Avatar"
    565565msgstr ""
    566566
    567 #: includes/class-webmention-receiver.php:318
     567#: includes/class-webmention-receiver.php:334
    568568msgid "Delete"
    569569msgstr ""
    570570
    571 #: includes/class-webmention-receiver.php:348
    572 #: includes/class-webmention-sender.php:439
     571#: includes/class-webmention-receiver.php:364
     572#: includes/class-webmention-sender.php:483
    573573msgid "Missing or invalid nonce."
    574574msgstr ""
    575575
    576 #: includes/class-webmention-receiver.php:354
     576#: includes/class-webmention-receiver.php:370
    577577msgid "Invalid comment ID."
    578578msgstr ""
    579579
    580 #: includes/class-webmention-receiver.php:362
    581 #: includes/class-webmention-sender.php:453
     580#: includes/class-webmention-receiver.php:378
     581#: includes/class-webmention-sender.php:497
    582582msgid "Insufficient rights."
    583583msgstr ""
    584584
    585585#. translators: 1: Webmention endpoint 2: Date sent
    586 #: includes/class-webmention-sender.php:404
     586#: includes/class-webmention-sender.php:448
    587587msgid "Sent to %1$s on %2$s. Response code: %3$d."
    588588msgstr ""
    589589
    590590#. translators: 1: Webmention endpoint 2: Date sent
    591 #: includes/class-webmention-sender.php:404
     591#: includes/class-webmention-sender.php:448
    592592msgid "M j, Y \\a\\t H:i"
    593593msgstr ""
    594594
    595595#. translators: Webmention endpoint
    596 #: includes/class-webmention-sender.php:407
     596#: includes/class-webmention-sender.php:451
    597597msgid "Could not send webmention to %s."
    598598msgstr ""
    599599
    600600#. translators: Webmention endpoint
    601 #: includes/class-webmention-sender.php:410
     601#: includes/class-webmention-sender.php:454
    602602msgid "Could not send webmention to %s. Trying again soon."
    603603msgstr ""
    604604
    605 #: includes/class-webmention-sender.php:420
     605#: includes/class-webmention-sender.php:464
    606606msgid "Resend"
    607607msgstr ""
    608608
    609 #: includes/class-webmention-sender.php:424
    610 #: includes/class-webmention.php:143
     609#: includes/class-webmention-sender.php:468
     610#: includes/class-webmention.php:152
    611611msgid "Webmention scheduled."
    612612msgstr ""
    613613
    614 #: includes/class-webmention-sender.php:426
     614#: includes/class-webmention-sender.php:470
    615615msgid "No endpoints found."
    616616msgstr ""
    617617
    618 #: includes/class-webmention-sender.php:445
     618#: includes/class-webmention-sender.php:489
    619619msgid "Invalid post ID."
    620620msgstr ""
  • indieblocks/tags/0.10.0/readme.txt

    r2993569 r3002715  
    33Tags: blocks, gutenberg, indieweb, notes, likes, microblog, microblogging, micropub, fse, site editor, webmention, syndication
    44Tested up to: 6.4
    5 Stable tag: 0.9.1
     5Stable tag: 0.10.0
    66License: GNU General Public License v3.0
    77License URI: https://www.gnu.org/licenses/gpl-3.0.html
     
    1010
    1111== Description ==
     12Use blocks, and, optionally, "short-form" post types to easily "IndieWebify" your WordPress site.
     13
    1214IndieBlocks registers several blocks (Bookmark, Like, Reply, and Repost, as well as the older Context block) that take a URL and output corresponding _microformatted_ HTML.
    1315
     
    1820These microformats, in combination with the Webmention protocol, allow for rich _cross-site_ conversations. IndieBlocks comes with its own Webmention implementation, but a separate plugin can be used, too.
    1921
    20 IndieBlocks also registers several "theme" blocks (Facepile, Location, Syndication, and Link Preview), to be used in (block) theme templates.
     22IndieBlocks also registers several "theme" blocks (Facepile, Location, Syndication, and Link Preview), to be used in "block theme" templates.
    2123
    2224== Installation ==
     
    2729More details can be found on [https://indieblocks.xyz/](https://indieblocks.xyz/). Issues may be filed at [https://github.com/janboddez/indieblocks](https://github.com/janboddez/indieblocks).
    2830
     31== Frequently Asked Questions ==
     32= How does this plugin interact with the various other IndieWeb plugins? =
     33While IndieBlocks does not depend on _any_ other plugin, it is compatible with, and extends, the Micropub plugin for WordPress. See [https://indieblocks.xyz/documentation/micropub-and-indieauth/](https://indieblocks.xyz/documentation/micropub-and-indieauth/) for some more information.
     34
     35IndieBlocks&rsquo; Facepile and Syndication blocks also aim to be compatible with, respectively, the Webmention and Syndication Links plugins.
     36
    2937== Changelog ==
     38= 0.10.0 =
     39Send webmentions also for comments, to mentioned sites and the comment parent, if it exists and itself originated as a webmention.
     40
    3041= 0.9.1 =
    3142Fix Webmention backlinks in Facepile block, add avatar background and icon color pickers.
     43
    3244= 0.9.0 =
    3345Overhaul theme microformats functionality.
     46
    3447= 0.8.1 =
    3548Fix issue with saving meta from block editor. Fix Markdown in Micropub notes.
     49
    3650= 0.8.0 =
    3751Various bug fixes. Add Link Preview block. Also, webmentions are now closed when comments are, although this behavior is filterable.
     52
    3853= 0.7.1 =
    3954Add Location block. The Facepile block now supports v5.0 and up of the Webmention plugin.
     55
    4056= 0.7.0 =
    4157Store temperatures in Kelvin rather than degrees Celsius. Update `masterminds/html5` to version 2.8.0. Add Location block.
     58
    4259= 0.6.0 =
    4360"Facepile" likes, bookmarks, and reposts.
     61
    4462= 0.5.0 =
    4563Add Bookmark, Like, Reply and Repost blocks. Additional title options.
     64
    4665= 0.4.0 =
    4766Add `indieblocks/syndication-links` block.
     67
    4868= 0.3.6 =
    4969Minor bug fix, new plugin URL.
     70
    5071= 0.3.5 =
    5172Fix rescheduling of webmentions from the classic editor.
     73
    5274= 0.3.4 =
    5375Webmention tweaks.
    5476= 0.3.3 =
    5577Slight block changes. Bug fixes, and basic Webmention support.
     78
    5679= 0.2.0 =
    5780Slightly improved "empty" URL handling, and permalink flushing. Additional CPT, feed and Micropub options. Date-based CPT archives, and basic location functions.
     81
    5882= 0.1.0 =
    5983Very first version.
  • indieblocks/trunk/blocks/facepile/block.json

    r2961482 r3002715  
    2929                "fontSize": true
    3030            }
     31        },
     32        "spacing": {
     33            "margin": ["top", "bottom"],
     34            "padding": false,
     35            "blockGap": false
    3136        }
    3237    }
  • indieblocks/trunk/blocks/link-preview/class-link-preview-block.php

    r2993569 r3002715  
    6868
    6969            if ( ! empty( $card['thumbnail'] ) ) :
    70                 // Check if file still exists.
    71                 $upload_dir = wp_upload_dir();
    72                 $file_path  = str_replace( $upload_dir['baseurl'], $upload_dir['basedir'], $card['thumbnail'] );
    73 
    74                 if ( is_file( $file_path ) ) :
    75                     ?>
    76                     <img src="<?php echo esc_url_raw( $card['thumbnail'] ); ?>" width="90" height="90" alt="">
    77                     <?php
    78                 endif;
     70                ?>
     71                <img src="<?php echo esc_url_raw( $card['thumbnail'] ); ?>" width="90" height="90" alt="">
     72                <?php
    7973            endif;
    8074
  • indieblocks/trunk/includes/class-parser.php

    r2993569 r3002715  
    8484
    8585        if ( empty( $mf2 ) ) {
     86            $fragment = wp_parse_url( $this->url, PHP_URL_FRAGMENT );
     87            if ( ! empty( $fragment ) ) {
     88                // If the URL contains a fragment, parse only the corresponding
     89                // page section.
     90                // @todo: Do this for `$this->dom`, too?
     91                $xpath = new \DOMXPath( $this->dom );
     92
     93                foreach ( $xpath->query( "//*[@id='$fragment']" ) as $el ) {
     94                    $content = $this->dom->saveHTML( $el );
     95                    break;
     96                }
     97            }
     98
    8699            $mf2 = Mf2\parse( $content, $this->url );
    87100            set_transient( 'indieblocks:mf2:' . $hash, $mf2, 3600 );
    88101        }
    89102
    90         $this->mf2 = Mf2\parse( $content, $this->url );
     103        $this->mf2 = $mf2;
    91104    }
    92105
     
    297310        if ( ! empty( $this->mf2['items'][0]['properties']['content'][0]['html'] ) ) {
    298311            return $this->mf2['items'][0]['properties']['content'][0]['html'];
     312        } elseif ( ! empty( $this->mf2['items'][0]['properties']['content'][0]['text'] ) ) {
     313            return $this->mf2['items'][0]['properties']['content'][0]['text'];
     314        } elseif ( ! empty( $this->mf2['items'][0]['properties']['content'][0] && is_string( $this->mf2['items'][0]['properties']['content'][0] ) ) ) {
     315            return $this->mf2['items'][0]['properties']['content'][0];
    299316        }
    300317
  • indieblocks/trunk/includes/class-plugin.php

    r2993569 r3002715  
    1212     * Plugin version.
    1313     */
    14     const PLUGIN_VERSION = '0.9.1';
     14    const PLUGIN_VERSION = '0.10.0';
    1515
    1616    /**
  • indieblocks/trunk/includes/class-theme-mf2.php

    r2993569 r3002715  
    178178        $processor->add_class( 'h-card u-author' );
    179179
    180         if ( ! empty( $instance->attributes['avatarSize'] ) ) {
     180        if ( ! empty( $instance->attributes['avatarSize'] ) && ! empty( $instance->attributes['showAvatar'] ) ) {
    181181            $processor->next_tag( 'img' );
    182182            $processor->add_class( 'u-photo' );
     
    481481        }
    482482
    483         $upload_dir = wp_upload_dir();
    484         $file_path  = str_replace( $upload_dir['baseurl'], $upload_dir['basedir'], $url );
    485 
    486         if ( ! is_file( $file_path ) ) {
    487             return null;
    488         }
    489 
    490483        $width  = (int) ( ! empty( $args['width'] ) ? $args['width'] : 96 );
    491484        $height = (int) ( ! empty( $args['height'] ) ? $args['height'] : 96 );
  • indieblocks/trunk/includes/class-webmention-parser.php

    r2961482 r3002715  
    6363        if ( ! empty( $published ) ) {
    6464            $commentdata['comment_date']     = get_date_from_gmt( $published, 'Y-m-d H:i:s' );
    65             $commentdata['comment_date_gmt'] = date( 'Y-m-d H:i:s', strtotime( $published ) );
    66         }
    67 
    68         $commentdata['comment_meta']['indieblocks_webmention_source'] = esc_url_raw( $parser->get_url() ?: $source ); // phpcs:ignore WordPress.PHP.DisallowShortTernary.Found
     65            $commentdata['comment_date_gmt'] = date( 'Y-m-d H:i:s', strtotime( $published ) ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
     66        }
     67
     68        $commentdata['comment_meta']['indieblocks_webmention_source'] = esc_url_raw( $parser->get_url() ?: $source ); // phpcs:ignore Universal.Operators.DisallowShortTernary.Found
    6969
    7070        $hentry_kind = $parser->get_type();
  • indieblocks/trunk/includes/class-webmention-receiver.php

    r2993569 r3002715  
    103103
    104104        $table_name  = $wpdb->prefix . 'indieblocks_webmentions';
    105         $webmentions = $wpdb->get_results( "SELECT id, source, post_id, ip, created_at FROM $table_name WHERE status = 'draft' LIMIT 5" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
     105        $webmentions = $wpdb->get_results( "SELECT id, source, target, post_id, ip, created_at FROM $table_name WHERE status = 'draft' LIMIT 5" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    106106
    107107        if ( empty( $webmentions ) || ! is_array( $webmentions ) ) {
     
    131131                            'key'     => 'indieblocks_webmention_source',
    132132                            'compare' => '=',
    133                             'value'   => esc_url( $webmention->source ),
     133                            'value'   => esc_url_raw( $webmention->source ),
     134                        ),
     135                        array(
     136                            'key'     => 'indieblocks_webmention_target',
     137                            'compare' => 'EXISTS',
     138                        ),
     139                        array(
     140                            'key'     => 'indieblocks_webmention_target',
     141                            'compare' => '=',
     142                            'value'   => esc_url_raw( $webmention->target ),
    134143                        ),
    135144                    ),
     
    205214            $host = wp_parse_url( $webmention->source, PHP_URL_HOST );
    206215
     216            // Look for a target URL fragment (and possible parent comment).
     217            $fragment = wp_parse_url( $webmention->target, PHP_URL_FRAGMENT );
     218            if ( ! empty( $fragment ) && preg_match( '~^comment-\d+$~', $fragment ) ) {
     219                $parent = get_comment( str_replace( 'comment-', '', str_replace( 'comment-', '', $fragment ) ) );
     220            }
     221
    207222            // Some defaults.
    208223            $commentdata = array(
     
    213228                'comment_author_IP'    => $webmention->ip,
    214229                'comment_content'      => __( '&hellip; commented on this.', 'indieblocks' ),
    215                 'comment_parent'       => 0,
     230                'comment_parent'       => ! empty( $parent ) && $webmention->post_id === $parent->comment_post_ID ? $parent->comment_ID : 0,
    216231                'user_id'              => 0,
    217232                'comment_date'         => $webmention->created_at,
     
    220235                'comment_meta'         => array(
    221236                    'indieblocks_webmention_source' => esc_url_raw( $webmention->source ),
     237                    'indieblocks_webmention_target' => esc_url_raw( $webmention->target ),
    222238                ),
    223239            );
     
    371387
    372388            // Delete file.
    373             if ( is_file( $file_path ) ) {
    374                 wp_delete_file( $file_path );
    375             }
    376 
    377             // Delete reference in database.
    378             delete_comment_meta( $comment_id, 'indieblocks_webmention_avatar' );
     389            wp_delete_file( $file_path );
     390
     391            // Delete _all_ references to this file (i.e., not just this
     392            // comment's meta field).
     393            global $wpdb;
     394
     395            $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
     396                $wpdb->prepare(
     397                    "DELETE FROM $wpdb->commentmeta WHERE meta_key = %s AND meta_value = %s",
     398                    'indieblocks_webmention_avatar',
     399                    esc_url_raw( $url )
     400                )
     401            );
    379402        }
    380403
  • indieblocks/trunk/includes/class-webmention-sender.php

    r2993569 r3002715  
    1818     * callback function queued in the background.
    1919     *
    20      * @param string  $new_status New post status.
    21      * @param string  $old_status Old post status.
    22      * @param WP_Post $post       Post object.
    23      */
    24     public static function schedule_webmention( $new_status, $old_status, $post ) {
    25         if ( wp_is_post_revision( $post->ID ) || wp_is_post_autosave( $post->ID ) ) {
    26             return;
    27         }
    28 
    29         /* @see https://github.com/WordPress/gutenberg/issues/15094#issuecomment-1021288811. */
    30         if ( ! empty( $_REQUEST['meta-box-loader'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    31             // Avoid scheduling (or posting, in case of no delay) webmentions
    32             // more than once.
    33             return;
     20     * @param int                  $obj_id     Post or comment ID.
     21     * @param \WP_Post|\WP_Comment $obj        Post or comment object.
     22     * @param mixed                $deprecated Used to be the post object, now deprecated.
     23     */
     24    public static function schedule_webmention( $obj_id, $obj = null, $deprecated = null ) {
     25        if ( null !== $deprecated ) {
     26            _deprecated_argument( 'post', '0.10.0', 'Passing a third argument to `\IndieBlocks\Webmention_Sender::schedule_webmention()` is deprecated.' );
    3427        }
    3528
     
    3932        }
    4033
    41         if ( 'publish' !== $new_status ) {
     34        if ( 'comment_post' === current_filter() ) {
     35            $obj = get_comment( $obj_id );
     36        }
     37
     38        if ( $obj instanceof \WP_Post ) {
     39            if ( 'publish' !== $obj->post_status ) {
     40                // Do not send webmention on delete/unpublish, for now.
     41                return;
     42            }
     43
     44            /* @see https://github.com/WordPress/gutenberg/issues/15094#issuecomment-1021288811. */
     45            if ( ! empty( $_REQUEST['meta-box-loader'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
     46                // Avoid scheduling (or posting, in case of no delay) webmentions
     47                // more than once.
     48                return;
     49            }
     50
     51            if ( wp_is_post_revision( $obj->ID ) || wp_is_post_autosave( $obj->ID ) ) {
     52                return;
     53            }
     54
     55            if ( ! in_array( $obj->post_type, Webmention::get_supported_post_types(), true ) ) {
     56                return;
     57            }
     58        } elseif ( '1' !== $obj->comment_approved ) {
    4259            // Do not send webmention on delete/unpublish, for now.
    4360            return;
    4461        }
    4562
    46         if ( ! in_array( $post->post_type, Webmention::get_supported_post_types(), true ) ) {
    47             return;
    48         }
    49 
    50         // Fetch our post's HTML.
    51         $html = apply_filters( 'the_content', $post->post_content );
    52 
    53         // Scan it for outgoing links.
    54         $urls = static::find_outgoing_links( $html );
    55 
    56         // Parse in targets that may have been there previously, but don't delete
    57         // them, yet.
    58         $history = get_post_meta( $post->ID, '_indieblocks_webmention_history', true );
     63        $urls = array();
     64
     65        if ( $obj instanceof \WP_Post ) {
     66            // Fetch our post's HTML.
     67            $html = apply_filters( 'the_content', $obj->post_content );
     68
     69            // Scan it for outgoing links.
     70            $urls = static::find_outgoing_links( $html );
     71        } elseif ( ! empty( $obj->comment_parent ) ) {
     72            // Add in the parent's, if any, Webmention source.
     73            $source = get_comment_meta( $obj->comment_parent, 'indieblocks_webmention_source', true );
     74            if ( ! empty( $source ) ) {
     75                $urls[] = $source;
     76            }
     77        }
     78
     79        // Parse in targets that may have been there previously, but don't
     80        // delete them, yet.
     81        $history = get_meta( $obj, '_indieblocks_webmention_history' );
     82
    5983        if ( ! empty( $history ) && is_array( $history ) ) {
    60             $urls = array_unique( array_merge( $urls, $history ) );
    61         }
    62 
    63         if ( empty( $urls ) || ! is_array( $urls ) ) {
     84            $urls = array_merge( $urls, $history );
     85        }
     86
     87        if ( empty( $urls ) ) {
    6488            // Nothing to do. Bail.
    6589            return;
    6690        }
    6791
     92        $urls     = array_unique( $urls );
    6893        $schedule = false;
    6994
     
    91116
    92117                // Schedule sending out the actual webmentions.
    93                 error_log( "[Indieblocks/Webmention] Scheduling webmention for post {$post->ID}." ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
    94                 wp_schedule_single_event( time() + $delay, 'indieblocks_webmention_send', array( $post->ID ) );
    95 
    96                 add_post_meta( $post->ID, '_indieblocks_webmention', 'scheduled', true ); // Does not affect existing values.
     118                if ( $obj instanceof \WP_Post ) {
     119                    error_log( "[Indieblocks/Webmention] Scheduling webmention for post {$obj->ID}." ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
     120                } else {
     121                    error_log( "[Indieblocks/Webmention] Scheduling webmention for comment {$obj->comment_ID}." ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
     122                }
     123
     124                add_meta( $obj, '_indieblocks_webmention', 'scheduled' );
     125                wp_schedule_single_event( time() + $delay, 'indieblocks_webmention_send', array( $obj ) );
    97126            } else {
    98127                // Send inline (although retries will be scheduled as always).
    99                 static::send_webmention( $post->ID );
     128                static::send_webmention( $obj );
    100129            }
    101130        }
     
    106135     * a post.
    107136     *
    108      * @param int $post_id Post ID.
    109      */
    110     public static function send_webmention( $post_id ) {
    111         $post = get_post( $post_id );
    112 
    113         if ( 'publish' !== $post->post_status ) {
    114             // Do not send webmentions on delete/unpublish, for now.
    115             return;
    116         }
    117 
    118         if ( ! in_array( $post->post_type, Webmention::get_supported_post_types(), true ) ) {
    119             // This post type doesn't support Webmention.
    120             return;
    121         }
    122 
    123         // Fetch our post's HTML.
    124         $html = apply_filters( 'the_content', $post->post_content );
    125 
    126         // Scan it for outgoing links, again, as things might have changed.
    127         $urls = static::find_outgoing_links( $html );
    128 
    129         // Parse in (and then forget) targets that may have been there before.
     137     * @param \WP_Post|\WP_Comment $obj Post or comment object.
     138     */
     139    public static function send_webmention( $obj ) {
     140        if ( $obj instanceof \WP_Post ) {
     141            if ( 'publish' !== $obj->post_status ) {
     142                // Do not send webmention on delete/unpublish, for now.
     143                return;
     144            }
     145
     146            if ( ! in_array( $obj->post_type, Webmention::get_supported_post_types(), true ) ) {
     147                // This post type doesn't support Webmention.
     148                return;
     149            }
     150        } elseif ( '1' !== $obj->comment_approved ) {
     151            return;
     152        }
     153
     154        $urls = array();
     155
     156        if ( $obj instanceof \WP_Post ) {
     157            // Fetch our post's HTML.
     158            $html = apply_filters( 'the_content', $obj->post_content );
     159
     160            // Scan it for outgoing links.
     161            $urls = static::find_outgoing_links( $html );
     162        } elseif ( ! empty( $obj->comment_parent ) ) {
     163            // Add in the parent's, if any, Webmention source.
     164            $source = get_comment_meta( $obj->comment_parent, 'indieblocks_webmention_source', true );
     165            if ( ! empty( $source ) ) {
     166                $urls[] = $source;
     167            }
     168        }
     169
     170        // Parse in (_and_ then forget) targets that may have been there before.
    130171        // This also means that "historic" targets are excluded from retries!
    131172        // Note that we _also_ retarget pages that threw an error or we
    132173        // otherwise failed to reach previously. Both are probably acceptable.
    133         $history = get_post_meta( $post->ID, '_indieblocks_webmention_history', true );
    134         delete_post_meta( $post->ID, '_indieblocks_webmention_history' );
     174        $history = get_meta( $obj, '_indieblocks_webmention_history' );
     175        delete_meta( $obj, '_indieblocks_webmention_history' );
     176
    135177        if ( ! empty( $history ) && is_array( $history ) ) {
    136             $urls = array_unique( array_merge( $urls, $history ) );
    137         }
    138 
    139         if ( empty( $urls ) || ! is_array( $urls ) ) {
     178            $urls = array_merge( $urls, $history );
     179        }
     180
     181        if ( empty( $urls ) ) {
    140182            // One or more links must've been removed. Nothing to do. Bail.
    141183            return;
    142184        }
    143185
     186        $urls = array_unique( $urls );
     187
    144188        // Fetch whatever Webmention-related stats we've got for this post.
    145         $webmention = get_post_meta( $post->ID, '_indieblocks_webmention', true );
     189        $webmention = get_meta( $obj, '_indieblocks_webmention' );
    146190
    147191        if ( empty( $webmention ) || ! is_array( $webmention ) ) {
     
    157201            if ( empty( $endpoint ) || false === wp_http_validate_url( $endpoint ) ) {
    158202                // Skip.
     203                error_log( '[Indieblocks/Webmention] Could not find a Webmention endpoint for target ' . esc_url_raw( $url ) . '.' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
    159204                continue;
    160205            }
     
    190235                array(
    191236                    'body' => array(
    192                         'source' => get_permalink( $post->ID ),
     237                        'source' => $obj instanceof \WP_Post ? get_permalink( $obj->ID ) : get_comment_link( $obj->comment_ID ),
    193238                        'target' => $url,
    194239                    ),
     
    196241            );
    197242
    198             if ( is_wp_error( $response ) ) {
     243            if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) >= 500 ) {
    199244                // Something went wrong.
    200245                error_log( '[Indieblocks/Webmention] Error trying to send a webmention to ' . esc_url_raw( $endpoint ) . ': ' . $response->get_error_message() ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
     246                error_log( print_r( $response, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log,WordPress.PHP.DevelopmentFunctions.error_log_print_r
    201247
    202248                $webmention[ $hash ]['retries'] = $retries + 1;
    203                 update_post_meta( $post->ID, '_indieblocks_webmention', $webmention );
     249
     250                update_meta( $obj, '_indieblocks_webmention', $webmention );
    204251
    205252                // Schedule a retry in 5 to 15 minutes.
    206                 wp_schedule_single_event( time() + wp_rand( 300, 900 ), 'indieblocks_webmention_send', array( $post->ID ) );
    207 
    208                 continue;
    209             } elseif ( wp_remote_retrieve_response_code( $response ) >= 500 ) {
    210                 // Something went wrong.
    211                 error_log( '[Indieblocks/Webmention] Error trying to send a webmention to ' . esc_url_raw( $endpoint ) . '.' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
    212                 error_log( print_r( $response, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log,WordPress.PHP.DevelopmentFunctions.error_log_print_r
    213 
    214                 $webmention[ $hash ]['retries'] = $retries + 1;
    215                 update_post_meta( $post->ID, '_indieblocks_webmention', $webmention );
    216 
    217                 // Schedule a retry in 5 to 15 minutes.
    218                 wp_schedule_single_event( time() + wp_rand( 300, 900 ), 'indieblocks_webmention_send', array( $post->ID ) );
     253                wp_schedule_single_event( time() + wp_rand( 300, 900 ), 'indieblocks_webmention_send', array( $obj ) );
    219254
    220255                continue;
     
    228263        }
    229264
    230         update_post_meta( $post->ID, '_indieblocks_webmention', $webmention );
     265        update_meta( $obj, '_indieblocks_webmention', $webmention );
    231266    }
    232267
     
    463498
    464499        $post = get_post( $post_id );
    465         static::schedule_webmention( $post->post_status, $post->post_status, $post );
     500        static::schedule_webmention( $post_id, $post );
    466501
    467502        wp_die();
  • indieblocks/trunk/includes/class-webmention.php

    r2993569 r3002715  
    2424
    2525        add_action( 'add_meta_boxes', array( Webmention_Sender::class, 'add_meta_box' ) );
    26         add_action( 'transition_post_status', array( Webmention_Sender::class, 'schedule_webmention' ), 10, 3 );
     26
     27        foreach ( static::get_supported_post_types() as $post_type ) {
     28            add_action( "publish_{$post_type}", array( Webmention_Sender::class, 'schedule_webmention' ), 10, 2 );
     29        }
     30
     31        // When a comment is first inserted into the database.
     32        add_action( 'comment_post', array( Webmention_Sender::class, 'schedule_webmention' ) ); // Pass only one argument (the comment ID) to `Webmention_Sender::schedule_webmention()`!
     33        // When a comment is approved. Or a previously approved comment updated.
     34        add_action( 'comment_approved_comment', array( Webmention_Sender::class, 'schedule_webmention' ), 10, 2 );
     35
    2736        add_action( 'indieblocks_webmention_send', array( Webmention_Sender::class, 'send_webmention' ) );
    2837
  • indieblocks/trunk/includes/functions.php

    r2993569 r3002715  
    3939 */
    4040function debug_log( $item ) {
    41     error_log( print_r( $item, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log,WordPress.PHP.DevelopmentFunctions.error_log_print_r
     41    error_log( is_string( $item ) ? $item : print_r( $item, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log,WordPress.PHP.DevelopmentFunctions.error_log_print_r
    4242}
    4343
     
    283283            }
    284284        } else {
    285             debug_log( '[IndieBlocks] Could not reisize ' . $file_path . ': ' . $image->get_error_message() . '.' );
     285            debug_log( '[IndieBlocks] Could not resize ' . $file_path . ': ' . $image->get_error_message() . '.' );
    286286        }
    287287
     
    376376    return $facepile_comments;
    377377}
     378
     379/**
     380 * Get post or comment meta.
     381 *
     382 * @param  \WP_Post|\WP_Comment $obj      Post or comment.
     383 * @param  string               $meta_key The meta key.
     384 * @return string                         The meta value (or an empty) string.
     385 */
     386function get_meta( $obj, $meta_key ) {
     387    if ( $obj instanceof \WP_Post ) {
     388        return get_post_meta( $obj->ID, $meta_key, true );
     389    }
     390
     391    if ( $obj instanceof \WP_Comment ) {
     392        return get_comment_meta( $obj->comment_ID, $meta_key, true );
     393    }
     394
     395    return '';
     396}
     397
     398/**
     399 * Update post or comment meta.
     400 *
     401 * @param  \WP_Post|\WP_Comment $obj        Post or comment.
     402 * @param  string               $meta_key   The meta key.
     403 * @param  mixed                $meta_value The value.
     404 */
     405function add_meta( $obj, $meta_key, $meta_value ) {
     406    if ( $obj instanceof \WP_Post ) {
     407        add_post_meta( $obj->ID, $meta_key, $meta_value );
     408    }
     409
     410    if ( $obj instanceof \WP_Comment ) {
     411        add_comment_meta( $obj->comment_ID, $meta_key, $meta_value );
     412    }
     413}
     414
     415/**
     416 * Update post or comment meta.
     417 *
     418 * @param  \WP_Post|\WP_Comment $obj        Post or comment.
     419 * @param  string               $meta_key   The meta key.
     420 * @param  mixed                $meta_value The value.
     421 */
     422function update_meta( $obj, $meta_key, $meta_value ) {
     423    if ( $obj instanceof \WP_Post ) {
     424        update_post_meta( $obj->ID, $meta_key, $meta_value );
     425    }
     426
     427    if ( $obj instanceof \WP_Comment ) {
     428        update_comment_meta( $obj->comment_ID, $meta_key, $meta_value );
     429    }
     430}
     431
     432/**
     433 * Delete post or comment meta.
     434 *
     435 * @param  \WP_Post|\WP_Comment $obj      Post or comment.
     436 * @param  string               $meta_key The meta key.
     437 */
     438function delete_meta( $obj, $meta_key ) {
     439    if ( $obj instanceof \WP_Post ) {
     440        delete_post_meta( $obj->ID, $meta_key );
     441    }
     442
     443    if ( $obj instanceof \WP_Comment ) {
     444        delete_comment_meta( $obj->comment_ID, $meta_key );
     445    }
     446}
  • indieblocks/trunk/indieblocks.php

    r2993569 r3002715  
    99 * License URI:       http://www.gnu.org/licenses/gpl-3.0.html
    1010 * Text Domain:       indieblocks
    11  * Version:           0.9.1
     11 * Version:           0.10.0
    1212 * Requires at least: 6.2
    1313 * GitHub Plugin URI: https://github.com/janboddez/indieblocks
  • indieblocks/trunk/languages/indieblocks.pot

    r2993569 r3002715  
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: IndieBlocks 0.9.1\n"
     5"Project-Id-Version: IndieBlocks 0.10.0\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/indieblocks\n"
    77"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
     
    1010"Content-Type: text/plain; charset=UTF-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "POT-Creation-Date: 2023-11-08T20:41:32+00:00\n"
     12"POT-Creation-Date: 2023-11-26T22:12:55+01:00\n"
    1313"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    14 "X-Generator: WP-CLI 2.6.0\n"
     14"X-Generator: WP-CLI 2.9.0\n"
    1515"X-Domain: indieblocks\n"
    1616
     
    165165#: includes/class-options-handler.php:376
    166166#: includes/class-options-handler.php:479
    167 #: includes/class-webmention-receiver.php:288
    168 #: includes/class-webmention-sender.php:372
     167#: includes/class-webmention-receiver.php:304
     168#: includes/class-webmention-sender.php:416
    169169msgid "Webmention"
    170170msgstr ""
     
    548548msgstr ""
    549549
    550 #: includes/class-webmention-receiver.php:214
     550#: includes/class-webmention-receiver.php:229
    551551msgid "&hellip; commented on this."
    552552msgstr ""
    553553
    554 #: includes/class-webmention-receiver.php:307
     554#: includes/class-webmention-receiver.php:323
    555555msgid "Source"
    556556msgstr ""
    557557
    558 #: includes/class-webmention-receiver.php:310
     558#: includes/class-webmention-receiver.php:326
    559559#: blocks/context/block.js:67
    560560msgid "Type"
    561561msgstr ""
    562562
    563 #: includes/class-webmention-receiver.php:314
     563#: includes/class-webmention-receiver.php:330
    564564msgid "Avatar"
    565565msgstr ""
    566566
    567 #: includes/class-webmention-receiver.php:318
     567#: includes/class-webmention-receiver.php:334
    568568msgid "Delete"
    569569msgstr ""
    570570
    571 #: includes/class-webmention-receiver.php:348
    572 #: includes/class-webmention-sender.php:439
     571#: includes/class-webmention-receiver.php:364
     572#: includes/class-webmention-sender.php:483
    573573msgid "Missing or invalid nonce."
    574574msgstr ""
    575575
    576 #: includes/class-webmention-receiver.php:354
     576#: includes/class-webmention-receiver.php:370
    577577msgid "Invalid comment ID."
    578578msgstr ""
    579579
    580 #: includes/class-webmention-receiver.php:362
    581 #: includes/class-webmention-sender.php:453
     580#: includes/class-webmention-receiver.php:378
     581#: includes/class-webmention-sender.php:497
    582582msgid "Insufficient rights."
    583583msgstr ""
    584584
    585585#. translators: 1: Webmention endpoint 2: Date sent
    586 #: includes/class-webmention-sender.php:404
     586#: includes/class-webmention-sender.php:448
    587587msgid "Sent to %1$s on %2$s. Response code: %3$d."
    588588msgstr ""
    589589
    590590#. translators: 1: Webmention endpoint 2: Date sent
    591 #: includes/class-webmention-sender.php:404
     591#: includes/class-webmention-sender.php:448
    592592msgid "M j, Y \\a\\t H:i"
    593593msgstr ""
    594594
    595595#. translators: Webmention endpoint
    596 #: includes/class-webmention-sender.php:407
     596#: includes/class-webmention-sender.php:451
    597597msgid "Could not send webmention to %s."
    598598msgstr ""
    599599
    600600#. translators: Webmention endpoint
    601 #: includes/class-webmention-sender.php:410
     601#: includes/class-webmention-sender.php:454
    602602msgid "Could not send webmention to %s. Trying again soon."
    603603msgstr ""
    604604
    605 #: includes/class-webmention-sender.php:420
     605#: includes/class-webmention-sender.php:464
    606606msgid "Resend"
    607607msgstr ""
    608608
    609 #: includes/class-webmention-sender.php:424
    610 #: includes/class-webmention.php:143
     609#: includes/class-webmention-sender.php:468
     610#: includes/class-webmention.php:152
    611611msgid "Webmention scheduled."
    612612msgstr ""
    613613
    614 #: includes/class-webmention-sender.php:426
     614#: includes/class-webmention-sender.php:470
    615615msgid "No endpoints found."
    616616msgstr ""
    617617
    618 #: includes/class-webmention-sender.php:445
     618#: includes/class-webmention-sender.php:489
    619619msgid "Invalid post ID."
    620620msgstr ""
  • indieblocks/trunk/readme.txt

    r2993569 r3002715  
    33Tags: blocks, gutenberg, indieweb, notes, likes, microblog, microblogging, micropub, fse, site editor, webmention, syndication
    44Tested up to: 6.4
    5 Stable tag: 0.9.1
     5Stable tag: 0.10.0
    66License: GNU General Public License v3.0
    77License URI: https://www.gnu.org/licenses/gpl-3.0.html
     
    1010
    1111== Description ==
     12Use blocks, and, optionally, "short-form" post types to easily "IndieWebify" your WordPress site.
     13
    1214IndieBlocks registers several blocks (Bookmark, Like, Reply, and Repost, as well as the older Context block) that take a URL and output corresponding _microformatted_ HTML.
    1315
     
    1820These microformats, in combination with the Webmention protocol, allow for rich _cross-site_ conversations. IndieBlocks comes with its own Webmention implementation, but a separate plugin can be used, too.
    1921
    20 IndieBlocks also registers several "theme" blocks (Facepile, Location, Syndication, and Link Preview), to be used in (block) theme templates.
     22IndieBlocks also registers several "theme" blocks (Facepile, Location, Syndication, and Link Preview), to be used in "block theme" templates.
    2123
    2224== Installation ==
     
    2729More details can be found on [https://indieblocks.xyz/](https://indieblocks.xyz/). Issues may be filed at [https://github.com/janboddez/indieblocks](https://github.com/janboddez/indieblocks).
    2830
     31== Frequently Asked Questions ==
     32= How does this plugin interact with the various other IndieWeb plugins? =
     33While IndieBlocks does not depend on _any_ other plugin, it is compatible with, and extends, the Micropub plugin for WordPress. See [https://indieblocks.xyz/documentation/micropub-and-indieauth/](https://indieblocks.xyz/documentation/micropub-and-indieauth/) for some more information.
     34
     35IndieBlocks&rsquo; Facepile and Syndication blocks also aim to be compatible with, respectively, the Webmention and Syndication Links plugins.
     36
    2937== Changelog ==
     38= 0.10.0 =
     39Send webmentions also for comments, to mentioned sites and the comment parent, if it exists and itself originated as a webmention.
     40
    3041= 0.9.1 =
    3142Fix Webmention backlinks in Facepile block, add avatar background and icon color pickers.
     43
    3244= 0.9.0 =
    3345Overhaul theme microformats functionality.
     46
    3447= 0.8.1 =
    3548Fix issue with saving meta from block editor. Fix Markdown in Micropub notes.
     49
    3650= 0.8.0 =
    3751Various bug fixes. Add Link Preview block. Also, webmentions are now closed when comments are, although this behavior is filterable.
     52
    3853= 0.7.1 =
    3954Add Location block. The Facepile block now supports v5.0 and up of the Webmention plugin.
     55
    4056= 0.7.0 =
    4157Store temperatures in Kelvin rather than degrees Celsius. Update `masterminds/html5` to version 2.8.0. Add Location block.
     58
    4259= 0.6.0 =
    4360"Facepile" likes, bookmarks, and reposts.
     61
    4462= 0.5.0 =
    4563Add Bookmark, Like, Reply and Repost blocks. Additional title options.
     64
    4665= 0.4.0 =
    4766Add `indieblocks/syndication-links` block.
     67
    4868= 0.3.6 =
    4969Minor bug fix, new plugin URL.
     70
    5071= 0.3.5 =
    5172Fix rescheduling of webmentions from the classic editor.
     73
    5274= 0.3.4 =
    5375Webmention tweaks.
    5476= 0.3.3 =
    5577Slight block changes. Bug fixes, and basic Webmention support.
     78
    5679= 0.2.0 =
    5780Slightly improved "empty" URL handling, and permalink flushing. Additional CPT, feed and Micropub options. Date-based CPT archives, and basic location functions.
     81
    5882= 0.1.0 =
    5983Very first version.
Note: See TracChangeset for help on using the changeset viewer.