-
-
Save igorhrcek/b90e3749ec6dd83781ca10ecb80b86f3 to your computer and use it in GitHub Desktop.
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
<?php | |
namespace App\Libraries\Commands; | |
abstract class AbstractCommand implements CommandInterface | |
{ | |
/** | |
* @return array | |
*/ | |
public function getSynopsis(): array | |
{ | |
return []; | |
} | |
/** | |
* @return string | |
*/ | |
final public function getName(): string | |
{ | |
return sprintf('benchmark %s', $this->getCommandName()); | |
} | |
/** | |
* Get the full command name | |
* | |
* @return string | |
*/ | |
abstract protected function getCommandName(): string; | |
} |
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
<?php | |
namespace App\Libraries\Commands; | |
interface CommandInterface | |
{ | |
/** | |
* Get command name | |
* | |
* @return string | |
*/ | |
public function getName(): string; | |
/** | |
* Executes the command | |
* | |
* @param $arguments | |
* @param $options | |
* | |
*/ | |
public function __invoke($arguments, $options); | |
/** | |
* Get the positional and associative arguments a command accepts. | |
* | |
* @return array | |
*/ | |
public function getSynopsis(): array; | |
/** | |
* Get the command description. | |
* | |
* @return string | |
*/ | |
public function getDescription(): string; | |
} |
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
<?php | |
namespace App\Libraries\Commands; | |
use App\Libraries\Commands\Libraries\CommentsSync; | |
class CommentsCommand extends AbstractCommand { | |
public function __invoke($arguments, $options) | |
{ | |
$sync = (new CommentsSync($options))->sync(); | |
} | |
/** | |
* Define a WP CLI command name | |
* | |
* @return strirng | |
*/ | |
protected function getCommandName() : string | |
{ | |
return "comments-sync"; | |
} | |
/** | |
* Returns a brief description of the WP CLI command | |
* | |
* @return string | |
*/ | |
public function getDescription() : string | |
{ | |
return "Fetch and store thread comments as WordPress comments in articles with connected XenForo Threads."; | |
} | |
/** | |
* Provides definition of the additional command arguments | |
* | |
* @return array | |
*/ | |
public function getSynopsis(): array | |
{ | |
return [ | |
[ | |
'type' => 'assoc', | |
'name' => 'published-since', | |
'description' => 'Defines a time frame in which published articled will be taken into account (now minus passed number). Defaults to `close_comments_days_old`.', | |
'optional' => true | |
], | |
[ | |
'type' => 'assoc', | |
'name' => 'post_type', | |
'description' => 'Defines for which post type a comments will be syncronized. Defaults to `post`.', | |
'optional' => true, | |
'default' => 'post' | |
], | |
]; | |
} | |
} |
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
<?php | |
namespace App\Libraries\Commands\Libraries; | |
class CommentsSync { | |
/** | |
* Passed command options | |
* | |
* @var array | |
*/ | |
public array $options; | |
/** | |
* WordPress `close_comments_days_old` option value | |
* | |
* @var integer | |
*/ | |
public int $optionCloseCommentsOld; | |
/** | |
* XFWP_Requests class instance | |
* | |
* @var \XFWP_Requests | |
*/ | |
private \XFWP_Requests $xf; | |
/** | |
* Defines a WordPress post type that will be used for comments sync | |
* | |
* @var string | |
*/ | |
private string $postType; | |
/** | |
* Post meta keys which is used for storing XFWP data | |
* | |
* @var string | |
*/ | |
private string $xfwpMetaKey = 'xfwp'; | |
/** | |
* Default sleep time between XF API calls | |
* | |
* @var integer | |
*/ | |
private int $sleep = 1; | |
public function __construct(array $options) | |
{ | |
$this->options = $options; | |
$this->postType = $options['post_type']; | |
$this->sleep = (isset($options['sleep'])) ? (int)$options['sleep'] : $this->sleep; | |
$this->optionCloseCommentsOld = (isset($options['published-since'])) ? (int)$options['published-since'] : get_option('close_comments_days_old'); | |
$this->xf = new \XFWP_Requests(); | |
} | |
/** | |
* Girl for everyone and everything | |
* | |
* @return void | |
*/ | |
public function sync() : void | |
{ | |
$postIds = $this->getPostIdsByConnectedThreads(); | |
$threadsIds = $this->getThreadIds($postIds); | |
foreach($threadsIds as $threadId) { | |
$response = $this->xf->thread_posts($threadId['threadId']); | |
if($response) { | |
\WP_CLI::log("Processing thread " . $threadId['threadId'] . ", post " . $threadId['postId']); | |
$this->processThreadPosts($response, $threadId); | |
} | |
\WP_CLI::log("Sleeping for " . $this->sleep . " second(s)..."); | |
sleep($this->sleep); | |
} | |
\WP_CLI::success("All comments have been synced."); | |
} | |
/** | |
* Returns a list of Connected Threads Ids | |
* | |
* With WP_Query we fetch posts within $optionCloseCommentsOld days that have `xfwp` meta_value and then extract thread_ids from it. | |
* | |
* @return array | |
*/ | |
private function getPostIdsByConnectedThreads() : array | |
{ | |
$args = [ | |
'post_type' => $this->postType, | |
'post_status' => 'publish', | |
'fields' => 'ids', | |
'posts_per_page' => -1, | |
'date_query' => [ | |
[ | |
'after' => $this->optionCloseCommentsOld . ' days ago' | |
] | |
], | |
'meta_query' => [ | |
[ | |
'key' => $this->xfwpMetaKey, | |
'compare' => 'EXISTS' | |
] | |
] | |
]; | |
$posts = new \WP_Query($args); | |
return $posts->posts; | |
} | |
/** | |
* Returns an array of threadIds for posts | |
* | |
* @param array $postIds | |
* | |
* @return array | |
*/ | |
private function getThreadIds(array $postIds) : array | |
{ | |
$threadIds = []; | |
foreach($postIds as $postId) { | |
$metas = \get_post_meta($postId, $this->xfwpMetaKey, FALSE); | |
foreach($metas as $meta) { | |
if(isset($meta['comments']["thread_id"]) && (int)$meta['comments']["thread_id"] > 0) { | |
array_push($threadIds, [ | |
"postId" => $postId, | |
"threadId" => (int)$meta['comments']["thread_id"] | |
]); | |
} | |
} | |
} | |
return $threadIds; | |
} | |
private function processThreadPosts(array $threadPosts, array $entity) : void | |
{ | |
//Uhvati komentare za post | |
$args = [ | |
'post_id' => $entity["postId"], | |
'count' => true | |
]; | |
if(!isset($threadPosts["posts"]) || count($threadPosts["posts"]) == 0) { | |
return; | |
} | |
//If WordPress post has 0 comments, add them all | |
if(get_comments($args) == 0) { | |
\WP_CLI::log("Article has no comments, storing all comments."); | |
foreach($threadPosts["posts"] as $threadPost) { | |
$this->storePostComment($threadPost, $entity); | |
} | |
} else { | |
//This post already has comments in it so we need to inspect each one | |
//to make sure that we do not override those that are trashed by WordPress admins | |
global $wpdb; | |
$query = "SELECT comment_ID FROM {$wpdb->prefix}commentmeta WHERE meta_key = %s AND meta_value = %d"; | |
foreach($threadPosts["posts"] as $threadPost) { | |
$commentMeta = $wpdb->get_row($wpdb->prepare($query, 'thread_post_id', (int)$threadPost['post_id'])); | |
//We do not have a comment that corresponds to the thread post id | |
if(!isset($commentMeta->comment_ID)) { | |
\WP_CLI::log("Storing new thread posts as comments..."); | |
$this->storePostComment($threadPost, $entity); | |
} else { | |
$comment = get_comment($commentMeta->comment_ID); | |
//If comment is approved, update it | |
if($comment->comment_approved !== "trash") { | |
\WP_CLI::log("Updating existing comment..."); | |
$this->updatePostComment((int)$commentMeta->comment_ID, $threadPost, $entity); | |
} | |
} | |
} | |
} | |
} | |
/** | |
* Stores XF Thread post as a comment | |
* | |
* @param array $threadPost | |
* @param array $entity | |
* | |
* @return boolean | |
*/ | |
private function storePostComment(array $threadPost, array $entity) : bool | |
{ | |
$postDate = $threadPost['post_date']; | |
$dt = new \DateTime("@$postDate"); | |
$args = [ | |
'comment_post_ID' => $entity['postId'], | |
'comment_content' => $threadPost['message'], | |
'comment_author' => $threadPost['user']['username'], | |
'comment_date' => $dt->format("Y-m-d H:i:s"), | |
'comment_karma' => $threadPost['reaction_score'], | |
'comment_approved' => 1, | |
'comment_meta' => [ | |
'thread_post_id' => $threadPost['post_id'], | |
'author_reaction_score' => $threadPost['user']['reaction_score'], | |
] | |
]; | |
$comment = wp_insert_comment($args); | |
return $comment > 0; | |
} | |
/** | |
* Updated information of an existing comment in WordPress database | |
* | |
* @param integer $commentId | |
* @param array $threadPost | |
* @param array $entity | |
* | |
* @return boolean | |
*/ | |
private function updatePostComment(int $commentId, array $threadPost, array $entity) : bool | |
{ | |
$args = [ | |
'comment_ID' => $commentId, | |
'comment_content' => $threadPost['message'], | |
'comment_karma' => $threadPost['reaction_score'] | |
]; | |
return wp_update_comment($args); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment