Skip to content

Commit

Permalink
Merge pull request #962 from alleyinteractive/feature/v2.3.3
Browse files Browse the repository at this point in the history
Release v2.3.3
  • Loading branch information
kevinfodness authored Nov 9, 2022
2 parents ec67f91 + 87b6627 commit a462e3f
Show file tree
Hide file tree
Showing 12 changed files with 167 additions and 62 deletions.
47 changes: 47 additions & 0 deletions admin/class-admin-apple-post-sync.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,53 @@ public function __construct( $settings = null ) {
if ( 'yes' === $this->settings->get( 'api_autosync_delete' ) ) {
add_action( 'before_delete_post', array( $this, 'do_delete' ) );
}

// Optionally take certain actions on post status transition.
add_action( 'transition_post_status', [ $this, 'action__transition_post_status' ], 10, 3 );
}

/**
* A callback function for the transition_post_status action hook.
*
* @param string $new_status The new post status after the transition.
* @param string $old_status The previous post status.
* @param WP_Post $post The post object being transitioned.
*/
public function action__transition_post_status( $new_status, $old_status, $post ) {
/**
* Determines whether to delete an article via the Apple News API if it is
* moved from publish status to the trash in WordPress.
*
* @since 2.3.3
*
* @param bool $should_delete Whether the post should be deleted via the Apple News API or not.
* @param int $post_id The ID of the post that was moved to the trash.
*/
$delete_on_trash = apply_filters( 'apple_news_should_post_delete_on_trash', false, $post->ID );

/**
* Determines whether to delete an article via the Apple News API if it is
* unpublished in WordPress (defined as moving a post from the `publish`
* status to any other status, including `trash`).
*
* @since 2.3.3
*
* @param bool $should_delete Whether the post should be deleted via the Apple News API or not.
* @param int $post_id The ID of the post that was unpublished.
*/
$delete_on_unpublish = apply_filters( 'apple_news_should_post_delete_on_unpublish', false, $post->ID );

// Determine whether to delete the article via the API.
if ( $old_status !== $new_status
&& 'publish' === $old_status
&& ( $delete_on_unpublish
|| ( 'trash' === $new_status
&& $delete_on_trash
)
)
) {
$this->do_delete( $post->ID );
}
}

/**
Expand Down
2 changes: 1 addition & 1 deletion apple-news.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* Plugin Name: Publish to Apple News
* Plugin URI: http://github.com/alleyinteractive/apple-news
* Description: Export and sync posts to Apple format.
* Version: 2.3.2
* Version: 2.3.3
* Author: Alley
* Author URI: https://alley.co
* Text Domain: apple-news
Expand Down
2 changes: 1 addition & 1 deletion includes/class-apple-news.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class Apple_News {
* @var string
* @access public
*/
public static $version = '2.3.2';
public static $version = '2.3.3';

/**
* Link to support for the plugin on WordPress.org.
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "publish-to-apple-news",
"version": "2.3.2",
"version": "2.3.3",
"license": "GPLv3",
"main": "index.php",
"engines": {
Expand Down
8 changes: 6 additions & 2 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ Contributors: potatomaster, kevinfodness, jomurgel, tylermachado, benpbolton, al
Donate link: https://wordpress.org
Tags: publish, apple, news, iOS
Requires at least: 4.0
Tested up to: 5.9
Tested up to: 6.1
Requires PHP: 5.6
Stable tag: 2.3.2
Stable tag: 2.3.3
License: GPLv3 or later
License URI: https://www.gnu.org/licenses/gpl.html

Expand Down Expand Up @@ -46,6 +46,10 @@ Please visit our [wiki](https://github.com/alleyinteractive/apple-news/wiki) for

== Changelog ==

= 2.3.3 =
* Enhancement: Tested up to WordPress 6.1.
* Experimental: Added opt-in filters for deleting posts that have been unpublished.

= 2.3.2 =
* Bugfix: Fixes a bug where the layout body-layout-last is not added to the list of layouts if the body content ends with something other than a paragraph.
* Bugfix: Fixes a bug where galleries were no longer being properly converted to Apple News Format due to a change in gallery markup that was introduced in WordPress 5.8.
Expand Down
131 changes: 86 additions & 45 deletions tests/admin/apple-actions/index/test-class-delete.php
Original file line number Diff line number Diff line change
@@ -1,56 +1,97 @@
<?php
/**
* Publish to Apple News tests: Apple_News_Admin_Action_Index_Delete_Test class
*
* @package Apple_News
* @subpackage Tests
*/

