diff --git a/.distignore b/.distignore
index d50d9f0..f883b76 100644
--- a/.distignore
+++ b/.distignore
@@ -4,6 +4,7 @@
/node_modules
/bin
/sass
+/src
/vendor
/tests
/config
diff --git a/.editorconfig b/.editorconfig
index 43b737f..ea6c38c 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -11,7 +11,3 @@ charset = utf-8
[*.php]
indent_style = tab
indent_size = 4
-
-[*.{js,json}]
-indent_style = space
-indent_size = 2
diff --git a/build/editor-plugin/block.json b/build/editor-plugin/block.json
new file mode 100644
index 0000000..f41effc
--- /dev/null
+++ b/build/editor-plugin/block.json
@@ -0,0 +1,8 @@
+{
+ "name": "editor-plugin",
+ "title": "Editor Plugin: not a block, but block.json is very useful.",
+ "category": "widgets",
+ "icon": "admin-comments",
+ "keywords": [],
+ "editorScript": "file:./plugin.js"
+}
\ No newline at end of file
diff --git a/build/editor-plugin/plugin.asset.php b/build/editor-plugin/plugin.asset.php
new file mode 100644
index 0000000..726932c
--- /dev/null
+++ b/build/editor-plugin/plugin.asset.php
@@ -0,0 +1 @@
+ array('react', 'wp-components', 'wp-core-data', 'wp-data', 'wp-editor', 'wp-i18n', 'wp-plugins'), 'version' => '03845d869ccb1b1eb23c');
diff --git a/build/editor-plugin/plugin.js b/build/editor-plugin/plugin.js
new file mode 100644
index 0000000..b27222a
--- /dev/null
+++ b/build/editor-plugin/plugin.js
@@ -0,0 +1 @@
+(()=>{"use strict";const e=window.React,n=window.wp.editor,t=window.wp.plugins,o=window.wp.components,i=window.wp.data,w=window.wp.coreData,s=window.wp.i18n;(0,t.registerPlugin)("webmention-editor-plugin",{render:()=>{const t=(0,i.useSelect)((e=>e("core/editor").getCurrentPostType()),[]),[r,a]=(0,w.useEntityProp)("postType",t,"meta");return(0,e.createElement)(n.PluginDocumentSettingPanel,{name:"webmention",title:(0,s.__)("Webmentions","webmention")},(0,e.createElement)(o.CheckboxControl,{__nextHasNoMarginBottom:!0,label:(0,s.__)("Disable Webmentions","webmention"),help:(0,s.__)("Do not accept incoming Webmentions for this post.","webmention"),checked:r.webmentions_disabled,onChange:e=>{a({...r,webmentions_disabled:e})}}))}})})();
\ No newline at end of file
diff --git a/includes/class-block.php b/includes/class-block.php
new file mode 100644
index 0000000..581d597
--- /dev/null
+++ b/includes/class-block.php
@@ -0,0 +1,47 @@
+ true,
+ 'single' => true,
+ 'type' => 'boolean',
+ )
+ );
+ }
+ }
+
+ /**
+ * Enqueue the block editor assets.
+ */
+ public static function enqueue_editor_assets() {
+ // Check for our supported post types.
+ $current_screen = \get_current_screen();
+ $ap_post_types = \get_post_types_by_support( 'webmentions' );
+ if ( ! $current_screen || ! in_array( $current_screen->post_type, $ap_post_types, true ) ) {
+ return;
+ }
+ $asset_data = include WEBMENTION_PLUGIN_DIR . 'build/editor-plugin/plugin.asset.php';
+ $plugin_url = plugins_url( 'build/editor-plugin/plugin.js', WEBMENTION_PLUGIN_FILE );
+ wp_enqueue_script( 'webmention-block-editor', $plugin_url, $asset_data['dependencies'], $asset_data['version'], true );
+ }
+}
diff --git a/includes/class-receiver.php b/includes/class-receiver.php
index f782d0e..f82305b 100755
--- a/includes/class-receiver.php
+++ b/includes/class-receiver.php
@@ -242,7 +242,7 @@ public static function post( $request ) {
// check if webmentions are allowed
if ( ! webmentions_open( $comment_post_id ) ) {
- return new WP_Error( 'webmentions_closed', esc_html__( 'Webmentions are disabled for this post', 'webmention' ), array( 'status' => 400 ) );
+ return new WP_Error( 'webmentions_disabled', esc_html__( 'Webmentions are disabled for this post', 'webmention' ), array( 'status' => 400 ) );
}
$post = get_post( $comment_post_id );
diff --git a/includes/class-sender.php b/includes/class-sender.php
index 3269f49..7063ca7 100755
--- a/includes/class-sender.php
+++ b/includes/class-sender.php
@@ -208,14 +208,15 @@ public static function send_webmentions( $post_id ) {
$urls = webmention_extract_urls( $post->post_content, $support_media_urls );
// filter links
- $targets = apply_filters( 'webmention_links', $urls, $post_id );
- $targets = array_unique( $targets );
- $pung = get_pung( $post );
+ $targets = apply_filters( 'webmention_links', $urls, $post_id );
+ $targets = array_unique( $targets );
+ $mentioned = get_post_meta( $post->ID, '_webmentioned', true );
+ $mentioned = empty( $mentioned ) ? array() : $mentioned;
// Find previously sent Webmentions and send them one last time.
- $deletes = array_diff( $pung, $targets );
+ $deletes = array_diff( $mentioned, $targets );
- $ping = array();
+ $mentions = array();
foreach ( $targets as $target ) {
// send Webmention
@@ -225,16 +226,13 @@ public static function send_webmentions( $post_id ) {
continue;
}
- // check response
- if (
- ! is_wp_error( $response ) &&
- wp_remote_retrieve_response_code( $response ) < 400
- ) {
- $ping[] = $target;
- }
+ $code = wp_remote_retrieve_response_code( $response );
- // reschedule if server responds with a http error 5xx
- if ( wp_remote_retrieve_response_code( $response ) >= 500 ) {
+ // check response
+ if ( ! is_wp_error( $response ) && $code < 400 ) {
+ $mentions[] = $target;
+ } elseif ( $code >= 500 ) {
+ // reschedule if server responds with a http error 5xx
self::reschedule( $post_id );
}
}
@@ -246,23 +244,23 @@ public static function send_webmentions( $post_id ) {
// reschedule if server responds with a http error 5xx
if ( wp_remote_retrieve_response_code( $response ) >= 500 ) {
self::reschedule( $post_id );
- $ping[] = $deleted;
+ $mentions[] = $deleted;
}
}
+ if ( ! empty( $mentions ) ) {
+ update_post_meta( $post_id, '_webmentioned', $mentions );
+ }
+
+ $pung = get_pung( $post );
+
if ( ! empty( $ping ) ) {
- self::update_ping( $post, $ping );
+ self::update_ping( $post, array_merge( $pung, $ping ) );
}
- return $ping;
+ return $mentions;
}
- /*
- * Update the Pinged List as Opposed to Adding to It.
- *
- * @param int|WP_Post $post_id Post.
- * @param array $pinged Array of URLs
- */
public static function update_ping( $post_id, $pinged ) {
global $wpdb;
$post = get_post( $post_id );
diff --git a/includes/functions.php b/includes/functions.php
index 532c3ef..d2d0416 100644
--- a/includes/functions.php
+++ b/includes/functions.php
@@ -550,18 +550,22 @@ function ifset( &$var, $return = false ) { // phpcs:ignore Universal.NamingConve
* @return boolean if webmentions are open
*/
function webmentions_open( $post = null ) {
- $_post = get_post( $post );
- $post_id = $_post ? $_post->ID : 0;
-
- // If the post type does not support Webmentions do not even check further
- if ( ! post_type_supports( get_post_type( $post_id ), 'webmentions' ) ) {
- return false;
+ $post = get_post( $post );
+ $post_id = $post ? $post->ID : 0;
+ $open = false;
+ if ( $post ) {
+ // Always consider the home mention link page to be open.
+ if ( get_option( 'webmention_home_mentions' ) === $post->ID ) {
+ $open = true;
+ } elseif ( ! post_type_supports( get_post_type( $post ), 'webmentions' ) ) {
+ // If the post type does not support Webmentions do not even check further.
+ $open = false;
+ } else {
+ // If the webmentions_disabled meta key exists then consider webmentions closed. Otherwise consider them open.
+ $open = ! ( metadata_exists( 'post', $post_id, 'webmentions_disabled' ) ); // Invert the result, as exists is closed and not exists is open.
+ }
}
- if ( get_option( 'webmention_home_mentions' ) === $post_id ) {
- return true;
- }
- $open = ( $_post && ( pings_open( $post ) ) );
/**
* Filters whether the current post is open for webmentions.
*
@@ -572,23 +576,6 @@ function webmentions_open( $post = null ) {
return apply_filters( 'webmentions_open', $open, $post_id );
}
-/**
- * Return enabled status of Homepage Webmentions.
- *
- * @since 3.8.9
- *
- * @param bool $open Whether the current post is open for pings.
- * @param int $post_id The post ID.
- * @return boolean if pings are open
- */
-function webmention_pings_open( $open, $post_id ) {
- if ( get_option( 'webmention_home_mentions' ) === $post_id ) {
- return true;
- }
-
- return $open;
-}
-
/**
* Retrieve the default comment status for a given post type.
*
@@ -602,16 +589,7 @@ function webmention_pings_open( $open, $post_id ) {
* @return string
*/
function webmention_get_default_comment_status( $status, $post_type, $comment_type ) {
- if ( 'webmention' === $comment_type ) {
- return post_type_supports( $post_type, 'webmentions' ) ? 'open' : 'closed';
- }
-
- // Since support for the pingback comment type is used to keep pings open...
- if ( ( 'pingback' === $comment_type ) ) {
- return ( post_type_supports( $post_type, 'webmentions' ) ? 'open' : $status );
- }
-
- return $status;
+ return is_registered_webmention_comment_type( $comment_type ) ? 'open' : $status;
}
/**
@@ -707,3 +685,31 @@ function is_html( $string ) { // phpcs:ignore Universal.NamingConventions.NoRese
return ( wp_strip_all_tags( $string ) !== $string );
}
}
+
+/**
+ * Check if a site supports the block editor.
+ *
+ * @return boolean True if the site supports the block editor, false otherwise.
+ */
+function site_supports_blocks() {
+ $return = true;
+
+ if ( \version_compare( \get_bloginfo( 'version' ), '5.9', '<' ) ) {
+ $return = false;
+ } elseif ( \function_exists( 'classicpress_version' ) ) {
+ $return = false;
+ } elseif (
+ ! \function_exists( 'register_block_type_from_metadata' ) ||
+ ! \function_exists( 'do_blocks' )
+ ) {
+ $return = false;
+ }
+
+ /**
+ * Allow plugins to disable block editor support,
+ * thus disabling blocks registered by the Webmentions plugin.
+ *
+ * @param boolean $supports_blocks True if the site supports the block editor, false otherwise.
+ */
+ return apply_filters( 'webmention_site_supports_blocks', $return );
+}
diff --git a/package.json b/package.json
index 64be192..5c1d17d 100644
--- a/package.json
+++ b/package.json
@@ -3,6 +3,10 @@
"description": "Webmention support for WordPress posts",
"main": "webmention.php",
"devDependencies": {
+ "@wordpress/components": "^28.0.0",
+ "@wordpress/data": "^10.0.0",
+ "@wordpress/env": "^10.10.0",
+ "@wordpress/icons": "^10.10.0"
},
"repository": {
"type": "git",
@@ -19,5 +23,12 @@
"bugs": {
"url": "https://github.com/pfefferle/wordpress-webmention/issues"
},
- "homepage": "https://github.com/pfefferle/wordpress-webmention"
+ "homepage": "https://github.com/pfefferle/wordpress-webmention",
+ "scripts": {
+ "dev": "wp-scripts start",
+ "build": "wp-scripts build",
+ "readme": "grunt wp_readme_to_markdown",
+ "env-start": "wp-env start",
+ "env-stop": "wp-env stop"
+ }
}
diff --git a/src/editor-plugin/block.json b/src/editor-plugin/block.json
new file mode 100644
index 0000000..119a62d
--- /dev/null
+++ b/src/editor-plugin/block.json
@@ -0,0 +1,8 @@
+{
+ "name": "editor-plugin",
+ "title": "Editor Plugin: not a block, but block.json is very useful.",
+ "category": "widgets",
+ "icon": "admin-comments",
+ "keywords": [],
+ "editorScript": "file:./plugin.js"
+}
diff --git a/src/editor-plugin/plugin.js b/src/editor-plugin/plugin.js
new file mode 100644
index 0000000..de82c7e
--- /dev/null
+++ b/src/editor-plugin/plugin.js
@@ -0,0 +1,34 @@
+import { PluginDocumentSettingPanel } from '@wordpress/editor';
+import { registerPlugin } from '@wordpress/plugins';
+import { CheckboxControl } from '@wordpress/components';
+import { useSelect } from '@wordpress/data';
+import { useEntityProp } from '@wordpress/core-data';
+import { __ } from '@wordpress/i18n';
+
+
+const EditorPlugin = () => {
+ const postType = useSelect(
+ ( select ) => select( 'core/editor' ).getCurrentPostType(),
+ []
+ );
+ const [ meta, setMeta ] = useEntityProp( 'postType', postType, 'meta' );
+
+ return (
+
+ {
+ setMeta( { ...meta, webmentions_disabled: value } );
+ } }
+ />
+
+ );
+}
+
+registerPlugin( 'webmention-editor-plugin', { render: EditorPlugin } );
diff --git a/tests/test-sender.php b/tests/test-sender.php
new file mode 100644
index 0000000..72d0887
--- /dev/null
+++ b/tests/test-sender.php
@@ -0,0 +1,101 @@
+post = self::factory()->post->create_and_get( array(
+ 'post_content' => 'Test post with a link to Example',
+ ) );
+ }
+
+ public function test_send_webmentions() {
+ // Mock der Webmention-Endpunkt-Entdeckung
+ add_filter( 'webmention_server_url', function( $url, $target ) {
+ return 'https://example.com/webmention';
+ }, 10, 2 );
+
+ // Mock der HTTP-Anfrage
+ add_filter( 'pre_http_request', function( $preempt, $args, $url ) {
+ return array(
+ 'response' => array( 'code' => 200 ),
+ 'body' => 'Webmention received',
+ );
+ }, 10, 3 );
+
+ $result = Sender::send_webmentions( $this->post->ID );
+
+ // Überprüfe, ob die Webmention gesendet wurde
+ $this->assertIsArray( $result );
+ $this->assertContains( 'https://example.com', $result );
+
+ // Überprüfe, ob die URLs in den Post-Meta gespeichert wurden
+ $mentioned_urls = get_post_meta( $this->post->ID, '_webmentioned', true );
+ $this->assertIsArray( $mentioned_urls );
+ $this->assertContains( 'https://example.com', $mentioned_urls );
+ }
+
+ public function test_update_ping() {
+ $pinged = array(
+ 'https://example1.com',
+ 'https://example2.com',
+ );
+
+ $result = Sender::update_ping( $this->post->ID, $pinged );
+
+ // Überprüfe, ob die Pings aktualisiert wurden
+ $this->assertIsString( $result );
+ $this->assertEquals( implode( "\n", $pinged ), $result );
+
+ // Überprüfe die Datenbank direkt
+ $updated_post = get_post( $this->post->ID );
+ $this->assertEquals( $result, $updated_post->pinged );
+ }
+
+ public function test_update_ping_invalid_post() {
+ $result = Sender::update_ping( 999999, array( 'https://example.com' ) );
+ $this->assertFalse( $result );
+ }
+
+ public function test_update_ping_invalid_pinged() {
+ $result = Sender::update_ping( $this->post->ID, 'not an array' );
+ $this->assertFalse( $result );
+ }
+
+ public function test_send_webmentions_with_error_response() {
+ // Mock der Webmention-Endpunkt-Entdeckung
+ add_filter( 'webmention_server_url', function( $url, $target ) {
+ return 'https://example.com/webmention';
+ }, 10, 2 );
+
+ // Mock der HTTP-Anfrage mit 500er Fehler
+ add_filter( 'pre_http_request', function( $preempt, $args, $url ) {
+ return array(
+ 'response' => array(
+ 'code' => 500,
+ 'message' => 'Internal Server Error',
+ ),
+ 'body' => 'Server Error',
+ 'headers' => array(),
+ 'cookies' => array(),
+ );
+ }, 10, 3 );
+
+ $result = Sender::send_webmentions( $this->post->ID );
+
+ // Überprüfe, ob der Versuch neu geplant wurde
+ $this->assertTrue( metadata_exists( 'post', $this->post->ID, '_mentionme' ) );
+ $this->assertEquals( '1', get_post_meta( $this->post->ID, '_mentionme_tries', true ) );
+ }
+
+ public function tear_down() {
+ parent::tear_down();
+ remove_all_filters( 'webmention_server_url' );
+ remove_all_filters( 'pre_http_request' );
+ }
+}
diff --git a/tests/test-webmention.php b/tests/test-webmention.php
index daa5145..9d8ff35 100644
--- a/tests/test-webmention.php
+++ b/tests/test-webmention.php
@@ -5,4 +5,4 @@ public function test_remove_sl() {
$this->assertEquals( true, true );
}
-}
\ No newline at end of file
+}
diff --git a/webmention.php b/webmention.php
index f6fa26a..2fe19fb 100755
--- a/webmention.php
+++ b/webmention.php
@@ -118,6 +118,12 @@ function init() {
require_once __DIR__ . '/includes/class-discovery.php';
add_action( 'init', array( '\Webmention\Discovery', 'init' ) );
+ if ( site_supports_blocks() ) {
+ // initialize Webmention Bloks.
+ require_once __DIR__ . '/includes/class-block.php';
+ add_action( 'init', array( '\Webmention\Block', 'init' ) );
+ }
+
// load local avatar store.
if ( 1 === (int) get_option( 'webmention_avatar_store_enable', 0 ) ) {
require_once __DIR__ . '/includes/class-avatar-store.php';
@@ -132,7 +138,6 @@ function init() {
// Default Comment Status.
add_filter( 'get_default_comment_status', 'webmention_get_default_comment_status', 11, 3 );
- add_filter( 'pings_open', 'webmention_pings_open', 10, 2 );
// Load language files.
load_plugin_textdomain( 'webmention', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
@@ -149,6 +154,18 @@ function init() {
remove_action( 'admin_init', array( 'Semantic_Linkbacks_Plugin', 'admin_init' ) );
add_action( 'wp_enqueue_scripts', '\Webmention\enqueue_scripts' );
+
+ // remove the "webmentions_disabled" meta value if the post is updated
+ \add_action(
+ 'updated_postmeta',
+ function ( $meta_id, $object_id, $meta_key, $meta_value ) {
+ if ( 'webmentions_disabled' === $meta_key && empty( $meta_value ) ) {
+ \delete_post_meta( $object_id, 'webmentions_disabled' );
+ }
+ },
+ 10,
+ 4
+ );
}
add_action( 'plugins_loaded', '\Webmention\init' );