2
0
Fork 0
mirror of https://github.com/discourse/wp-discourse.git synced 2025-10-03 08:59:21 +08:00

DEV: Refactor publish_post_after_save function (#488)

* Refactor publish_post_after_save function

* Simplify return statements; move update_post_meta call out of force_publish_post function.

* Simplify publish_to_discourse condition; Add tests for the force-publish option.

* Use gmdate() instead of date() in force_publish_max_age test.

* Add force_publish_allowed method and property; Update unit tests.

* Remove type declaration from property. Not suported in < php7.4
This commit is contained in:
Simon Cossar 2023-10-20 09:50:02 -07:00 committed by GitHub
parent 7a810ab710
commit 70fbc7ca32
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 865 additions and 678 deletions

View file

@ -42,6 +42,16 @@ class DiscoursePublish extends DiscourseBase {
*/
protected $log_args;

/**
* Allows the `force_publish_allowed` method to return `true` in unit tests.
*
* @access public
* @var bool
*/
public $force_publish_allowed = false;



/**
* DiscoursePublish constructor.
*
@ -69,64 +79,113 @@ class DiscoursePublish extends DiscourseBase {
}

/**
* Published a post to Discourse after it has been saved.
* Determines if a post should be published to Discourse after it is saved on WordPress.
*
* @param int $post_id The id of the post that has been saved.
* @param object $post The Post object.
* @param \WP_Post $post The Post object.
*
* @return null
*/
public function publish_post_after_save( $post_id, $post ) {
if ( $this->exclude_post( $post_id, $post ) ) {
return null;
}

$post_should_be_auto_published = $this->auto_publish( $post_id );
$post_already_published = $this->dc_get_post_meta( $post_id, 'discourse_post_id', true );
$post_marked_to_be_published = $this->dc_get_post_meta( $post_id, 'publish_to_discourse', true );
$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 );

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 );
}
return null;
}

