-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(content-distribution): Sync authors #194
Open
naxoc
wants to merge
34
commits into
trunk
Choose a base branch
from
feat/content-distribution-authors
base: trunk
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+554
−25
Open
Changes from 21 commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
18cb10c
work in progress
naxoc 06d1397
Merge branch 'trunk' into feat/content-distribution-authors
naxoc 0227d6c
Merge branch 'trunk' into feat/content-distribution-authors
naxoc d323ebb
Merge branch 'trunk' into feat/content-distribution-authors
naxoc 25511b4
Add to outgoing
naxoc 2a7185f
Clean up
naxoc 36b30ed
Merge branch 'trunk' into feat/content-distribution-authors
naxoc 6e13d27
Liniting
naxoc c4581cd
Remane to avoid confusion
naxoc b08b048
Merge branch 'trunk' into feat/content-distribution-authors
naxoc 077d5ce
Merge branch 'trunk' into feat/content-distribution-authors
naxoc cd2276c
Add some comments on a way forward
naxoc caa506d
Move stuff around
naxoc ea7bb12
Merge branch 'trunk' into feat/content-distribution-authors
naxoc beed21f
most things work now
naxoc 8e770bb
Fix tests
naxoc 4150ad0
Work in progress
naxoc c718269
Merge branch 'trunk' into feat/content-distribution-authors
naxoc 9b66863
PHPCS
naxoc ffd0116
Cleanup
naxoc f0e4459
Check for warning
naxoc 1700eb7
Work in progress
naxoc 7f20d29
Merge branch 'trunk' into feat/content-distribution-authors
naxoc 32a5d18
Use partial payloads and simplify
naxoc 71ac748
phpcs
naxoc 113d019
More phpcs
naxoc 37c2c9b
Suggestion from review
naxoc 33daeb0
Review feedback
naxoc 12547b6
Move 'multiple_authors' to post data
naxoc 0736b2b
Use filter for both incoming and outgoing multiple_authors
naxoc 7ae0574
Don't hit the db more than necessary
naxoc 1c69f02
Move outoging authors to outgoing post
naxoc af741a4
Move incoming authors to incoming post
naxoc 17e4b8c
Fix docblock
naxoc File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
103 changes: 103 additions & 0 deletions
103
includes/content-distribution/class-cap-authors-filters.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
<?php | ||
/** | ||
* Newspack Network filters for making guest authors work. | ||
* | ||
* @package Newspack | ||
*/ | ||
|
||
namespace Newspack_Network\Content_Distribution; | ||
|
||
/** | ||
* Class to support distributed Guest Authors. | ||
*/ | ||
class Cap_Authors_Filters { | ||
|
||
/** | ||
* Go! | ||
* | ||
* @return void | ||
*/ | ||
public static function init(): void { | ||
if ( ! Cap_Authors::is_co_authors_plus_active() ) { | ||
return; | ||
} | ||
|
||
if ( ! is_admin() ) { | ||
add_filter( 'get_coauthors', [ __CLASS__, 'filter_get_coauthors' ], 10, 2 ); | ||
add_filter( 'newspack_author_bio_name', [ __CLASS__, 'filter_newspack_author_bio_name' ], 10, 3 ); | ||
add_filter( 'author_link', [ __CLASS__, 'filter_author_link' ], 20, 3 ); | ||
} | ||
} | ||
|
||
/** | ||
* Filters the coauthors of a post to include CAP's guest authors | ||
* | ||
* @param array $coauthors Array of coauthors. | ||
* @param int $post_id Post ID. | ||
* | ||
* @return array | ||
*/ | ||
public static function filter_get_coauthors( $coauthors, $post_id ) { | ||
if ( empty( get_post_meta( $post_id, Incoming_Post::NETWORK_POST_ID_META, true ) ) ) { | ||
return $coauthors; | ||
} | ||
|
||
$distributed_authors = get_post_meta( $post_id, Cap_Authors::AUTHOR_LIST_META_KEY, true ); | ||
|
||
if ( ! $distributed_authors ) { | ||
return $coauthors; | ||
} | ||
|
||
$guest_authors = []; | ||
|
||
foreach ( $distributed_authors as $distributed_author ) { | ||
|
||
if ( 'guest_author' !== $distributed_author['type'] ) { | ||
continue; | ||
} | ||
// This removes the author URL from the guest author. | ||
$distributed_author['user_nicename'] = ''; | ||
$distributed_author['ID'] = - 2; | ||
|
||
$guest_authors[] = (object) $distributed_author; | ||
} | ||
|
||
return [ ...$coauthors, ...$guest_authors ]; | ||
} | ||
|
||
/** | ||
* Add job title for guest authors in the author bio. | ||
* | ||
* @param string $author_name The author name. | ||
* @param int $author_id The author ID. | ||
* @param object $author The author object. | ||
*/ | ||
public static function filter_newspack_author_bio_name( $author_name, $author_id, $author = null ) { | ||
if ( empty( $author->type ) || 'guest_author' !== $author->type ) { | ||
return $author_name; | ||
} | ||
|
||
if ( $author && ! empty( $author->newspack_job_title ) ) { | ||
$author_name .= '<span class="author-job-title">' . $author->newspack_job_title . '</span>'; | ||
} | ||
|
||
return $author_name; | ||
} | ||
|
||
/** | ||
* Filter the author link for guest authors. | ||
* | ||
* @param string $link The author link. | ||
* @param int $author_id The author ID. | ||
* @param string $author_nicename The author nicename. | ||
* | ||
* @return string | ||
*/ | ||
public static function filter_author_link( $link, $author_id, $author_nicename ) { | ||
if ( - 2 === $author_id && empty( $author_nicename ) ) { | ||
$link = '#'; | ||
} | ||
|
||
return $link; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
<?php | ||
/** | ||
* Newspack Network author ingestion for content distribution. | ||
* | ||
* @package Newspack | ||
*/ | ||
|
||
namespace Newspack_Network\Content_Distribution; | ||
|
||
use Newspack_Network\Debugger; | ||
use Newspack_Network\User_Update_Watcher; | ||
use WP_Error; | ||
use WP_Post; | ||
|
||
/** | ||
* Class to handle author ingestion for content distribution. | ||
*/ | ||
class Cap_Authors { | ||
|
||
/** | ||
* Meta key for the author list we transfer. | ||
* | ||
* Note that it can have both Guest Contributors (that are WP_User objects) and Guest Authors (that are Guest Author objects). | ||
*/ | ||
const AUTHOR_LIST_META_KEY = 'newspack_network_author_list'; | ||
|
||
/** | ||
* Get things going. | ||
* | ||
* @return void | ||
*/ | ||
public static function init(): void { | ||
if ( ! self::is_co_authors_plus_active() ) { | ||
return; | ||
} | ||
Cap_Authors_Filters::init(); | ||
|
||
add_action( 'set_object_terms', [ __CLASS__, 'handle_cap_author_change' ], 10, 6 ); | ||
} | ||
|
||
/** | ||
* Helper to check if Co-Authors Plus is active. | ||
* | ||
* @return bool Whether Co-Authors Plus is active. | ||
*/ | ||
public static function is_co_authors_plus_active(): bool { | ||
global $coauthors_plus; | ||
|
||
return $coauthors_plus instanceof \CoAuthors_Plus && function_exists( 'get_coauthors' ); | ||
} | ||
|
||
/** | ||
* Action callback. | ||
* | ||
* Add a postmeta entry with the Co-Authors Plus authors for outgoing posts. | ||
* | ||
* @param int $object_id The object ID. | ||
* @param array $terms The terms. | ||
* @param array $tt_ids The term taxonomy IDs. | ||
* @param string $taxonomy The taxonomy. | ||
* @param bool $append Whether to append. | ||
* @param array $old_tt_ids The old term taxonomy IDs. | ||
* | ||
* @return void | ||
*/ | ||
public static function handle_cap_author_change( $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids ): void { | ||
if ( 'author' !== $taxonomy ) { // Co-Authors Plus author taxonomy. | ||
return; | ||
} | ||
// If the terms are the same, we don't need to do anything. Note that one array has string values and one has | ||
// int values, so we use array_map with the intval for the comparison. | ||
if ( array_map( 'intval', $old_tt_ids ) === array_map( 'intval', $tt_ids ) ) { | ||
return; | ||
} | ||
|
||
try { | ||
$outgoing_post = new Outgoing_Post( $object_id ); | ||
if ( ! $outgoing_post->is_distributed() ) { | ||
naxoc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// TODO. This is problematic I think. | ||
return; | ||
} | ||
|
||
$cap_authors = self::get_cap_authors_for_distribution( $outgoing_post->get_post() ); | ||
update_post_meta( $object_id, self::AUTHOR_LIST_META_KEY, $cap_authors ); | ||
|
||
} catch ( \InvalidArgumentException ) { | ||
return; | ||
} | ||
} | ||
|
||
/** | ||
* Get the Co-Authors Plus authors for distribution. | ||
* | ||
* @param WP_Post $post Post to get authors for. | ||
* | ||
* @return array Array of authors in distributable format. | ||
*/ | ||
private static function get_cap_authors_for_distribution( WP_Post $post ): array { | ||
|
||
$co_authors = get_coauthors( $post->ID ); | ||
if ( empty( $co_authors ) ) { | ||
return []; | ||
} | ||
|
||
$authors = []; | ||
|
||
foreach ( $co_authors as $co_author ) { | ||
if ( is_a( $co_author, 'WP_User' ) ) { | ||
// This will never return an error because we are checking for is_a() first. | ||
$authors[] = Outgoing_Author::get_wp_user_for_distribution( $co_author ); | ||
continue; | ||
} | ||
|
||
$guest_author = self::get_guest_author_for_distribution( $co_author ); | ||
if ( is_wp_error( $guest_author ) ) { | ||
Debugger::log( 'Error getting guest author for distribution on post ' . $post->ID . ': ' . $guest_author->get_error_message() ); | ||
Debugger::log( $co_author ); | ||
continue; | ||
} | ||
$authors[] = $guest_author; | ||
} | ||
|
||
return $authors; | ||
} | ||
|
||
/** | ||
* Ingest authors for a post distributed to this site | ||
* | ||
* @param int $post_id The post ID. | ||
* @param string $remote_url The remote URL. | ||
* @param array $cap_authors Array of distributed authors. | ||
* | ||
* @return void | ||
*/ | ||
public static function ingest_cap_authors_for_post( int $post_id, string $remote_url, array $cap_authors ): void { | ||
if ( ! self::is_co_authors_plus_active() ) { | ||
return; | ||
} | ||
|
||
$cap_authors = reset( $cap_authors ); | ||
if (! is_array( $cap_authors ) || empty( $cap_authors ) ) { | ||
return; | ||
} | ||
|
||
Debugger::log( 'Ingesting authors from networked post.' ); | ||
User_Update_Watcher::$enabled = false; | ||
|
||
$coauthors = []; | ||
|
||
foreach ( $cap_authors as $author ) { | ||
$author_type = $author['type'] ?? ''; | ||
switch ( $author_type ) { | ||
case 'wp_user': | ||
$user = Incoming_Author::get_wp_user_author( $remote_url, $author ); | ||
if ( is_wp_error( $user ) ) { | ||
Debugger::log( 'Error ingesting author: ' . $user->get_error_message() ); | ||
} | ||
$coauthors[] = $user->user_nicename; | ||
break; | ||
case 'guest_author': | ||
// Do nothing here. We get the guest authors from the meta data on post views. See Cap_Authors_Filters. | ||
break; | ||
default: | ||
Debugger::log( sprintf( 'Error ingesting author: Invalid author type "%s"', $author_type ) ); | ||
} | ||
} | ||
|
||
global $coauthors_plus; | ||
// Do this even if the array is empty, to clear out any existing authors. | ||
$coauthors_plus->add_coauthors( $post_id, $coauthors ); | ||
} | ||
|
||
/** | ||
* Get the guest author data to be distributed along with the post. | ||
* | ||
* @param object $guest_author The Guest Author object. | ||
* | ||
* @return WP_Error|array | ||
*/ | ||
private static function get_guest_author_for_distribution( $guest_author ): array|WP_Error { | ||
global $coauthors_plus; | ||
|
||
if ( ! is_object( $guest_author ) || ! isset( $guest_author->type ) || 'guest-author' !== $guest_author->type ) { | ||
return new WP_Error( 'Error getting guest author details for distribution. Invalid Guest Author' ); | ||
} | ||
|
||
$author = (array) $guest_author; | ||
$author['type'] = 'guest_author'; | ||
|
||
// Gets the guest author avatar. | ||
// We only want to send an actual uploaded avatar, we don't want to send the fallback avatar, like gravatar. | ||
// If no avatar was set, let it default to the fallback set in the target site. | ||
$author_avatar = $coauthors_plus->guest_authors->get_guest_author_thumbnail( $guest_author, 80 ); | ||
if ( $author_avatar ) { | ||
$author['avatar_img_tag'] = $author_avatar; | ||
} | ||
|
||
return $author; | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This docblock needs an update.