Skip to content

Commit

Permalink
DEV: Refactor xmlrpc_publish_post_to_discourse (#491)
Browse files Browse the repository at this point in the history
* Refactor xmlrpc_publish_post_to_discourse; Return wp_mail success response from publish_failure_notification.

* Add missing doc comments; don't use magic method to access title.

* Pass post title to sync_to_discourse without setting it as a variable; Use '__return_true' in add_filter callback.
  • Loading branch information
scossar authored Oct 30, 2023
1 parent 70fbc7c commit d5d84d9
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 38 deletions.
41 changes: 18 additions & 23 deletions lib/discourse-publish.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,20 +97,13 @@ public function publish_post_after_save( $post_id, $post ) {
$publish_new_post_to_discourse = ( $post_marked_to_be_published || $post_should_be_auto_published ) && ! $post_already_published;
$topic_should_be_updated = $this->dc_get_post_meta( $post_id, 'update_discourse_topic', true );
$force_publish_post = $this->force_publish_post( $post );
if ( $force_publish_post ) {
// All force published posts are published to the default publish-category.
update_post_meta( $post_id, 'publish_post_category', intval( $this->options['publish-category'] ) );
}

$publish_to_discourse = $publish_new_post_to_discourse || $topic_should_be_updated || $force_publish_post;
$publish_to_discourse = apply_filters( 'wpdc_publish_after_save', $publish_to_discourse, $post_id, $post );
$publish_to_discourse = $publish_new_post_to_discourse || $topic_should_be_updated || $force_publish_post;
$publish_to_discourse = apply_filters( 'wpdc_publish_after_save', $publish_to_discourse, $post_id, $post );

if ( $publish_to_discourse ) {
$title = $this->sanitize_title( $post->post_title );
$title = apply_filters( 'wpdc_publish_format_title', $title, $post_id );
// Clear existing publishing errors.
delete_post_meta( $post_id, 'wpdc_publishing_error' );
$this->sync_to_discourse( $post_id, $title, $post->post_content );
$this->sync_to_discourse( $post_id, $post->post_title, $post->post_content );
}
return null;
}
Expand Down Expand Up @@ -189,35 +182,35 @@ protected function force_publish_allowed() {
}

/**
* For publishing by xmlrpc.
* For publishing via xmlrpc.
*
* Hooks into the 'xmlrpc_publish_post' action. Publishing via xmlrpc is disabled by default. It can be enabled by
* adding a function that hooks into 'wp_discourse_before_xmlrpc_publish'. This method exists for historical reasons.
* Its main purpose is to allow a publish-failure-notice to be sent when authors publish posts from blogging software.
*
* Hooks into 'xmlrpc_publish_post'. Publishing through this hook is disabled. This is to prevent
* posts being inadvertently published to Discourse when they are edited using blogging software.
* This can be overridden by hooking into the `wp_discourse_before_xmlrpc_publish` filter and setting
* `$publish_to_discourse` to true based on some condition - testing for the presence of a tag can
* work for this.
* @param int $post_id The post ID.
*
* @param int $post_id The post id.
* @return null|bool
*/
public function xmlrpc_publish_post_to_discourse( $post_id ) {
$post = get_post( $post_id );
$post_is_published = 'publish' === get_post_status( $post_id );
$publish_to_discourse = false;
$publish_to_discourse = apply_filters( 'wp_discourse_before_xmlrpc_publish', $publish_to_discourse, $post );
$title = $this->sanitize_title( $post->post_title );
$title = apply_filters( 'wpdc_publish_format_title', $title, $post_id );

if ( $publish_to_discourse && $post_is_published && $this->is_valid_sync_post_type( $post_id ) && ! empty( $title ) && ! $this->has_excluded_tag( $post ) ) {
if ( $publish_to_discourse ) {
update_post_meta( $post_id, 'publish_to_discourse', 1 );
$this->sync_to_discourse( $post_id, $title, $post->post_content );
$this->publish_post_after_save( $post_id, $post );
} elseif ( $post_is_published && ! empty( $this->options['auto-publish'] ) ) {
$this->email_notifier->publish_failure_notification(
// Allows a notification to be sent about posts that have been published from a blogging app.
$success = $this->email_notifier->publish_failure_notification(
$post,
array(
'location' => 'after_xmlrpc_publish',
)
);
return $success;
}
return null;
}

/**
Expand Down Expand Up @@ -268,6 +261,8 @@ protected function sync_to_discourse_work( $post_id, $title, $raw ) {
$use_multisite_configuration = is_multisite() && ! empty( $options['multisite-configuration-enabled'] );
$add_featured_link = ! empty( $options['add-featured-link'] );
$permalink = get_permalink( $post_id );
$title = $this->sanitize_title( $title );
$title = apply_filters( 'wpdc_publish_format_title', $title, $post_id );

$this->log_args = array(
'wp_title' => $title,
Expand Down
8 changes: 7 additions & 1 deletion lib/email-notification.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public function setup_options() {
*
* @param object $post $discourse_post The post where the failure occurred.
* @param array $args Optional arguments for the function. The 'location' argument can be used to indicate where the failure occurred.
*
* @return void|bool
*/
public function publish_failure_notification( $post, $args ) {
$post_id = $post->ID;
Expand Down Expand Up @@ -110,7 +112,11 @@ public function publish_failure_notification( $post, $args ) {
// translators: Discourse publishing email. Placeholder: Discourse support URL.
$message .= sprintf( __( '<%1$s>', 'wp-discourse' ), esc_url( $support_url ) ) . "\r\n";
// translators: Discourse publishing email. Placeholder: blogname, email message.
wp_mail( $publish_failure_email, sprintf( __( '[%s] Discourse Publishing Failure' ), $blogname ), $message );
$success = wp_mail( $publish_failure_email, sprintf( __( '[%s] Discourse Publishing Failure' ), $blogname ), $message );

return $success;
}// End if().

return false;
}
}
90 changes: 76 additions & 14 deletions tests/phpunit/test-discourse-publish.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ class DiscoursePublishTest extends UnitTest {
*/
protected $publish;

/**
* A partial mock instance of EmailNotification.
*
* @access protected
* @var \Mockery\Mock
*/
protected $email_notifier;

/**
* Setup test class
*/
Expand All @@ -40,9 +48,9 @@ public static function setUpBeforeClass() {
*/
public function setUp() {
parent::setUp();

$register_actions = false;
$this->publish = new DiscoursePublish( new EmailNotification(), $register_actions );
$register_actions = false;
$this->email_notifier = \Mockery::mock( EmailNotification::class )->makePartial();
$this->publish = new DiscoursePublish( $this->email_notifier, $register_actions );
$this->publish->setup_options( self::$plugin_options );
$this->publish->setup_logger();
}
Expand Down Expand Up @@ -726,8 +734,9 @@ function( $prempt, $args, $url ) use ( $tags, $response ) {
*/
public function test_force_publish_allowed_property() {
// Enable the force-publish option, but don't override default value of the force_publish_allowed property.
self::$plugin_options['force-publish'] = 1;
$this->publish->setup_options( self::$plugin_options );
$plugin_options = self::$plugin_options;
$plugin_options['force-publish'] = 1;
$this->publish->setup_options( $plugin_options );

// Set up a response body for creating a new post.
$body = $this->mock_remote_post_success( 'post_create', 'POST' );
Expand Down Expand Up @@ -765,8 +774,9 @@ public function test_force_publish_allowed_property() {
public function test_force_publish_option() {
$this->publish->force_publish_allowed = true;
// Explicitly disable the force-publish option.
self::$plugin_options['force-publish'] = 0;
$this->publish->setup_options( self::$plugin_options );
$plugin_options = self::$plugin_options;
$plugin_options['force-publish'] = 0;
$this->publish->setup_options( $plugin_options );

// Set up a response body for creating a new post.
$body = $this->mock_remote_post_success( 'post_create', 'POST' );
Expand All @@ -785,8 +795,9 @@ public function test_force_publish_option() {
$this->assertEmpty( get_post_meta( $post_id, 'discourse_post_id', true ) );

// Enable the force-publish option.
self::$plugin_options['force-publish'] = 1;
$this->publish->setup_options( self::$plugin_options );
$plugin_options = self::$plugin_options;
$plugin_options['force-publish'] = 1;
$this->publish->setup_options( $plugin_options );

// Trigger the publish_post_after_save method.
$this->publish->publish_post_after_save( $post_id, $post );
Expand All @@ -804,10 +815,11 @@ public function test_force_publish_option() {
*/
public function test_force_publish_max_age_prevents_older_posts_from_being_published() {
$this->publish->force_publish_allowed = true;
self::$plugin_options['force-publish'] = 1;
$plugin_options = self::$plugin_options;
$plugin_options['force-publish'] = 1;
// Don't publish posts that were created greater than 2 days ago.
self::$plugin_options['force-publish-max-age'] = 2;
$this->publish->setup_options( self::$plugin_options );
$plugin_options['force-publish-max-age'] = 2;
$this->publish->setup_options( $plugin_options );

// Set up a response hook for creating a new post.
$body = $this->mock_remote_post_success( 'post_create', 'POST' );
Expand All @@ -828,8 +840,8 @@ public function test_force_publish_max_age_prevents_older_posts_from_being_publi
$this->assertEmpty( get_post_meta( $post_id, 'discourse_post_id', true ) );

// Change force-publish-max-age to 20.
self::$plugin_options['force-publish-max-age'] = 20;
$this->publish->setup_options( self::$plugin_options );
$plugin_options['force-publish-max-age'] = 20;
$this->publish->setup_options( $plugin_options );

// Trigger the publish_post_after_save method.
$this->publish->publish_post_after_save( $post_id, $post );
Expand All @@ -842,6 +854,56 @@ public function test_force_publish_max_age_prevents_older_posts_from_being_publi
wp_delete_post( $post_id );
}

/**
* Posts can only be published via XMLRPC by hooking into the wp_discourse_before_xmlrpc_publish filter with a function
* that returns `true`.
*/
public function test_wp_discourse_before_xmlrpc_publish_filter() {
$body = $this->mock_remote_post_success( 'post_create', 'POST' );
$discourse_post_id = $body->id;
// Note: `self::$post_atts['meta_input']['publish_to_discourse'] === 1`.
$post_atts = self::$post_atts;
$post_id = wp_insert_post( $post_atts, false, false );

// Call xmlrpc_publish_post_to_discourse without hooking into the wp_discourse_before_xmlrpc_publish filter.
$this->publish->xmlrpc_publish_post_to_discourse( $post_id );

// Ensure that publication has not occurred.
$this->assertEmpty( get_post_meta( $post_id, 'discourse_post_id', true ) );

// Hook into the filter to allow for xmlrpc publishing.
add_filter( 'wp_discourse_before_xmlrpc_publish', '__return_true' );

$this->publish->xmlrpc_publish_post_to_discourse( $post_id );

// Ensure that publication has occurred.
$this->assertEquals( get_post_meta( $post_id, 'discourse_post_id', true ), $discourse_post_id );

// Cleanup.
wp_delete_post( $post_id );
remove_filter( 'wp_discourse_before_xmlrpc_publish', '__return_true' );
}

/**
* When the auto-publish option is enabled, posts published via XMLRPC will trigger a publish_failure_notification.
*/
public function test_xmlrpc_publish_failure_notification() {
$plugin_options = self::$plugin_options;
// The xmlrpc failure notification will only be triggered if the auto-publish option is set.
$plugin_options['auto-publish'] = 1;
$this->publish->setup_options( $plugin_options );

$post_atts = self::$post_atts;
$post_id = wp_insert_post( $post_atts, false, false );

$this->email_notifier->shouldReceive( 'publish_failure_notification' )->withSomeOfArgs( array( 'location' => 'after_xmlrpc_publish' ) )->andReturn( true );

$this->assertTrue( $this->publish->xmlrpc_publish_post_to_discourse( $post_id ) );

// Cleanup.
wp_delete_post( $post_id );
}

/**
* Successful remote_post request returns original response.
*/
Expand Down

0 comments on commit d5d84d9

Please sign in to comment.