/**
* Excludes a post from being published under various conditions.
*
* Posts are excluded from publishing if the plugin is unconfigured, the post's status is not set to 'publish',
* the post is a revision, doesn't have a title, is not a valid post type, or has an excluded tag.
*
* @param int $post_id The ID of the post.
* @param \WP_Post $post The Post object.
*
* @return bool
*/
protected function exclude_post( $post_id, $post ) {
$plugin_unconfigured = empty( $this->options['url'] ) || empty( $this->options['api-key'] ) || empty( $this->options['publish-username'] );
$publish_status_not_set = 'publish' !== get_post_status( $post_id );
$publish_private = apply_filters( 'wpdc_publish_private_post', false, $post_id );
if ( wp_is_post_revision( $post_id )
return wp_is_post_revision( $post_id )
|| ( $publish_status_not_set && ! $publish_private )
|| $plugin_unconfigured
|| empty( $post->post_title )
|| ! $this->is_valid_sync_post_type( $post_id )
|| $this->has_excluded_tag( $post_id, $post )
) {

return null;
|| $this->has_excluded_tag( $post );
}

// Clear existing publishing errors.
delete_post_meta( $post_id, 'wpdc_publishing_error' );

/**
* Determines if the plugin's 'auto-publish' option is enabled and if it has been overridden for a particular post.
*
* The auto-publish option causes the 'Publish to Discourse' checkbox in the post editor to be pre-checked for all new
* posts. It is 'overridden' if the checkbox is manually unchecked.
*
* @param int $post_id The ID of the post.
*
* @return bool
*/
protected function auto_publish( $post_id ) {
// If the auto-publish option is enabled publish unpublished topics, unless the setting has been overridden.
$auto_publish_overridden = intval( get_post_meta( $post_id, 'wpdc_auto_publish_overridden', true ) ) === 1;
$auto_publish = ! $auto_publish_overridden && ! empty( $this->options['auto-publish'] );
$auto_publish_overridden = intval( $this->dc_get_post_meta( $post_id, 'wpdc_auto_publish_overridden', true ) ) === 1;
return ! $auto_publish_overridden && ! empty( $this->options['auto-publish'] );
}

$publish_to_discourse = get_post_meta( $post_id, 'publish_to_discourse', true ) || $auto_publish;
$publish_to_discourse = apply_filters( 'wpdc_publish_after_save', $publish_to_discourse, $post_id, $post );
/**
* Determines if a post should be 'force published.'
*
* Posts are force published if the 'force-publish' option is enabled and the post was created within the time period
* set by the 'force-publish-max-age' setting (ignored when 'force-publish-max-age is set to 0.)
*
* @param object $post The Post object.
*
* @return bool
*/
protected function force_publish_post( $post ) {
if ( empty( $this->options['force-publish'] ) || ! $this->force_publish_allowed() ) {
return false;
}

$force_publish_enabled = ! empty( $this->options['force-publish'] );
$force_publish_post = false;
if ( $force_publish_enabled ) {
// The Force Publish setting can't be easily supported with both the Block and Classic editors. The $is_rest_request
// variable is used to only allow the Force Publish setting to be respected for posts published with the Block Editor.
$is_rest_request = defined( 'REST_REQUEST' ) && REST_REQUEST;
$force_publish_max_age = ! empty( $this->options['force-publish-max-age'] ) ? intval( $this->options['force-publish-max-age'] ) : 0;
$min_date = date_create()->modify( "-{$force_publish_max_age} day" )->format( 'U' );
$post_time = strtotime( $post->post_date );

if ( ( ( 0 === $force_publish_max_age ) || $post_time >= $min_date ) && $is_rest_request ) {
$force_publish_post = true;
update_post_meta( $post_id, 'publish_post_category', intval( $this->options['publish-category'] ) );
}
return 0 === $force_publish_max_age || $post_time >= $min_date;
}

$already_published = $this->dc_get_post_meta( $post_id, 'discourse_post_id', true );
$update_discourse_topic = get_post_meta( $post_id, 'update_discourse_topic', true );
$title = $this->sanitize_title( $post->post_title );
$title = apply_filters( 'wpdc_publish_format_title', $title, $post_id );

if ( $force_publish_post || ( ! $already_published && $publish_to_discourse ) || $update_discourse_topic ) {
$this->sync_to_discourse( $post_id, $title, $post->post_content );
}

return null;
/**
* Checks if the post was published via REST_REQUEST.
*
* Currently, the force-publish option is only supported for posts published via the Block editor (a REST_REQUEST.)
* The `force_publish_allowed` property is used in unit tests.
*
* @return bool
*/
protected function force_publish_allowed() {
return ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || $this->force_publish_allowed;
}

/**
@ -148,7 +207,7 @@ class DiscoursePublish extends DiscourseBase {
$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_id ) ) {
if ( $publish_to_discourse && $post_is_published && $this->is_valid_sync_post_type( $post_id ) && ! empty( $title ) && ! $this->has_excluded_tag( $post ) ) {
update_post_meta( $post_id, 'publish_to_discourse', 1 );
$this->sync_to_discourse( $post_id, $title, $post->post_content );
} elseif ( $post_is_published && ! empty( $this->options['auto-publish'] ) ) {
@ -728,12 +787,11 @@ class DiscoursePublish extends DiscourseBase {
/**
* Checks if a post has an excluded tag.
*
* @param int $post_id The ID of the post in question.
* @param \WP_Post $post The Post object.
*
* @return bool
*/
protected function has_excluded_tag( $post_id, $post ) {
protected function has_excluded_tag( $post ) {
if ( version_compare( get_bloginfo( 'version' ), '5.6', '<' ) ) {
return false;
}

View file

@ -17,6 +17,7 @@ use \WPDiscourse\Test\UnitTest;
*/
class DiscoursePublishTest extends UnitTest {


/**
* Instance of DiscoursePublish.
*
@ -31,6 +32,7 @@ class DiscoursePublishTest extends UnitTest {
public static function setUpBeforeClass() {
parent::setUpBeforeClass();
self::initialize_variables();

}

/**
@ -671,12 +673,15 @@ class DiscoursePublishTest extends UnitTest {

// Add filter.
add_filter(
'wpdc_publish_body', function( $body, $remote_post_type ) use ( $tags ) {
'wpdc_publish_body',
function( $body, $remote_post_type ) use ( $tags ) {
if ( 'create_post' === $remote_post_type ) {
$body['tags'] = $tags;
}
return $body;
}, 10, 2
},
10,
2
);

$raw_body = $this->response_body_json( 'post_create' );
@ -686,7 +691,8 @@ class DiscoursePublishTest extends UnitTest {

// Check tags are in the body passed to request.
add_filter(
'pre_http_request', function( $prempt, $args, $url ) use ( $tags, $response ) {
'pre_http_request',
function( $prempt, $args, $url ) use ( $tags, $response ) {
$body = json_decode( $args['body'] );

if ( ! isset( $body->tags ) || ! ( $tags === $body->tags ) ) {
@ -694,7 +700,9 @@ class DiscoursePublishTest extends UnitTest {
} else {
return $response;
}
}, 10, 3
},
10,
3
);

// Setup post.
@ -713,6 +721,127 @@ class DiscoursePublishTest extends UnitTest {
wp_delete_post( $post_id );
}

/**
* Test that the default value of the force_publish_allowed property prevents force-publishing.
*/
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 );

// Set up a response body for creating a new post.
$body = $this->mock_remote_post_success( 'post_create', 'POST' );
$discourse_post_id = $body->id;

// Set publish_to_discourse to 0 to test the force-publish option.
$post_atts = self::$post_atts;
$post_atts['meta_input']['publish_to_discourse'] = 0;
$post_id = wp_insert_post( $post_atts, false, false );

// Trigger the publish_post_after_save method.
$post = get_post( $post_id );
$this->publish->publish_post_after_save( $post_id, $post );

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

// Set force_publish_allowed to true.
$this->publish->force_publish_allowed = true;

// Trigger the publish_post_after_save method.
$this->publish->publish_post_after_save( $post_id, $post );

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

// Cleanup.
wp_delete_post( $post_id );
}

/**
* Test that enabling the force-publish overrides the publish_to_discourse meta-data.
*/
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 );

// Set up a response body for creating a new post.
$body = $this->mock_remote_post_success( 'post_create', 'POST' );
$discourse_post_id = $body->id;

// Set publish_to_discourse to 0 to test the force-publish option.
$post_atts = self::$post_atts;
$post_atts['meta_input']['publish_to_discourse'] = 0;
$post_id = wp_insert_post( $post_atts, false, false );

// Trigger the publish_post_after_save method.
$post = get_post( $post_id );
$this->publish->publish_post_after_save( $post_id, $post );

// Ensure that publication has not occurred.
$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 );

// Trigger the publish_post_after_save method.
$this->publish->publish_post_after_save( $post_id, $post );

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

// Cleanup.
wp_delete_post( $post_id );
}

/**
* Test that the force-publish-max-age option prevents older posts from being published.
*/
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;
// 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 );

// Set up a response hook for creating a new post.
$body = $this->mock_remote_post_success( 'post_create', 'POST' );
$discourse_post_id = $body->id;

// Set publish_to_discourse to 0 to test the force-publish option.
// Set post_date to 7 days in the past.
$post_atts = self::$post_atts;
$post_atts['meta_input']['publish_to_discourse'] = 0;
$post_atts['post_date'] = gmdate( 'Y-m-d H:i:s', strtotime( '-7 days' ) );
$post_id = wp_insert_post( $post_atts, false, false );

// Trigger the publish_post_after_save method.
$post = get_post( $post_id );
$this->publish->publish_post_after_save( $post_id, $post );

// Ensure that publication has not occurred.
$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 );

// Trigger the publish_post_after_save method.
$this->publish->publish_post_after_save( $post_id, $post );

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

// Cleanup.
wp_delete_post( $post_id );
}

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