diff --git a/lib/discourse-publish.php b/lib/discourse-publish.php index 0b5e4fd..4cb7520 100644 --- a/lib/discourse-publish.php +++ b/lib/discourse-publish.php @@ -27,12 +27,12 @@ class DiscoursePublish extends DiscourseBase { protected $email_notifier; /** - * Logger context - * - * @access protected - * @var string - */ - protected $logger_context = 'publish'; + * Logger context + * + * @access protected + * @var string + */ + protected $logger_context = 'publish'; /** * Instance store for log args @@ -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 int $post_id The id of the post that has been saved. + * @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; - } - - // Clear existing publishing errors. - delete_post_meta( $post_id, 'wpdc_publishing_error' ); + || $this->has_excluded_tag( $post ); + } + /** + * 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 ); - - $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'] ) ); - } + /** + * 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; } - $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 ); + $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 ( $force_publish_post || ( ! $already_published && $publish_to_discourse ) || $update_discourse_topic ) { - $this->sync_to_discourse( $post_id, $title, $post->post_content ); - } + return 0 === $force_publish_max_age || $post_time >= $min_date; + } - 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; } diff --git a/tests/phpunit/test-discourse-publish.php b/tests/phpunit/test-discourse-publish.php index 6c80826..2205878 100644 --- a/tests/phpunit/test-discourse-publish.php +++ b/tests/phpunit/test-discourse-publish.php @@ -17,311 +17,313 @@ use \WPDiscourse\Test\UnitTest; */ class DiscoursePublishTest extends UnitTest { - /** - * Instance of DiscoursePublish. - * - * @access protected - * @var \WPDiscourse\DiscoursePublish\DiscoursePublish - */ - protected $publish; - /** - * Setup test class - */ - public static function setUpBeforeClass() { - parent::setUpBeforeClass(); - self::initialize_variables(); - } + /** + * Instance of DiscoursePublish. + * + * @access protected + * @var \WPDiscourse\DiscoursePublish\DiscoursePublish + */ + protected $publish; - /** - * Setup each test. - */ - public function setUp() { - parent::setUp(); + /** + * Setup test class + */ + public static function setUpBeforeClass() { + parent::setUpBeforeClass(); + self::initialize_variables(); - $register_actions = false; - $this->publish = new DiscoursePublish( new EmailNotification(), $register_actions ); - $this->publish->setup_options( self::$plugin_options ); - $this->publish->setup_logger(); - } + } - /** - * Sync_to_discourse handles new posts correctly. - */ - public function test_sync_to_discourse_when_creating() { - // Set up a response body for creating a new post. - $body = $this->mock_remote_post_success( 'post_create', 'POST' ); - $discourse_post_id = $body->id; - $discourse_topic_id = $body->topic_id; - $discourse_permalink = self::$discourse_url . '/t/' . $body->topic_slug . '/' . $body->topic_id; - $discourse_category = self::$post_atts['meta_input']['publish_post_category']; + /** + * Setup each test. + */ + public function setUp() { + parent::setUp(); - // Add the post. - $post_id = wp_insert_post( self::$post_atts, false, false ); + $register_actions = false; + $this->publish = new DiscoursePublish( new EmailNotification(), $register_actions ); + $this->publish->setup_options( self::$plugin_options ); + $this->publish->setup_logger(); + } - // Run the publication. - $post = get_post( $post_id ); - $this->publish->sync_to_discourse_without_lock( $post_id, $post->title, $post->post_content ); + /** + * Sync_to_discourse handles new posts correctly. + */ + public function test_sync_to_discourse_when_creating() { + // Set up a response body for creating a new post. + $body = $this->mock_remote_post_success( 'post_create', 'POST' ); + $discourse_post_id = $body->id; + $discourse_topic_id = $body->topic_id; + $discourse_permalink = self::$discourse_url . '/t/' . $body->topic_slug . '/' . $body->topic_id; + $discourse_category = self::$post_atts['meta_input']['publish_post_category']; - // Ensure the right post meta is created. - $this->assertEquals( get_post_meta( $post_id, 'discourse_post_id', true ), $discourse_post_id ); - $this->assertEquals( get_post_meta( $post_id, 'discourse_topic_id', true ), $discourse_topic_id ); - $this->assertEquals( get_post_meta( $post_id, 'discourse_permalink', true ), $discourse_permalink ); - $this->assertEquals( get_post_meta( $post_id, 'publish_post_category', true ), $discourse_category ); - $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_response', true ), 'success' ); + // Add the post. + $post_id = wp_insert_post( self::$post_atts, false, false ); - // Cleanup. - wp_delete_post( $post_id ); - } + // Run the publication. + $post = get_post( $post_id ); + $this->publish->sync_to_discourse_without_lock( $post_id, $post->title, $post->post_content ); - /** - * Sync_to_discourse when creating a new post with embed error response. - */ - public function test_sync_to_discourse_when_creating_with_embed_error() { - // Set up the error responses. - $raw_response = $this->build_response( 'unprocessable', 'embed' ); - $error_message = json_decode( $raw_response['body'] )->errors[0]; - $request = array( + // Ensure the right post meta is created. + $this->assertEquals( get_post_meta( $post_id, 'discourse_post_id', true ), $discourse_post_id ); + $this->assertEquals( get_post_meta( $post_id, 'discourse_topic_id', true ), $discourse_topic_id ); + $this->assertEquals( get_post_meta( $post_id, 'discourse_permalink', true ), $discourse_permalink ); + $this->assertEquals( get_post_meta( $post_id, 'publish_post_category', true ), $discourse_category ); + $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_response', true ), 'success' ); + + // Cleanup. + wp_delete_post( $post_id ); + } + + /** + * Sync_to_discourse when creating a new post with embed error response. + */ + public function test_sync_to_discourse_when_creating_with_embed_error() { + // Set up the error responses. + $raw_response = $this->build_response( 'unprocessable', 'embed' ); + $error_message = json_decode( $raw_response['body'] )->errors[0]; + $request = array( 'response' => $raw_response, 'method' => 'POST', - ); - $this->mock_remote_post( $request ); + ); + $this->mock_remote_post( $request ); - // Add the post. - $post_id = wp_insert_post( self::$post_atts, false, false ); + // Add the post. + $post_id = wp_insert_post( self::$post_atts, false, false ); - // Run the publication. - $post = get_post( $post_id ); - $response = $this->publish->sync_to_discourse_without_lock( - $post_id, - $post->title, - $post->post_content - ); + // Run the publication. + $post = get_post( $post_id ); + $response = $this->publish->sync_to_discourse_without_lock( + $post_id, + $post->title, + $post->post_content + ); - // Ensure the right error is returned. - $this->assertEquals( $response, $this->build_post_error() ); + // Ensure the right error is returned. + $this->assertEquals( $response, $this->build_post_error() ); - // Ensure the post meta is updated correctly. - $this->assertEquals( get_post_meta( $post_id, 'wpdc_auto_publish_overridden', true ), 1 ); - $this->assertEquals( get_post_meta( $post_id, 'publish_to_discourse', true ), '' ); - $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_error', true ), $error_message ); + // Ensure the post meta is updated correctly. + $this->assertEquals( get_post_meta( $post_id, 'wpdc_auto_publish_overridden', true ), 1 ); + $this->assertEquals( get_post_meta( $post_id, 'publish_to_discourse', true ), '' ); + $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_error', true ), $error_message ); - // Ensure the right log is created. - $log = $this->get_last_log(); - $this->assertRegExp( '/publish.ERROR: create_post.post_error/', $log ); - $this->assertRegExp( '/"http_code":' . $raw_response['response']['code'] . '/', $log ); - $this->assertRegExp( '/"response_message":"' . $error_message . '"/', $log ); + // Ensure the right log is created. + $log = $this->get_last_log(); + $this->assertRegExp( '/publish.ERROR: create_post.post_error/', $log ); + $this->assertRegExp( '/"http_code":' . $raw_response['response']['code'] . '/', $log ); + $this->assertRegExp( '/"response_message":"' . $error_message . '"/', $log ); - // Cleanup. - wp_delete_post( $post_id ); - } + // Cleanup. + wp_delete_post( $post_id ); + } - /** - * Sync_to_discourse when creating a new post with category error response. - */ - public function test_sync_to_discourse_when_creating_with_category_error() { - // Set up the error responses. - $raw_response = $this->build_response( 'invalid_parameters', 'category' ); - $error_message = json_decode( $raw_response['body'] )->errors[0]; - $request = array( + /** + * Sync_to_discourse when creating a new post with category error response. + */ + public function test_sync_to_discourse_when_creating_with_category_error() { + // Set up the error responses. + $raw_response = $this->build_response( 'invalid_parameters', 'category' ); + $error_message = json_decode( $raw_response['body'] )->errors[0]; + $request = array( 'response' => $raw_response, 'method' => 'POST', - ); - $this->mock_remote_post( $request ); + ); + $this->mock_remote_post( $request ); - // Add the post. - $post_id = wp_insert_post( self::$post_atts, false, false ); + // Add the post. + $post_id = wp_insert_post( self::$post_atts, false, false ); - // Run the publication. - $post = get_post( $post_id ); - $response = $this->publish->sync_to_discourse_without_lock( - $post_id, - $post->title, - $post->post_content - ); + // Run the publication. + $post = get_post( $post_id ); + $response = $this->publish->sync_to_discourse_without_lock( + $post_id, + $post->title, + $post->post_content + ); - // Ensure the right error is returned. - $this->assertEquals( $response, $this->build_post_error() ); + // Ensure the right error is returned. + $this->assertEquals( $response, $this->build_post_error() ); - // Ensure the post meta is updated correctly. - $this->assertEquals( get_post_meta( $post_id, 'publish_to_discourse', true ), '' ); - $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_error', true ), $error_message ); + // Ensure the post meta is updated correctly. + $this->assertEquals( get_post_meta( $post_id, 'publish_to_discourse', true ), '' ); + $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_error', true ), $error_message ); - // Ensure the right log is created. - $log = $this->get_last_log(); - $this->assertRegExp( '/publish.ERROR: create_post.post_error/', $log ); - $this->assertRegExp( '/"http_code":' . $raw_response['response']['code'] . '/', $log ); - $this->assertRegExp( '/"response_message":"' . $error_message . '"/', $log ); + // Ensure the right log is created. + $log = $this->get_last_log(); + $this->assertRegExp( '/publish.ERROR: create_post.post_error/', $log ); + $this->assertRegExp( '/"http_code":' . $raw_response['response']['code'] . '/', $log ); + $this->assertRegExp( '/"response_message":"' . $error_message . '"/', $log ); - // cleanup. - wp_delete_post( $post_id ); - } + // cleanup. + wp_delete_post( $post_id ); + } - /** - * Sync_to_discourse when creating a new post with invalid body in response. - */ - public function test_sync_to_discourse_when_creating_with_response_body_error() { - // Setup the invalid respond body. - $response = $this->build_response( 'success' ); - $response['body'] = '{ "invalid_body" : true }'; - $request = array( + /** + * Sync_to_discourse when creating a new post with invalid body in response. + */ + public function test_sync_to_discourse_when_creating_with_response_body_error() { + // Setup the invalid respond body. + $response = $this->build_response( 'success' ); + $response['body'] = '{ "invalid_body" : true }'; + $request = array( 'response' => $response, 'method' => 'POST', - ); - $this->mock_remote_post( $request ); + ); + $this->mock_remote_post( $request ); - // Add the post. - $post_id = wp_insert_post( self::$post_atts, false, false ); + // Add the post. + $post_id = wp_insert_post( self::$post_atts, false, false ); - // Run the publication. - $post = get_post( $post_id ); - $response = $this->publish->sync_to_discourse_without_lock( - $post_id, - $post->title, - $post->post_content - ); + // Run the publication. + $post = get_post( $post_id ); + $response = $this->publish->sync_to_discourse_without_lock( + $post_id, + $post->title, + $post->post_content + ); - // Ensure the right error is returned. - $this->assertEquals( $response, $this->build_body_error() ); + // Ensure the right error is returned. + $this->assertEquals( $response, $this->build_body_error() ); - // Ensure the post meta is updated correctly. - $this->assertEquals( get_post_meta( $post_id, 'publish_to_discourse', true ), '' ); - $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_error', true ), 'OK' ); - $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_response', true ), 'error' ); + // Ensure the post meta is updated correctly. + $this->assertEquals( get_post_meta( $post_id, 'publish_to_discourse', true ), '' ); + $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_error', true ), 'OK' ); + $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_response', true ), 'error' ); - // Ensure the right log is created. - $log = $this->get_last_log(); - $this->assertRegExp( '/publish.ERROR: create_post.body_validation_error/', $log ); + // Ensure the right log is created. + $log = $this->get_last_log(); + $this->assertRegExp( '/publish.ERROR: create_post.body_validation_error/', $log ); - // cleanup. - wp_delete_post( $post_id ); - } + // cleanup. + wp_delete_post( $post_id ); + } - /** - * Sync_to_discourse when creating a new post and post is enqueued. - */ - public function test_sync_to_discourse_when_creating_with_enqueued_post() { - // Setup the enqueued response body. - $response = $this->build_response( 'success' ); - $response['body'] = ''; - $request = array( + /** + * Sync_to_discourse when creating a new post and post is enqueued. + */ + public function test_sync_to_discourse_when_creating_with_enqueued_post() { + // Setup the enqueued response body. + $response = $this->build_response( 'success' ); + $response['body'] = ''; + $request = array( 'response' => $response, 'method' => 'POST', - ); - $this->mock_remote_post( $request ); + ); + $this->mock_remote_post( $request ); - // Add the post. - $post_id = wp_insert_post( self::$post_atts, false, false ); + // Add the post. + $post_id = wp_insert_post( self::$post_atts, false, false ); - // Run the publication. - $post = get_post( $post_id ); - $response = $this->publish->sync_to_discourse_without_lock( - $post_id, - $post->title, - $post->post_content - ); + // Run the publication. + $post = get_post( $post_id ); + $response = $this->publish->sync_to_discourse_without_lock( + $post_id, + $post->title, + $post->post_content + ); - // Ensure the right error is returned. - $message = __( 'The published post has been added to the Discourse approval queue', 'wp-discourse' ); - $this->assertEquals( $response, $this->build_notice( $message ) ); + // Ensure the right error is returned. + $message = __( 'The published post has been added to the Discourse approval queue', 'wp-discourse' ); + $this->assertEquals( $response, $this->build_notice( $message ) ); - // Ensure the post meta is updated correctly. - $this->assertEquals( get_post_meta( $post_id, 'publish_to_discourse', true ), 1 ); - $this->assertEquals( get_post_meta( $post_id, 'discourse_post_id', true ), '' ); - $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_error', true ), 'queued_topic' ); + // Ensure the post meta is updated correctly. + $this->assertEquals( get_post_meta( $post_id, 'publish_to_discourse', true ), 1 ); + $this->assertEquals( get_post_meta( $post_id, 'discourse_post_id', true ), '' ); + $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_error', true ), 'queued_topic' ); - // Ensure the right log is created. - $log = $this->get_last_log(); - $this->assertRegExp( '/publish.WARNING: create_post.queued_topic_notice/', $log ); + // Ensure the right log is created. + $log = $this->get_last_log(); + $this->assertRegExp( '/publish.WARNING: create_post.queued_topic_notice/', $log ); - // cleanup. - wp_delete_post( $post_id ); - } + // cleanup. + wp_delete_post( $post_id ); + } - /** - * Sync_to_discourse when creating a new post with direct-db-publication-flags. - */ - public function test_sync_to_discourse_when_creating_with_direct_db_publication_flags() { - // Enable direct db pubilcation flags option. - self::$plugin_options['direct-db-publication-flags'] = 1; - $this->publish->setup_options( self::$plugin_options ); + /** + * Sync_to_discourse when creating a new post with direct-db-publication-flags. + */ + public function test_sync_to_discourse_when_creating_with_direct_db_publication_flags() { + // Enable direct db pubilcation flags option. + self::$plugin_options['direct-db-publication-flags'] = 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; - $discourse_topic_id = $body->topic_id; - $discourse_permalink = self::$discourse_url . '/t/' . $body->topic_slug . '/' . $body->topic_id; - $discourse_category = self::$post_atts['meta_input']['publish_post_category']; + // Set up a response body for creating a new post. + $body = $this->mock_remote_post_success( 'post_create', 'POST' ); + $discourse_post_id = $body->id; + $discourse_topic_id = $body->topic_id; + $discourse_permalink = self::$discourse_url . '/t/' . $body->topic_slug . '/' . $body->topic_id; + $discourse_category = self::$post_atts['meta_input']['publish_post_category']; - // Add the post. - $post_id = wp_insert_post( self::$post_atts, false, false ); + // Add the post. + $post_id = wp_insert_post( self::$post_atts, false, false ); - // Run the publication. - $post = get_post( $post_id ); - $this->publish->sync_to_discourse_without_lock( $post_id, $post->title, $post->post_content ); + // Run the publication. + $post = get_post( $post_id ); + $this->publish->sync_to_discourse_without_lock( $post_id, $post->title, $post->post_content ); - // Ensure the right post meta is created. - $this->assertEquals( get_post_meta( $post_id, 'discourse_post_id', true ), $discourse_post_id ); - $this->assertEquals( get_post_meta( $post_id, 'discourse_topic_id', true ), $discourse_topic_id ); - $this->assertEquals( get_post_meta( $post_id, 'discourse_permalink', true ), $discourse_permalink ); - $this->assertEquals( get_post_meta( $post_id, 'publish_post_category', true ), $discourse_category ); - $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_response', true ), 'success' ); + // Ensure the right post meta is created. + $this->assertEquals( get_post_meta( $post_id, 'discourse_post_id', true ), $discourse_post_id ); + $this->assertEquals( get_post_meta( $post_id, 'discourse_topic_id', true ), $discourse_topic_id ); + $this->assertEquals( get_post_meta( $post_id, 'discourse_permalink', true ), $discourse_permalink ); + $this->assertEquals( get_post_meta( $post_id, 'publish_post_category', true ), $discourse_category ); + $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_response', true ), 'success' ); - // Cleanup. - wp_delete_post( $post_id ); - } + // Cleanup. + wp_delete_post( $post_id ); + } - /** - * Sync_to_discourse when creating a new post and pinning topics. - */ - public function test_sync_to_discourse_pin_topic() { - // Set up a response body for creating a new post, with subsequent pin request. - $discourse_post = json_decode( $this->response_body_file( 'post_create' ) ); - $pin_until = '2021-02-17'; - $second_request = array( - 'url' => self::$discourse_url . "/t/{$discourse_post->topic_id}/status", - 'method' => 'PUT', - 'response' => $this->build_response( 'success' ), - ); - $body = $this->mock_remote_post_success( 'post_create', 'POST', $second_request ); + /** + * Sync_to_discourse when creating a new post and pinning topics. + */ + public function test_sync_to_discourse_pin_topic() { + // Set up a response body for creating a new post, with subsequent pin request. + $discourse_post = json_decode( $this->response_body_file( 'post_create' ) ); + $pin_until = '2021-02-17'; + $second_request = array( + 'url' => self::$discourse_url . "/t/{$discourse_post->topic_id}/status", + 'method' => 'PUT', + 'response' => $this->build_response( 'success' ), + ); + $body = $this->mock_remote_post_success( 'post_create', 'POST', $second_request ); - // Add a post that will be pinned. - $post_atts = self::$post_atts; - $post_atts['meta_input']['wpdc_pin_until'] = $pin_until; - $post_id = wp_insert_post( $post_atts, false, false ); + // Add a post that will be pinned. + $post_atts = self::$post_atts; + $post_atts['meta_input']['wpdc_pin_until'] = $pin_until; + $post_id = wp_insert_post( $post_atts, false, false ); - // Run the publication. - $post = get_post( $post_id ); - $response = $this->publish->sync_to_discourse_without_lock( - $post_id, - $post->title, - $post->post_content - ); + // Run the publication. + $post = get_post( $post_id ); + $response = $this->publish->sync_to_discourse_without_lock( + $post_id, + $post->title, + $post->post_content + ); - // Ensure the right result. - $this->assertFalse( is_wp_error( $response ) ); - $this->assertTrue( empty( get_post_meta( $post_id, 'wpdc_pin_until', true ) ) ); + // Ensure the right result. + $this->assertFalse( is_wp_error( $response ) ); + $this->assertTrue( empty( get_post_meta( $post_id, 'wpdc_pin_until', true ) ) ); - // Cleanup. - wp_delete_post( $post_id ); - } + // Cleanup. + wp_delete_post( $post_id ); + } - /** - * Sync_to_discourse when creating a new post with Discourse Username set. - */ - public function test_sync_to_discourse_discourse_username() { - $discourse_username = 'angus2'; + /** + * Sync_to_discourse when creating a new post with Discourse Username set. + */ + public function test_sync_to_discourse_discourse_username() { + $discourse_username = 'angus2'; - // Setup the user - $user_id = self::factory()->user->create(); - add_user_meta( $user_id, 'discourse_username', $discourse_username, true ); + // Setup the user + $user_id = self::factory()->user->create(); + add_user_meta( $user_id, 'discourse_username', $discourse_username, true ); - // Set up a response body for creating a new post - $raw_body = $this->response_body_file( 'post_create' ); - $discourse_post = json_decode( $raw_body ); - $response = $this->build_response( 'success' ); - $response['body'] = $raw_body; - $request = array( + // Set up a response body for creating a new post + $raw_body = $this->response_body_file( 'post_create' ); + $discourse_post = json_decode( $raw_body ); + $response = $this->build_response( 'success' ); + $response['body'] = $raw_body; + $request = array( 'headers' => array( 'Api-Key' => self::$connection_options['api-key'], 'Api-Username' => $discourse_username, @@ -330,49 +332,49 @@ class DiscoursePublishTest extends UnitTest { ), 'method' => 'POST', 'response' => $response, - ); - $body = $this->mock_remote_post( $request ); + ); + $body = $this->mock_remote_post( $request ); - // Add the post. - $post_atts = self::$post_atts; - $post_atts['post_author'] = $user_id; - $post_id = wp_insert_post( $post_atts, false, false ); + // Add the post. + $post_atts = self::$post_atts; + $post_atts['post_author'] = $user_id; + $post_id = wp_insert_post( $post_atts, false, false ); - // Run the publication. - $post = get_post( $post_id ); - $response = $this->publish->sync_to_discourse_without_lock( - $post_id, - $post->title, - $post->post_content - ); + // Run the publication. + $post = get_post( $post_id ); + $response = $this->publish->sync_to_discourse_without_lock( + $post_id, + $post->title, + $post->post_content + ); - // Ensure the right result. - $this->assertFalse( is_wp_error( $response ) ); + // Ensure the right result. + $this->assertFalse( is_wp_error( $response ) ); - // Cleanup. - wp_delete_post( $post_id ); - } + // Cleanup. + wp_delete_post( $post_id ); + } - /** - * Sync_to_discourse when creating a new post with Discourse Username set. - */ - public function test_sync_to_discourse_discourse_username_with_single_user_api_key() { - $discourse_username = 'angus'; + /** + * Sync_to_discourse when creating a new post with Discourse Username set. + */ + public function test_sync_to_discourse_discourse_username_with_single_user_api_key() { + $discourse_username = 'angus'; - // Enable single user api key - self::$plugin_options['single-user-api-key-publication'] = 1; - $this->publish->setup_options( self::$plugin_options ); + // Enable single user api key + self::$plugin_options['single-user-api-key-publication'] = 1; + $this->publish->setup_options( self::$plugin_options ); - // Setup the user - $user_id = self::factory()->user->create(); - add_user_meta( $user_id, 'discourse_username', $discourse_username, true ); + // Setup the user + $user_id = self::factory()->user->create(); + add_user_meta( $user_id, 'discourse_username', $discourse_username, true ); - // Set up a response body for creating a new post - $raw_body = $this->response_body_file( 'post_create' ); - $discourse_post = json_decode( $raw_body ); - $response = $this->build_response( 'success' ); - $response['body'] = $raw_body; - $first_request = array( + // Set up a response body for creating a new post + $raw_body = $this->response_body_file( 'post_create' ); + $discourse_post = json_decode( $raw_body ); + $response = $this->build_response( 'success' ); + $response['body'] = $raw_body; + $first_request = array( 'headers' => array( 'Api-Key' => self::$connection_options['api-key'], 'Api-Username' => self::$connection_options['publish-username'], @@ -381,439 +383,566 @@ class DiscoursePublishTest extends UnitTest { ), 'method' => 'POST', 'response' => $response, - ); - $second_request = array( - 'url' => self::$discourse_url . "/t/{$discourse_post->topic_id}/change-owner", - 'method' => 'POST', - 'body' => json_encode( - array( + ); + $second_request = array( + 'url' => self::$discourse_url . "/t/{$discourse_post->topic_id}/change-owner", + 'method' => 'POST', + 'body' => json_encode( + array( 'username' => $discourse_username, 'post_ids' => array( "{$discourse_post->id}" ), ) - ), - 'response' => $this->build_response( 'success' ), - ); - $body = $this->mock_remote_post( $first_request, $second_request ); + ), + 'response' => $this->build_response( 'success' ), + ); + $body = $this->mock_remote_post( $first_request, $second_request ); - // Add the post. - $post_atts = self::$post_atts; - $post_atts['post_author'] = $user_id; - $post_id = wp_insert_post( $post_atts, false, false ); + // Add the post. + $post_atts = self::$post_atts; + $post_atts['post_author'] = $user_id; + $post_id = wp_insert_post( $post_atts, false, false ); - // Run the publication. - $post = get_post( $post_id ); - $response = $this->publish->sync_to_discourse_without_lock( - $post_id, - $post->title, - $post->post_content - ); + // Run the publication. + $post = get_post( $post_id ); + $response = $this->publish->sync_to_discourse_without_lock( + $post_id, + $post->title, + $post->post_content + ); - // Ensure the right result. - $this->assertFalse( is_wp_error( $response ) ); + // Ensure the right result. + $this->assertFalse( is_wp_error( $response ) ); - // Cleanup. - wp_delete_post( $post_id ); - } + // Cleanup. + wp_delete_post( $post_id ); + } - /** - * Sync_to_discourse when updating a post. - */ - public function test_sync_to_discourse_when_updating() { - // Set up a response body for updating an existing post. - $body = $this->mock_remote_post_success( 'post_update', 'PUT' ); - $post = $body->post; + /** + * Sync_to_discourse when updating a post. + */ + public function test_sync_to_discourse_when_updating() { + // Set up a response body for updating an existing post. + $body = $this->mock_remote_post_success( 'post_update', 'PUT' ); + $post = $body->post; - $discourse_post_id = $post->id; - $discourse_topic_id = $post->topic_id; - $discourse_permalink = self::$discourse_url . '/t/' . $post->topic_slug . '/' . $post->topic_id; - $discourse_category = self::$post_atts['meta_input']['publish_post_category']; + $discourse_post_id = $post->id; + $discourse_topic_id = $post->topic_id; + $discourse_permalink = self::$discourse_url . '/t/' . $post->topic_slug . '/' . $post->topic_id; + $discourse_category = self::$post_atts['meta_input']['publish_post_category']; - // Add a post that's already been published to Discourse. - $post_atts = self::$post_atts; - $post_atts['meta_input']['discourse_post_id'] = $discourse_post_id; - $post_id = wp_insert_post( $post_atts, false, false ); + // Add a post that's already been published to Discourse. + $post_atts = self::$post_atts; + $post_atts['meta_input']['discourse_post_id'] = $discourse_post_id; + $post_id = wp_insert_post( $post_atts, false, false ); - // Run the update. - update_post_meta( $post_id, 'update_discourse_topic', 1 ); - $post = get_post( $post_id ); - $this->publish->sync_to_discourse_without_lock( $post_id, $post->title, $post->post_content ); + // Run the update. + update_post_meta( $post_id, 'update_discourse_topic', 1 ); + $post = get_post( $post_id ); + $this->publish->sync_to_discourse_without_lock( $post_id, $post->title, $post->post_content ); - // Ensure the right post meta still exists. - $this->assertEquals( get_post_meta( $post_id, 'discourse_post_id', true ), $discourse_post_id ); - $this->assertEquals( get_post_meta( $post_id, 'discourse_topic_id', true ), $discourse_topic_id ); - $this->assertEquals( get_post_meta( $post_id, 'discourse_permalink', true ), $discourse_permalink ); - $this->assertEquals( get_post_meta( $post_id, 'publish_post_category', true ), $discourse_category ); - $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_response', true ), 'success' ); + // Ensure the right post meta still exists. + $this->assertEquals( get_post_meta( $post_id, 'discourse_post_id', true ), $discourse_post_id ); + $this->assertEquals( get_post_meta( $post_id, 'discourse_topic_id', true ), $discourse_topic_id ); + $this->assertEquals( get_post_meta( $post_id, 'discourse_permalink', true ), $discourse_permalink ); + $this->assertEquals( get_post_meta( $post_id, 'publish_post_category', true ), $discourse_category ); + $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_response', true ), 'success' ); - // Cleanup. - wp_delete_post( $post_id ); - } + // Cleanup. + wp_delete_post( $post_id ); + } - /** - * Sync_to_discourse when updating a post and post is deleted. - */ - public function test_sync_to_discourse_when_updating_with_deleted_topic() { - // Setup the response body for an existing post that's been deleted. - $response = $this->build_response( 'success' ); - $raw_body = $this->response_body_json( 'post_update' ); - $body = json_decode( $raw_body ); - $body->post->deleted_at = '2021-03-10T23:06:05.328Z'; - $response['body'] = json_encode( $body ); - $request = array( + /** + * Sync_to_discourse when updating a post and post is deleted. + */ + public function test_sync_to_discourse_when_updating_with_deleted_topic() { + // Setup the response body for an existing post that's been deleted. + $response = $this->build_response( 'success' ); + $raw_body = $this->response_body_json( 'post_update' ); + $body = json_decode( $raw_body ); + $body->post->deleted_at = '2021-03-10T23:06:05.328Z'; + $response['body'] = json_encode( $body ); + $request = array( 'response' => $response, 'method' => 'PUT', - ); - $this->mock_remote_post( $request ); + ); + $this->mock_remote_post( $request ); - // Add a post that's already been published to Discourse. - $discourse_post_id = $body->post->id; - $post_atts = self::$post_atts; - $post_atts['meta_input']['discourse_post_id'] = $discourse_post_id; - $post_id = wp_insert_post( $post_atts, false, false ); + // Add a post that's already been published to Discourse. + $discourse_post_id = $body->post->id; + $post_atts = self::$post_atts; + $post_atts['meta_input']['discourse_post_id'] = $discourse_post_id; + $post_id = wp_insert_post( $post_atts, false, false ); - // Run the update. - update_post_meta( $post_id, 'update_discourse_topic', 1 ); - $post = get_post( $post_id ); - $response = $this->publish->sync_to_discourse_without_lock( - $post_id, - $post->title, - $post->post_content - ); + // Run the update. + update_post_meta( $post_id, 'update_discourse_topic', 1 ); + $post = get_post( $post_id ); + $response = $this->publish->sync_to_discourse_without_lock( + $post_id, + $post->title, + $post->post_content + ); - // Ensure the right error is returned. - $message = __( 'The Discourse topic associated with this post has been deleted', 'wp-discourse' ); - $this->assertEquals( $response, $this->build_notice( $message ) ); + // Ensure the right error is returned. + $message = __( 'The Discourse topic associated with this post has been deleted', 'wp-discourse' ); + $this->assertEquals( $response, $this->build_notice( $message ) ); - // Ensure the post meta is updated correctly. - $this->assertEquals( get_post_meta( $post_id, 'publish_to_discourse', true ), 1 ); - $this->assertEquals( get_post_meta( $post_id, 'discourse_post_id', true ), $discourse_post_id ); - $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_error', true ), 'deleted_topic' ); + // Ensure the post meta is updated correctly. + $this->assertEquals( get_post_meta( $post_id, 'publish_to_discourse', true ), 1 ); + $this->assertEquals( get_post_meta( $post_id, 'discourse_post_id', true ), $discourse_post_id ); + $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_error', true ), 'deleted_topic' ); - // Ensure the right log is created. - $log = $this->get_last_log(); - $this->assertRegExp( '/publish.WARNING: update_post.deleted_topic_notice/', $log ); + // Ensure the right log is created. + $log = $this->get_last_log(); + $this->assertRegExp( '/publish.WARNING: update_post.deleted_topic_notice/', $log ); - // cleanup. - wp_delete_post( $post_id ); - } + // cleanup. + wp_delete_post( $post_id ); + } - /** - * Sync_to_discourse when updating a post and adding featured link. - */ - public function test_sync_to_discourse_when_updating_with_featured_link() { - // Enable featured link option. - self::$plugin_options['add-featured-link'] = 1; - $this->publish->setup_options( self::$plugin_options ); + /** + * Sync_to_discourse when updating a post and adding featured link. + */ + public function test_sync_to_discourse_when_updating_with_featured_link() { + // Enable featured link option. + self::$plugin_options['add-featured-link'] = 1; + $this->publish->setup_options( self::$plugin_options ); - // Add a post that's already been published to Discourse. - $body = json_decode( $this->response_body_json( 'post_update' ) ); - $discourse_post = $body->post; - $post_atts = self::$post_atts; - $post_atts['meta_input']['discourse_post_id'] = $discourse_post->id; - $post_id = wp_insert_post( $post_atts, false, false ); + // Add a post that's already been published to Discourse. + $body = json_decode( $this->response_body_json( 'post_update' ) ); + $discourse_post = $body->post; + $post_atts = self::$post_atts; + $post_atts['meta_input']['discourse_post_id'] = $discourse_post->id; + $post_id = wp_insert_post( $post_atts, false, false ); - // Set up a response body for updating an existing post, and the featured link in the second request. - $second_request = array( - 'url' => self::$discourse_url . '/t/' . $discourse_post->topic_slug . '/' . $discourse_post->topic_id, - 'method' => 'PUT', - 'response' => $this->build_response( 'success' ), - ); - $body = $this->mock_remote_post_success( 'post_update', 'PUT', $second_request ); - $post = $body->post; + // Set up a response body for updating an existing post, and the featured link in the second request. + $second_request = array( + 'url' => self::$discourse_url . '/t/' . $discourse_post->topic_slug . '/' . $discourse_post->topic_id, + 'method' => 'PUT', + 'response' => $this->build_response( 'success' ), + ); + $body = $this->mock_remote_post_success( 'post_update', 'PUT', $second_request ); + $post = $body->post; - // Run the update. - update_post_meta( $post_id, 'update_discourse_topic', 1 ); - $post = get_post( $post_id ); - $response = $this->publish->sync_to_discourse_without_lock( - $post_id, - $post->title, - $post->post_content - ); + // Run the update. + update_post_meta( $post_id, 'update_discourse_topic', 1 ); + $post = get_post( $post_id ); + $response = $this->publish->sync_to_discourse_without_lock( + $post_id, + $post->title, + $post->post_content + ); - // Ensure the right result. - $this->assertFalse( is_wp_error( $response ) ); + // Ensure the right result. + $this->assertFalse( is_wp_error( $response ) ); - // Cleanup. - wp_delete_post( $post_id ); - } + // Cleanup. + wp_delete_post( $post_id ); + } - /** - * Sync_to_discourse when updating a post with direct-db-publication-flags. - */ - public function test_sync_to_discourse_when_updating_with_direct_db_publication_flags() { - // Enable direct db pubilcation flags option. - self::$plugin_options['direct-db-publication-flags'] = 1; - $this->publish->setup_options( self::$plugin_options ); + /** + * Sync_to_discourse when updating a post with direct-db-publication-flags. + */ + public function test_sync_to_discourse_when_updating_with_direct_db_publication_flags() { + // Enable direct db pubilcation flags option. + self::$plugin_options['direct-db-publication-flags'] = 1; + $this->publish->setup_options( self::$plugin_options ); - // Set up a response body for updating an existing post. - $body = $this->mock_remote_post_success( 'post_update', 'PUT' ); - $post = $body->post; + // Set up a response body for updating an existing post. + $body = $this->mock_remote_post_success( 'post_update', 'PUT' ); + $post = $body->post; - $discourse_post_id = $post->id; - $discourse_topic_id = $post->topic_id; - $discourse_permalink = self::$discourse_url . '/t/' . $post->topic_slug . '/' . $post->topic_id; - $discourse_category = self::$post_atts['meta_input']['publish_post_category']; + $discourse_post_id = $post->id; + $discourse_topic_id = $post->topic_id; + $discourse_permalink = self::$discourse_url . '/t/' . $post->topic_slug . '/' . $post->topic_id; + $discourse_category = self::$post_atts['meta_input']['publish_post_category']; - // Add a post that's already been published to Discourse. - $post_atts = self::$post_atts; - $post_atts['meta_input']['discourse_post_id'] = $discourse_post_id; - $post_id = wp_insert_post( $post_atts, false, false ); + // Add a post that's already been published to Discourse. + $post_atts = self::$post_atts; + $post_atts['meta_input']['discourse_post_id'] = $discourse_post_id; + $post_id = wp_insert_post( $post_atts, false, false ); - // Run the update. - update_post_meta( $post_id, 'update_discourse_topic', 1 ); - $post = get_post( $post_id ); - $result = $this->publish->sync_to_discourse_without_lock( $post_id, $post->title, $post->post_content ); + // Run the update. + update_post_meta( $post_id, 'update_discourse_topic', 1 ); + $post = get_post( $post_id ); + $result = $this->publish->sync_to_discourse_without_lock( $post_id, $post->title, $post->post_content ); - // Ensure the right post meta still exists. - $this->assertEquals( get_post_meta( $post_id, 'discourse_post_id', true ), $discourse_post_id ); - $this->assertEquals( get_post_meta( $post_id, 'discourse_topic_id', true ), $discourse_topic_id ); - $this->assertEquals( get_post_meta( $post_id, 'discourse_permalink', true ), $discourse_permalink ); - $this->assertEquals( get_post_meta( $post_id, 'publish_post_category', true ), $discourse_category ); - $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_response', true ), 'success' ); + // Ensure the right post meta still exists. + $this->assertEquals( get_post_meta( $post_id, 'discourse_post_id', true ), $discourse_post_id ); + $this->assertEquals( get_post_meta( $post_id, 'discourse_topic_id', true ), $discourse_topic_id ); + $this->assertEquals( get_post_meta( $post_id, 'discourse_permalink', true ), $discourse_permalink ); + $this->assertEquals( get_post_meta( $post_id, 'publish_post_category', true ), $discourse_category ); + $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_response', true ), 'success' ); - // Cleanup. - wp_delete_post( $post_id ); - } + // Cleanup. + wp_delete_post( $post_id ); + } - /** - * Exclude_tags prevents publication if excluded tag is present - */ - public function test_exclude_tags_with_exclusionary_tag() { - if ( version_compare( get_bloginfo( 'version' ), '5.6', '<' ) ) { - $this->markTestSkipped( - 'Not supported on WordPress version.' - ); - } + /** + * Exclude_tags prevents publication if excluded tag is present + */ + public function test_exclude_tags_with_exclusionary_tag() { + if ( version_compare( get_bloginfo( 'version' ), '5.6', '<' ) ) { + $this->markTestSkipped( + 'Not supported on WordPress version.' + ); + } - // Create the exclusionary tag - $excluded_term = term_exists( 'dont_publish', 'post_tag' ); - if ( ! $excluded_term ) { - $excluded_term = wp_insert_term( 'dont_publish', 'post_tag' ); - } - $excluded_term = get_tag( $excluded_term['term_id'] ); - $excluded_term_slug = $excluded_term->slug; + // Create the exclusionary tag + $excluded_term = term_exists( 'dont_publish', 'post_tag' ); + if ( ! $excluded_term ) { + $excluded_term = wp_insert_term( 'dont_publish', 'post_tag' ); + } + $excluded_term = get_tag( $excluded_term['term_id'] ); + $excluded_term_slug = $excluded_term->slug; - // Enable exclude_tags option. - self::$plugin_options['exclude_tags'] = array( $excluded_term_slug ); - $this->publish->setup_options( self::$plugin_options ); + // Enable exclude_tags option. + self::$plugin_options['exclude_tags'] = array( $excluded_term_slug ); + $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' ); - self::$post_atts['tags_input'] = array( $excluded_term_slug ); + // Set up a response body for creating a new post. + $body = $this->mock_remote_post_success( 'post_create', 'POST' ); + self::$post_atts['tags_input'] = array( $excluded_term_slug ); - // Add the post. - $post_id = wp_insert_post( self::$post_atts, false, false ); + // Add the post. + $post_id = wp_insert_post( self::$post_atts, false, false ); - // Run the publication. - $post = get_post( $post_id ); - $this->publish->publish_post_after_save( $post_id, $post ); + // Run the publication. + $post = get_post( $post_id ); + $this->publish->publish_post_after_save( $post_id, $post ); - // Ensure no publication occurs. - $this->assertEquals( get_post_meta( $post_id, 'discourse_post_id', true ), null ); - $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_response', true ), null ); + // Ensure no publication occurs. + $this->assertEquals( get_post_meta( $post_id, 'discourse_post_id', true ), null ); + $this->assertEquals( get_post_meta( $post_id, 'wpdc_publishing_response', true ), null ); - // Cleanup. - wp_delete_post( $post_id ); - wp_delete_term( $excluded_term->ID, 'post_tags' ); - } + // Cleanup. + wp_delete_post( $post_id ); + wp_delete_term( $excluded_term->ID, 'post_tags' ); + } - /** - * Exclude_tags does not prevent publication if excluded tag is not present - */ - public function test_exclude_tags_with_non_exclusionary_tag() { - // Create a non exclusionary tag - $term = term_exists( 'publish', 'post_tag' ); - if ( ! $term ) { - $term = wp_insert_term( 'publish', 'post_tag' ); - } - $term = get_tag( $term['term_id'] ); - $term_slug = $term->slug; + /** + * Exclude_tags does not prevent publication if excluded tag is not present + */ + public function test_exclude_tags_with_non_exclusionary_tag() { + // Create a non exclusionary tag + $term = term_exists( 'publish', 'post_tag' ); + if ( ! $term ) { + $term = wp_insert_term( 'publish', 'post_tag' ); + } + $term = get_tag( $term['term_id'] ); + $term_slug = $term->slug; - // Create the exclusionary tag - $excluded_term = term_exists( 'dont_publish', 'post_tag' ); - if ( ! $excluded_term ) { - $excluded_term = wp_insert_term( 'dont_publish', 'post_tag' ); - } - $excluded_term = get_tag( $excluded_term['term_id'] ); - $excluded_term_slug = $excluded_term->slug; + // Create the exclusionary tag + $excluded_term = term_exists( 'dont_publish', 'post_tag' ); + if ( ! $excluded_term ) { + $excluded_term = wp_insert_term( 'dont_publish', 'post_tag' ); + } + $excluded_term = get_tag( $excluded_term['term_id'] ); + $excluded_term_slug = $excluded_term->slug; - // Enable excluded tags option. - self::$plugin_options['exclude_tags'] = array( $excluded_term_slug ); - $this->publish->setup_options( self::$plugin_options ); + // Enable excluded tags option. + self::$plugin_options['exclude_tags'] = array( $excluded_term_slug ); + $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; - self::$post_atts['tags_input'] = array( $term_slug ); + // Set up a response body for creating a new post. + $body = $this->mock_remote_post_success( 'post_create', 'POST' ); + $discourse_post_id = $body->id; + self::$post_atts['tags_input'] = array( $term_slug ); - // Add the post. - $post_id = wp_insert_post( self::$post_atts, false, false ); + // Add the post. + $post_id = wp_insert_post( self::$post_atts, false, false ); - // Run the publication. - $post = get_post( $post_id ); - $this->publish->publish_post_after_save( $post_id, $post ); + // Run the publication. + $post = get_post( $post_id ); + $this->publish->publish_post_after_save( $post_id, $post ); - // Ensure publication occurs. - $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' ); + // Ensure publication occurs. + $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 ); - wp_delete_term( $term->ID, 'post_tags' ); - wp_delete_term( $excluded_term->ID, 'post_tags' ); - } + // Cleanup. + wp_delete_post( $post_id ); + wp_delete_term( $term->ID, 'post_tags' ); + wp_delete_term( $excluded_term->ID, 'post_tags' ); + } - /** - * wpdc_publish_options filters publish_options - */ - public function test_wpdc_publish_options() { - $tags = array( 'tag1', 'tag2' ); + /** + * wpdc_publish_options filters publish_options + */ + public function test_wpdc_publish_options() { + $tags = array( 'tag1', 'tag2' ); - // Add filter. - add_filter( - 'wpdc_publish_body', function( $body, $remote_post_type ) use ( $tags ) { - if ( 'create_post' === $remote_post_type ) { + // Add filter. + add_filter( + 'wpdc_publish_body', + function( $body, $remote_post_type ) use ( $tags ) { + if ( 'create_post' === $remote_post_type ) { $body['tags'] = $tags; - } - return $body; - }, 10, 2 - ); + } + return $body; + }, + 10, + 2 + ); - $raw_body = $this->response_body_json( 'post_create' ); - $response = $this->build_response( 'success' ); - $response['body'] = $raw_body; - $body = json_decode( $raw_body ); + $raw_body = $this->response_body_json( 'post_create' ); + $response = $this->build_response( 'success' ); + $response['body'] = $raw_body; + $body = json_decode( $raw_body ); - // Check tags are in the body passed to request. - add_filter( - 'pre_http_request', function( $prempt, $args, $url ) use ( $tags, $response ) { - $body = json_decode( $args['body'] ); + // Check tags are in the body passed to request. + add_filter( + 'pre_http_request', + function( $prempt, $args, $url ) use ( $tags, $response ) { + $body = json_decode( $args['body'] ); - if ( ! isset( $body->tags ) || ! ( $tags === $body->tags ) ) { + if ( ! isset( $body->tags ) || ! ( $tags === $body->tags ) ) { return new \WP_Error( 'http_request_failed', 'Failed to add tags' ); - } else { - return $response; - } - }, 10, 3 - ); + } else { + return $response; + } + }, + 10, + 3 + ); - // Setup post. - $post_id = wp_insert_post( self::$post_atts, false, false ); - $discourse_post_id = $body->id; + // Setup post. + $post_id = wp_insert_post( self::$post_atts, false, false ); + $discourse_post_id = $body->id; - // Run the publication. - $post = get_post( $post_id ); - $this->publish->publish_post_after_save( $post_id, $post ); + // Run the publication. + $post = get_post( $post_id ); + $this->publish->publish_post_after_save( $post_id, $post ); - // Ensure publication occurs. - $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' ); + // Ensure publication occurs. + $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 ); - } + // Cleanup. + wp_delete_post( $post_id ); + } - /** - * Successful remote_post request returns original response. - */ - public function test_remote_post_success() { - $success_response = $this->build_response( 'success' ); - $request = array( + /** + * 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. + */ + public function test_remote_post_success() { + $success_response = $this->build_response( 'success' ); + $request = array( 'response' => $success_response, 'method' => 'POST', - ); - $this->mock_remote_post( $request ); - $response = $this->publish->remote_post( ...self::$remote_post_params ); - $this->assertEquals( $response, $success_response ); - } + ); + $this->mock_remote_post( $request ); + $response = $this->publish->remote_post( ...self::$remote_post_params ); + $this->assertEquals( $response, $success_response ); + } - /** - * Forbidden remote_post request returns standardised WP_Error and creates correct log. - */ - public function test_remote_post_forbidden() { - $raw_response = $this->build_response( 'forbidden' ); - $request = array( + /** + * Forbidden remote_post request returns standardised WP_Error and creates correct log. + */ + public function test_remote_post_forbidden() { + $raw_response = $this->build_response( 'forbidden' ); + $request = array( 'response' => $raw_response, 'method' => 'POST', - ); - $this->mock_remote_post( $request ); + ); + $this->mock_remote_post( $request ); - $response = $this->publish->remote_post( ...self::$remote_post_params ); - $this->assertEquals( $response, $this->build_post_error() ); + $response = $this->publish->remote_post( ...self::$remote_post_params ); + $this->assertEquals( $response, $this->build_post_error() ); - $log = $this->get_last_log(); - $this->assertRegExp( '/publish.ERROR: create_post.post_error/', $log ); - $this->assertRegExp( '/"http_code":' . $raw_response['response']['code'] . '/', $log ); - } + $log = $this->get_last_log(); + $this->assertRegExp( '/publish.ERROR: create_post.post_error/', $log ); + $this->assertRegExp( '/"http_code":' . $raw_response['response']['code'] . '/', $log ); + } - /** - * Unprocessable remote_post request returns standardised WP_Error and creates correct log. - */ - public function test_remote_post_unprocessable() { - $raw_response = $this->build_response( 'unprocessable', 'title' ); - $request = array( + /** + * Unprocessable remote_post request returns standardised WP_Error and creates correct log. + */ + public function test_remote_post_unprocessable() { + $raw_response = $this->build_response( 'unprocessable', 'title' ); + $request = array( 'response' => $raw_response, 'method' => 'POST', - ); - $this->mock_remote_post( $request ); + ); + $this->mock_remote_post( $request ); - $response = $this->publish->remote_post( ...self::$remote_post_params ); - $this->assertEquals( $response, $this->build_post_error() ); + $response = $this->publish->remote_post( ...self::$remote_post_params ); + $this->assertEquals( $response, $this->build_post_error() ); - $log = $this->get_last_log(); - $this->assertRegExp( '/publish.ERROR: create_post.post_error/', $log ); - $this->assertRegExp( '/"http_code":' . $raw_response['response']['code'] . '/', $log ); - } + $log = $this->get_last_log(); + $this->assertRegExp( '/publish.ERROR: create_post.post_error/', $log ); + $this->assertRegExp( '/"http_code":' . $raw_response['response']['code'] . '/', $log ); + } - /** - * Forbidden remote_post request returns standardised WP_Error and creates correct log. - */ - public function test_remote_post_failed_to_connect() { - $request = array( + /** + * Forbidden remote_post request returns standardised WP_Error and creates correct log. + */ + public function test_remote_post_failed_to_connect() { + $request = array( 'method' => 'POST', 'response' => new \WP_Error( 'http_request_failed', 'cURL error 7: Failed to connect to localhost port 3000: Connection refused' ), - ); - $this->mock_remote_post( $request ); + ); + $this->mock_remote_post( $request ); - $response = $this->publish->remote_post( ...self::$remote_post_params ); - $this->assertEquals( $response, $this->build_post_error() ); + $response = $this->publish->remote_post( ...self::$remote_post_params ); + $this->assertEquals( $response, $this->build_post_error() ); - $log = $this->get_last_log(); - $this->assertRegExp( '/publish.ERROR: create_post.post_error/', $log ); - } + $log = $this->get_last_log(); + $this->assertRegExp( '/publish.ERROR: create_post.post_error/', $log ); + } - /** - * Build error returned by discourse-publish when post request fails. - */ - protected function build_post_error() { - $message = __( 'An error occurred when communicating with Discourse', 'wp-discourse' ); - return new \WP_Error( 'discourse_publishing_response_error', $message ); - } + /** + * Build error returned by discourse-publish when post request fails. + */ + protected function build_post_error() { + $message = __( 'An error occurred when communicating with Discourse', 'wp-discourse' ); + return new \WP_Error( 'discourse_publishing_response_error', $message ); + } - /** - * Build error returned by discourse-publish when response body is invalid. - */ - protected function build_body_error() { - $message = __( 'An invalid response was returned from Discourse', 'wp-discourse' ); - return new \WP_Error( 'discourse_publishing_response_error', $message ); - } + /** + * Build error returned by discourse-publish when response body is invalid. + */ + protected function build_body_error() { + $message = __( 'An invalid response was returned from Discourse', 'wp-discourse' ); + return new \WP_Error( 'discourse_publishing_response_error', $message ); + } - /** - * Build an error notice returned by discourse-publish when post queued or topic deleted. - */ - protected function build_notice( $message ) { - return new \WP_Error( 'discourse_publishing_response_notice', $message ); - } + /** + * Build an error notice returned by discourse-publish when post queued or topic deleted. + */ + protected function build_notice( $message ) { + return new \WP_Error( 'discourse_publishing_response_notice', $message ); + } - /** - * Initialize static variables used by test class. - */ - public static function initialize_variables() { - self::$remote_post_params = array( - self::$discourse_url, + /** + * Initialize static variables used by test class. + */ + public static function initialize_variables() { + self::$remote_post_params = array( + self::$discourse_url, array( 'timeout' => 30, 'method' => 'POST', @@ -836,6 +965,6 @@ class DiscoursePublishTest extends UnitTest { ), 'create_post', 1, - ); - } + ); + } }