Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions includes/class-content-distribution.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Newspack_Network\Content_Distribution\Admin;
use Newspack_Network\Content_Distribution\API;
use Newspack_Network\Content_Distribution\Editor;
use Newspack_Network\Content_Distribution\Canonical_Url;
use Newspack_Network\Content_Distribution\Incoming_Post;
use Newspack_Network\Content_Distribution\Outgoing_Post;
use WP_Post;
Expand Down Expand Up @@ -54,6 +55,8 @@ public static function init() {
CLI::init();
API::init();
Editor::init();

Canonical_Url::init();
}

/**
Expand Down
91 changes: 91 additions & 0 deletions includes/content-distribution/class-canonical-url.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php
/**
* Newspack Content Distribution Canonical URL Handler
*
* @package Newspack
*/

namespace Newspack_Network\Content_Distribution;

use Newspack_Network\Content_Distribution;

/**
* Class to filter the canonical URLs for distributed content.
*/
class Canonical_Url {

const OPTION_NAME = 'newspack_network_canonical_url';

/**
* Initialize hooks.
*/
public static function init() {
add_filter( 'get_canonical_url', array( __CLASS__, 'filter_canonical_url' ), 10, 2 );
add_filter( 'wpseo_canonical', array( __CLASS__, 'wpseo_canonical_url' ), 10 );
}

/**
* Filters the canonical URL for distributed content.
*
* @param string $canonical_url Canonical URL.
* @param object $post Post object.
*
* @return string
*/
public static function filter_canonical_url( $canonical_url, $post ) {
if ( ! Content_Distribution::is_post_incoming( $post ) ) {
return $canonical_url;
}

$incoming_post = new Incoming_Post( $post->ID );

if ( ! $incoming_post->is_linked() ) {
return $canonical_url;
}

$canonical_url = $incoming_post->get_original_post_url();

$base_url = get_option( self::OPTION_NAME, '' );
if ( $base_url ) {
$canonical_url = str_replace( $incoming_post->get_original_site_url(), $base_url, $canonical_url );
}

return $canonical_url;
}

/**
* Handles the canonical URL change for distributed content when Yoast SEO is in use.
*
* @param string $canonical_url The Yoast WPSEO deduced canonical URL.
*
* @return string $canonical_url The updated distributor friendly URL.
*/
public static function wpseo_canonical_url( $canonical_url ) {

// Return as is if not on a singular page - taken from rel_canonical().
if ( ! is_singular() ) {
return $canonical_url;
}

$id = get_queried_object_id();

// Return as is if we do not have a object id for context - taken from rel_canonical().
if ( 0 === $id ) {
return $canonical_url;
}

$post = get_post( $id );

// Return as is if we don't have a valid post object - taken from wp_get_canonical_url().
if ( ! $post ) {
return $canonical_url;
}

// Return as is if current post is not published - taken from wp_get_canonical_url().
if ( 'publish' !== $post->post_status ) {
return $canonical_url;
}

return self::filter_canonical_url( $canonical_url, $post );
}
}
26 changes: 25 additions & 1 deletion includes/content-distribution/class-incoming-post.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ class Incoming_Post {
* not configured for distribution.
*/
public function __construct( $payload ) {
$post = null;

if ( is_numeric( $payload ) ) {
$post = get_post( $payload );
$payload = get_post_meta( $payload, self::PAYLOAD_META, true );
}

Expand All @@ -87,7 +90,10 @@ public function __construct( $payload ) {
$this->payload = $payload;
$this->network_post_id = $payload['network_post_id'];

$post = $this->query_post();
if ( ! $post ) {
$post = $this->query_post();
}

if ( $post ) {
$this->ID = $post->ID;
$this->post = $post;
Expand Down Expand Up @@ -134,6 +140,24 @@ protected function get_post_payload() {
return get_post_meta( $this->ID, self::PAYLOAD_META, true );
}

/**
* Get the post original URL.
*
* @return string The post original post URL. Empty string if not found.
*/
public function get_original_post_url() {
return $this->payload['post_url'] ?? '';
}

/**
* Get the post original site URL.
*
* @return string The post original site URL. Empty string if not found.
*/
public function get_original_site_url() {
return $this->payload['site_url'] ?? '';
}

/**
* Find the post from the payload's network post ID.
*
Expand Down
2 changes: 1 addition & 1 deletion includes/incoming-events/class-canonical-url-updated.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace Newspack_Network\Incoming_Events;

use Newspack_Network\Distributor_Customizations\Canonical_Url;
use Newspack_Network\Content_Distribution\Canonical_Url;

/**
* Class to handle the Canonical Url Updated Event
Expand Down
61 changes: 61 additions & 0 deletions tests/unit-tests/content-distribution/test-admin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
/**
* Class TestContentDistributionAdmin
*
* @package Newspack_Network
*/

namespace Test\Content_Distribution;

use Newspack_Network\Content_Distribution\Admin;

/**
* Test the Content Distribution Admin class.
*/
class TestAdmin extends \WP_UnitTestCase {
/**
* Test default roles option value.
*/
public function test_default_roles_options() {
$roles = get_option( Admin::CAPABILITY_ROLES_OPTION_NAME );
$this->assertNotEmpty( $roles );
$this->assertContains( 'administrator', $roles );
$this->assertContains( 'editor', $roles );
$this->assertContains( 'author', $roles );
}

/**
* Test default roles capability.
*/
public function test_default_roles_capability() {
$default_roles = get_option( Admin::CAPABILITY_ROLES_OPTION_NAME );
$all_roles = wp_roles();
foreach ( $all_roles->roles as $role_key => $role ) {
$role_obj = get_role( $role_key );
if ( in_array( $role_key, $default_roles, true ) ) {
$this->assertTrue( $role_obj->has_cap( Admin::CAPABILITY ) );
} else {
$this->assertFalse( $role_obj->has_cap( Admin::CAPABILITY ) );
}
}
}

/**
* Test updating roles.
*/
public function test_update_roles() {
$roles = get_option( Admin::CAPABILITY_ROLES_OPTION_NAME );
$roles[] = 'contributor';
update_option( Admin::CAPABILITY_ROLES_OPTION_NAME, $roles );

$role_obj = get_role( 'contributor' );
$this->assertTrue( $role_obj->has_cap( Admin::CAPABILITY ) );

$roles = get_option( Admin::CAPABILITY_ROLES_OPTION_NAME );
$roles = array_diff( $roles, [ 'contributor' ] );
update_option( Admin::CAPABILITY_ROLES_OPTION_NAME, $roles );

$role_obj = get_role( 'contributor' );
$this->assertFalse( $role_obj->has_cap( Admin::CAPABILITY ) );
}
}
43 changes: 43 additions & 0 deletions tests/unit-tests/content-distribution/test-canonical-url.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php
/**
* Class TestContentDistributionCanonicalUrl
*
* @package Newspack_Network
*/

namespace Test\Content_Distribution;

use Newspack_Network\Content_Distribution\Incoming_Post;

/**
* Test the Content Distribution Canonical URL class.
*/
class TestCanonicalUrl extends \WP_UnitTestCase {
/**
* Test default canonical URL.
*/
public function test_default_canonical_url() {
$payload = get_sample_payload( '', get_bloginfo( 'url' ) );
$incoming_post = new Incoming_Post( $payload );
$post_id = $incoming_post->insert( $payload );

wp_publish_post( $post_id );

$this->assertEquals( $payload['post_url'], wp_get_canonical_url( get_post( $post_id ) ) );
}

/**
* Test custom canonical URL base.
*/
public function test_custom_canonical_url() {
update_option( 'newspack_network_canonical_url', 'https://custom.test' );

$payload = get_sample_payload( '', get_bloginfo( 'url' ) );
$incoming_post = new Incoming_Post( $payload );
$post_id = $incoming_post->insert( $payload );

wp_publish_post( $post_id );

$this->assertEquals( 'https://custom.test/2021/01/slug', wp_get_canonical_url( get_post( $post_id ) ) );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
* @package Newspack_Network
*/

namespace Test\Content_Distribution;

use Newspack_Network\Content_Distribution;
use Newspack_Network\Content_Distribution\Outgoing_Post;
use Newspack_Network\Hub\Node as Hub_Node;

/**
* Test the Content_Distribution class.
*/
class TestContentDistribution extends WP_UnitTestCase {
class TestContentDistribution extends \WP_UnitTestCase {
/**
* "Mocked" network nodes.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
* @package Newspack_Network
*/

namespace Test\Content_Distribution;

use Newspack_Network\Content_Distribution\Incoming_Post;

/**
* Test the Incoming_Post class.
*/
class TestIncomingPost extends WP_UnitTestCase {
class TestIncomingPost extends \WP_UnitTestCase {
/**
* URL for node that distributes posts.
*
Expand All @@ -36,51 +38,7 @@ class TestIncomingPost extends WP_UnitTestCase {
* Get sample post payload.
*/
private function get_sample_payload() {
return [
'site_url' => $this->node_1,
'post_id' => 1,
'network_post_id' => '1234567890abcdef1234567890abcdef',
'sites' => [ $this->node_2 ],
'post_data' => [
'title' => 'Title',
'post_status' => 'publish',
'date_gmt' => '2021-01-01 00:00:00',
'modified_gmt' => '2021-01-01 00:00:00',
'slug' => 'slug',
'post_type' => 'post',
'raw_content' => 'Content',
'content' => '<p>Content</p>',
'excerpt' => 'Excerpt',
'thumbnail_url' => 'https://picsum.photos/id/1/300/300.jpg',
'taxonomy' => [
'category' => [
[
'name' => 'Category 1',
'slug' => 'category-1',
],
[
'name' => 'Category 2',
'slug' => 'category-2',
],
],
'post_tag' => [
[
'name' => 'Tag 1',
'slug' => 'tag-1',
],
[
'name' => 'Tag 2',
'slug' => 'tag-2',
],
],
],
'post_meta' => [
'single' => [ 'value' ],
'array' => [ [ 'a' => 'b', 'c' => 'd' ] ], // phpcs:ignore WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound
'multiple' => [ 'value 1', 'value 2' ],
],
],
];
return get_sample_payload( $this->node_1, $this->node_2 );
}

/**
Expand Down Expand Up @@ -222,6 +180,26 @@ public function test_insert_post_when_unlinked() {
$this->assertSame( 'Custom Content', $incoming_post->post_content );
}

/**
* Test get original post URL.
*/
public function test_get_original_post_url() {
$post_id = $this->incoming_post->insert();
$original_url = $this->incoming_post->get_original_post_url();
$payload = $this->get_sample_payload();
$this->assertSame( $payload['post_url'], $original_url );
}

/**
* Test get original site URL.
*/
public function test_get_original_site_url() {
$post_id = $this->incoming_post->insert();
$original_url = $this->incoming_post->get_original_site_url();
$payload = $this->get_sample_payload();
$this->assertSame( $payload['site_url'], $original_url );
}

/**
* Test relink post.
*/
Expand Down
Loading
Loading