use \Apple_Actions\Index\Delete as Delete;
use \Apple_Exporter\Settings as Settings;
use \Prophecy\Argument as Argument;
use Apple_Actions\Index\Delete;

class Admin_Action_Index_Delete_Test extends WP_UnitTestCase {
/**
* A class to test the functionality of the Apple_Actions\Index\Delete class.
*
* @package Apple_News
* @subpackage Tests
*/
class Apple_News_Admin_Action_Index_Delete_Test extends Apple_News_Testcase {
/**
* Tests the behavior of the automatic delete setting.
*/
public function test_auto_delete() {
// Create a post, which will automatically be published.
$this->become_admin();
$this->add_http_response( 'POST', 'https://news-api.apple.com/channels/foo/articles', wp_json_encode( $this->fake_article_response() ) );
$this->assertNotEmpty( $this->http_responses['POST']['https://news-api.apple.com/channels/foo/articles'] );
$post_id = self::factory()->post->create();
$this->assertEmpty( $this->http_responses['POST']['https://news-api.apple.com/channels/foo/articles'] );

private $prophet;
// Add an HTTP response for the delete operation, then delete the article, and verify it was triggered.
$this->add_http_response( 'DELETE', 'https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456' );
$this->assertNotEmpty( $this->http_responses['DELETE']['https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456'] );
wp_delete_post( $post_id, true );
$this->assertEmpty( $this->http_responses['DELETE']['https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456'] );

public function setup() {
parent::setup();
// Create a new article and move it to the trash and verify that the delete operation was not triggered.
$this->add_http_response( 'POST', 'https://news-api.apple.com/channels/foo/articles', wp_json_encode( $this->fake_article_response() ) );
$this->assertNotEmpty( $this->http_responses['POST']['https://news-api.apple.com/channels/foo/articles'] );
$post_id = self::factory()->post->create();
$this->assertEmpty( $this->http_responses['POST']['https://news-api.apple.com/channels/foo/articles'] );
$this->add_http_response( 'DELETE', 'https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456' );
$this->assertNotEmpty( $this->http_responses['DELETE']['https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456'] );
wp_delete_post( $post_id );
$this->assertNotEmpty( $this->http_responses['DELETE']['https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456'] );
array_pop( $this->http_responses['DELETE']['https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456'] );
$this->assertEmpty( $this->http_responses['DELETE']['https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456'] );

$this->prophet = new \Prophecy\Prophet;
$this->settings = new Settings();
$this->settings->set( 'api_key', 'foo' );
$this->settings->set( 'api_secret', 'bar' );
$this->settings->set( 'api_channel', 'baz' );
}

public function tearDown() {
$this->prophet->checkPredictions();
}

public function testActionPerform() {
$remote_id = uniqid();
$api = $this->prophet->prophesize( '\Apple_Push_API\API' );
$api->delete_article( $remote_id )
->shouldBeCalled();

// Create post with dummy remote id
$post_id = $this->factory->post->create();
update_post_meta( $post_id, 'apple_news_api_id', $remote_id );
// Create a new article and move it to draft status and verify that the delete operation was not triggered.
$this->add_http_response( 'POST', 'https://news-api.apple.com/channels/foo/articles', wp_json_encode( $this->fake_article_response() ) );
$this->assertNotEmpty( $this->http_responses['POST']['https://news-api.apple.com/channels/foo/articles'] );
$post = self::factory()->post->create_and_get();
$this->assertEmpty( $this->http_responses['POST']['https://news-api.apple.com/channels/foo/articles'] );
$this->add_http_response( 'DELETE', 'https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456' );
$this->assertNotEmpty( $this->http_responses['DELETE']['https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456'] );
$post->post_status = 'draft';
wp_update_post( $post );
$this->assertNotEmpty( $this->http_responses['DELETE']['https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456'] );
array_pop( $this->http_responses['DELETE']['https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456'] );
$this->assertEmpty( $this->http_responses['DELETE']['https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456'] );

$action = new Delete( $this->settings, $post_id );
$action->set_api( $api->reveal() );
$action->perform();
// Opt in to delete on trash via filter, create a new article, move it to the trash, and verify that the delete operation was triggered.
add_filter( 'apple_news_should_post_delete_on_trash', '__return_true' );
$this->add_http_response( 'POST', 'https://news-api.apple.com/channels/foo/articles', wp_json_encode( $this->fake_article_response() ) );
$this->assertNotEmpty( $this->http_responses['POST']['https://news-api.apple.com/channels/foo/articles'] );
$post_id = self::factory()->post->create();
$this->assertEmpty( $this->http_responses['POST']['https://news-api.apple.com/channels/foo/articles'] );
$this->add_http_response( 'DELETE', 'https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456' );
$this->assertNotEmpty( $this->http_responses['DELETE']['https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456'] );
wp_delete_post( $post_id );
$this->assertEmpty( $this->http_responses['DELETE']['https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456'] );
remove_filter( 'apple_news_should_post_delete_on_trash', '__return_true' );

$this->assertNotEquals( null, get_post_meta( $post_id, 'apple_news_api_deleted', true ) );
$this->assertEquals( null, get_post_meta( $post_id, 'apple_news_api_id', true ) );
}

public function testActionPerformWhenNotPushed() {
// Expect an exception
$this->setExpectedException( '\Apple_Actions\Action_Exception', 'This post has not been pushed to Apple News, cannot delete.' );

$api = $this->prophet->prophesize( '\Push_API\API' );
$post_id = $this->factory->post->create();
// Opt in to delete on unpublish via filter, create a new article, move it to draft, and verify that the delete operation was triggered.
add_filter( 'apple_news_should_post_delete_on_unpublish', '__return_true' );
$this->add_http_response( 'POST', 'https://news-api.apple.com/channels/foo/articles', wp_json_encode( $this->fake_article_response() ) );
$this->assertNotEmpty( $this->http_responses['POST']['https://news-api.apple.com/channels/foo/articles'] );
$post = self::factory()->post->create_and_get();
$this->assertEmpty( $this->http_responses['POST']['https://news-api.apple.com/channels/foo/articles'] );
$this->add_http_response( 'DELETE', 'https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456' );
$this->assertNotEmpty( $this->http_responses['DELETE']['https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456'] );
$post->post_status = 'draft';
wp_update_post( $post );
$this->assertEmpty( $this->http_responses['DELETE']['https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456'] );
remove_filter( 'apple_news_should_post_delete_on_unpublish', '__return_true' );

$action = new Delete( $this->settings, $post_id );
$action->set_api( $api->reveal() );
$action->perform();
// Opt in to delete on unpublish via filter, create a new article, move it to the trash, and verify that the delete operation was triggered.
add_filter( 'apple_news_should_post_delete_on_unpublish', '__return_true' );
$this->add_http_response( 'POST', 'https://news-api.apple.com/channels/foo/articles', wp_json_encode( $this->fake_article_response() ) );
$this->assertNotEmpty( $this->http_responses['POST']['https://news-api.apple.com/channels/foo/articles'] );
$post_id = self::factory()->post->create();
$this->assertEmpty( $this->http_responses['POST']['https://news-api.apple.com/channels/foo/articles'] );
$this->add_http_response( 'DELETE', 'https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456' );
$this->assertNotEmpty( $this->http_responses['DELETE']['https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456'] );
wp_delete_post( $post_id );
$this->assertEmpty( $this->http_responses['DELETE']['https://news-api.apple.com/articles/abcd1234-ef56-ab78-cd90-efabcdef123456'] );
remove_filter( 'apple_news_should_post_delete_on_unpublish', '__return_true' );
}

}

2 changes: 1 addition & 1 deletion tests/admin/apple-actions/index/test-class-push.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public function test_component_errors() {
$notices = get_user_meta( $user_id, 'apple_news_notice', true );
$this->assertEquals( 2, count( $notices ) );
$this->assertEquals( 'error', $notices[0]['type'] );
$this->assertEquals( 'Your Apple News API settings seem to be empty. Please fill in the API key, API secret and API channel fields in the plugin configuration page.', $notices[0]['message'] );
$this->assertEquals( 'There has been an error with the Apple News API: There has been an error with your request: ', $notices[0]['message'] );
$this->assertEquals( 'success', $notices[1]['type'] );
$this->assertEquals( 'abcd1234-ef56-ab78-cd90-efabcdef123456', get_post_meta( $post_id_1, 'apple_news_api_id', true ) );

Expand Down
1 change: 1 addition & 0 deletions tests/admin/test-class-admin-apple-notice.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
class Admin_Apple_Notice_Test extends WP_UnitTestCase {

public function setup() {
parent::setup();
$this->user_id = $this->factory->user->create( array( 'role' => 'administrator' ) );
wp_set_current_user( $this->user_id );
}
Expand Down
2 changes: 1 addition & 1 deletion tests/admin/test-class-admin-rest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
/**
* A class which is used to test REST requests in the admin.
*/
class Admin_Apple_REST_Test extends WP_UnitTestCase {
class Admin_Apple_REST_Test extends Apple_News_Testcase {
/**
* Make a REST request to reset API postmeta entries.
*
Expand Down
10 changes: 10 additions & 0 deletions tests/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ function _manually_load_plugin() {
update_option( 'permalink_structure', '/%postname%' );
update_option( 'siteurl', 'https://www.example.org' );

// Apple News reads in the channel/key/secret values on load.
update_option(
'apple_news_settings',
[
'api_channel' => 'foo',
'api_key' => 'bar',
'api_secret' => 'baz',
]
);

// Force WP to treat URLs as HTTPS during testing so the home and siteurl option protocols are honored.
$_SERVER['HTTPS'] = 1;

Expand Down
18 changes: 10 additions & 8 deletions tests/class-apple-news-testcase.php
Original file line number Diff line number Diff line change
Expand Up @@ -212,14 +212,16 @@ public function tearDown() {
* @param string $url The API endpoint to fake the response for.
* @param string $body The faked response body.
*/
protected function add_http_response( $verb, $url, $body, $headers = [], $response = [ 'code' => 200, 'message' => 'OK' ], $cookies = [], $filename = null ) {
$this->http_responses[ $verb ][ $url ][] = [
'body' => $body,
'cookies' => $cookies,
'filename' => $filename,
'headers' => new Requests_Utility_CaseInsensitiveDictionary( $headers ),
'response' => $response,
];
protected function add_http_response( $verb, $url, $body = '', $headers = [], $response = [ 'code' => 200, 'message' => 'OK' ], $cookies = [], $filename = null ) {
// Handle null for DELETE.
$this->http_responses[ $verb ][ $url ][] = 'DELETE' !== $verb
? [
'body' => $body,
'cookies' => $cookies,
'filename' => $filename,
'headers' => new Requests_Utility_CaseInsensitiveDictionary( $headers ),
'response' => $response,
] : null;
}

/**
Expand Down

0 comments on commit a462e3f

Please sign in to comment.