320 changes: 229 additions & 91 deletions composer.lock

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions includes/admin/class-rop-admin.php
Expand Up @@ -355,11 +355,11 @@ public function enqueue_scripts() {
$array_nonce['rop_cron_remote_agreement'] = filter_var( get_option( 'rop_remote_cron_terms_agree', false ), FILTER_VALIDATE_BOOLEAN );

$admin_url = get_admin_url( get_current_blog_id(), 'admin.php?page=TweetOldPost' );
$token = get_option( 'ROP_INSTALL_TOKEN_OPTION' );
$token = get_option( ROP_INSTALL_TOKEN_OPTION );
$signature = md5( $admin_url . $token );

$rop_auth_app_data = array(
'adminEmail' => urlencode( base64_encode( get_option( 'admin_email' ) ) ),
'adminEmail' => rawurlencode( base64_encode( get_option( 'admin_email' ) ) ),
'authAppUrl' => ROP_AUTH_APP_URL,
'authAppFacebookPath' => ROP_APP_FACEBOOK_PATH,
'authAppTwitterPath' => ROP_APP_TWITTER_PATH,
Expand Down Expand Up @@ -1023,7 +1023,6 @@ public function rop_cron_job_publish_now( $post_id = '', $accounts_data = array(
} else {
$logger->info( 'Fetching publish now queue: ' . print_r( $queue_stack, true ) );
}

foreach ( $queue_stack as $account => $events ) {
foreach ( $events as $index => $event ) {
$post = $event['post'];
Expand Down
185 changes: 109 additions & 76 deletions includes/admin/services/class-rop-linkedin-service.php
Expand Up @@ -534,7 +534,7 @@ public function share( $post_details, $args = array() ) {

// LinkedIn link post
if ( ! empty( $post_url ) && empty( $share_as_image_post ) && get_post_type( $post_id ) !== 'attachment' ) {
$new_post = $this->linkedin_article_post( $post_details, $hashtags, $args );
$new_post = $this->linkedin_article_post( $post_details, $hashtags, $args, $token );
}

// LinkedIn plain text post
Expand All @@ -547,7 +547,7 @@ public function share( $post_details, $args = array() ) {

// Linkedin Api v2 doesn't support video upload. Share as article post
if ( strpos( get_post_mime_type( $post_details['post_id'] ), 'video' ) !== false ) {
$new_post = $this->linkedin_article_post( $post_details, $hashtags, $args );
$new_post = $this->linkedin_article_post( $post_details, $hashtags, $args, $token );
} else {
$new_post = $this->linkedin_image_post( $post_details, $hashtags, $args, $token );
}
Expand Down Expand Up @@ -618,7 +618,7 @@ public function share( $post_details, $args = array() ) {
* @since 8.2.3
* @access private
*/
private function linkedin_article_post( $post_details, $hashtags, $args ) {
private function linkedin_article_post( $post_details, $hashtags, $args, $token = '' ) {

$author_urn = $args['is_company'] ? 'urn:li:organization:' : 'urn:li:person:';

Expand All @@ -631,6 +631,10 @@ function ( $matches ) {
$commentary
);

// Assets upload to linkedin.
$img = $this->get_path_by_url( $post_details['post_image'], $post_details['mimetype'] );
$asset_data = $this->linkedin_upload_assets( $img, $args, $token );

$new_post = array(
'author' => $author_urn . $args['id'],
'lifecycleState' => 'PUBLISHED',
Expand All @@ -651,6 +655,10 @@ function ( $matches ) {
),
);

if ( ! empty( $asset_data['value']['image'] ) ) {
$new_post['content']['article']['thumbnail'] = $asset_data['value']['image'];
}

return $new_post;

}
Expand Down Expand Up @@ -729,81 +737,14 @@ private function linkedin_image_post( $post_details, $hashtags, $args, $token )
return $this->linkedin_article_post( $post_details, $hashtags, $args );
}

$author_urn = $args['is_company'] ? 'urn:li:organization:' : 'urn:li:person:';

$register_image = array(
'initializeUploadRequest' => array(
'owner' => $author_urn . $args['id'],
),
);

$api_url = 'https://api.linkedin.com/rest/images?action=initializeUpload';
$response = wp_remote_post(
$api_url,
array(
'body' => wp_json_encode( $register_image ),
'headers' => array(
'Content-Type' => 'application/json',
'x-li-format' => 'json',
'X-Restli-Protocol-Version' => '2.0.0',
'Authorization' => 'Bearer ' . $token,
'Linkedin-Version' => 202208,
),
)
);

if ( is_wp_error( $response ) ) {
$error_string = $response->get_error_message();
$this->logger->alert_error( Rop_I18n::get_labels( 'errors.wordpress_api_error' ) . $error_string );
return false;
}

$body = json_decode( wp_remote_retrieve_body( $response ), true );

if ( empty( $body['value']['uploadUrl'] ) ) {
$this->logger->alert_error( 'Cannot share to LinkedIn, empty upload url' );
return false;
}

$upload_url = $body['value']['uploadUrl'];
$asset = $body['value']['image'];

if ( function_exists( 'exif_imagetype' ) ) {
$img_mime_type = image_type_to_mime_type( exif_imagetype( $img ) );
} else {
$this->logger->alert_error( Rop_I18n::get_labels( 'errors.linkedin_missing_exif_imagetype' ) );
return false;
}
$img_data = file_get_contents( $img );
$img_length = strlen( $img_data );

$wp_img_put = wp_remote_request(
$upload_url,
array(
'method' => 'PUT',
'headers' => array(
'Authorization' => 'Bearer ' . $token,
'Content-type' => $img_mime_type,
'Content-Length' => $img_length,
),
'body' => $img_data,
)
);

if ( is_wp_error( $wp_img_put ) ) {
$error_string = $wp_img_put->get_error_message();
$this->logger->alert_error( Rop_I18n::get_labels( 'errors.wordpress_api_error' ) . $error_string );
return false;
}

$response_code = $wp_img_put['response']['code'];

if ( $response_code !== 201 ) {
$response_message = $wp_img_put['response']['message'];
$this->logger->alert_error( 'Cannot share to LinkedIn. Error: ' . $response_code . ' ' . $response_message );
return false;
// Assets upload to linkedin.
$asset_data = $this->linkedin_upload_assets( $img, $args, $token );
if ( empty( $asset_data['value']['image'] ) ) {
$this->logger->info( 'No image set for post, but "Share as Image Post" is checked. Falling back to article post' );
return $this->linkedin_article_post( $post_details, $hashtags, $args );
}

$asset = $asset_data['value']['image'];
$commentary = $this->strip_excess_blank_lines( $post_details['content'] ) . $this->get_url( $post_details ) . $hashtags;
$commentary = preg_replace_callback(
'/([\(\)\{\}\[\]])|([@*<>\\\\\_~])/m',
Expand Down Expand Up @@ -992,4 +933,96 @@ public function populate_additional_data( $account ) {
return $account;
}

/**
* Linkedin upload media assets.
*
* @param string $image_url Post image URL.
* @param array $args Arguments needed by the method.
* @param string $token The user token.
*
* @return string|bool
*/
private function linkedin_upload_assets( $image_url, $args, $token ) {
if ( empty( $image_url ) ) {
$this->logger->alert_error( 'Cannot upload image to LinkedIn, empty upload url' );
return false;
}
$author_urn = $args['is_company'] ? 'urn:li:organization:' : 'urn:li:person:';

$register_image = array(
'initializeUploadRequest' => array(
'owner' => $author_urn . $args['id'],
),
);

$api_url = 'https://api.linkedin.com/rest/images?action=initializeUpload';
$response = wp_remote_post(
$api_url,
array(
'body' => wp_json_encode( $register_image ),
'headers' => array(
'Content-Type' => 'application/json',
'x-li-format' => 'json',
'X-Restli-Protocol-Version' => '2.0.0',
'Authorization' => 'Bearer ' . $token,
'Linkedin-Version' => 202208,
),
)
);

if ( is_wp_error( $response ) ) {
$error_string = $response->get_error_message();
$this->logger->alert_error( Rop_I18n::get_labels( 'errors.wordpress_api_error' ) . $error_string );
return false;
}

$body = json_decode( wp_remote_retrieve_body( $response ), true );

if ( empty( $body['value']['uploadUrl'] ) ) {
$this->logger->alert_error( 'Cannot share to LinkedIn, empty upload url' );
return false;
}

$upload_url = $body['value']['uploadUrl'];
$asset = $body['value']['image'];

if ( function_exists( 'exif_imagetype' ) ) {
$img_mime_type = image_type_to_mime_type( exif_imagetype( $image_url ) );
} else {
$this->logger->alert_error( Rop_I18n::get_labels( 'errors.linkedin_missing_exif_imagetype' ) );
return false;
}
$img_data = file_get_contents( $image_url );
$img_length = strlen( $img_data );

$wp_img_put = wp_remote_request(
$upload_url,
array(
'method' => 'PUT',
'headers' => array(
'Authorization' => 'Bearer ' . $token,
'Content-type' => $img_mime_type,
'Content-Length' => $img_length,
),
'body' => $img_data,
)
);

if ( is_wp_error( $wp_img_put ) ) {
$error_string = $wp_img_put->get_error_message();
$this->logger->alert_error( Rop_I18n::get_labels( 'errors.wordpress_api_error' ) . $error_string );
return false;
}

$response_code = $wp_img_put['response']['code'];

if ( 201 !== $response_code ) {
$response_message = $wp_img_put['response']['message'];
$this->logger->alert_error( 'Cannot share to LinkedIn. Error: ' . $response_code . ' ' . $response_message );
return false;
}

return $body;
}

}
29 changes: 19 additions & 10 deletions includes/admin/services/class-rop-twitter-service.php
Expand Up @@ -39,7 +39,7 @@ class Rop_Twitter_Service extends Rop_Services_Abstract {
* @access private
* @var string $consumer_key The Twitter APP Consumer Key.
*/
private $consumer_key = 'ofaYongByVpa3NDEbXa2g';
private $consumer_key = 'OE9PNEEzMFZBTHNvOE02T3pOUmc6MTpjaQ';

/**
* Holds the Twitter APP Consumer Secret.
Expand All @@ -51,7 +51,7 @@ class Rop_Twitter_Service extends Rop_Services_Abstract {
* @access private
* @var string $consumer_secret The Twitter APP Consumer Secret.
*/
private $consumer_secret = 'vTzszlMujMZCY3mVtTE6WovUKQxqv3LVgiVku276M';
private $consumer_secret = 'P9zJ8jKGBM_tdIP_RzAUGkos6fwKPYr-ezVqwa8rXKOCI_ndbT';


/**
Expand Down Expand Up @@ -105,7 +105,12 @@ public function authorize() {

$api = $this->get_api( $request_token['oauth_token'], $request_token['oauth_token_secret'] );

$access_token = $api->oauth( 'oauth/access_token', array( 'oauth_verifier' => $_GET['oauth_verifier'] ) );
$access_token = $api->oauth(
'oauth/access_token',
array(
'oauth_verifier' => $_GET['oauth_verifier'],
)
);

$_SESSION['rop_twitter_oauth_token'] = $access_token;

Expand Down Expand Up @@ -413,7 +418,7 @@ public function request_api_token() {
*/
private function twitter_article_post( $post_details ) {

$new_post['status'] = $this->strip_excess_blank_lines( $post_details['content'] ) . $this->get_url( $post_details );
$new_post['text'] = $this->strip_excess_blank_lines( $post_details['content'] ) . $this->get_url( $post_details );

return $new_post;
}
Expand All @@ -430,7 +435,7 @@ private function twitter_article_post( $post_details ) {
*/
private function twitter_text_post( $post_details ) {

$new_post['status'] = $this->strip_excess_blank_lines( $post_details['content'] );
$new_post['text'] = $this->strip_excess_blank_lines( $post_details['content'] );

return $new_post;
}
Expand Down Expand Up @@ -508,6 +513,8 @@ private function twitter_media_post( $post_details, $api ) {
}

$this->logger->info( 'Before upload to twitter . ' . json_encode( $upload_args ) );
$api->setTimeouts( 10, 60 );
$api->setApiVersion( '1.1' );
$media_response = $api->upload( 'media/upload', $upload_args, true );

if ( isset( $media_response->media_id_string ) ) {
Expand All @@ -531,7 +538,7 @@ private function twitter_media_post( $post_details, $api ) {
} while ( $upload_status->processing_info->state !== 'succeeded' && $limit <= 10 );

if ( ! empty( $media_id ) ) {
$new_post['media_ids'] = $media_id;
$new_post['media']['media_ids'][] = (string) $media_id;
}
} else {
$this->logger->alert_error( sprintf( 'Can not upload media to twitter. Error: %s', json_encode( $media_response ) ) );
Expand All @@ -543,7 +550,7 @@ private function twitter_media_post( $post_details, $api ) {
wp_delete_file( $media_path );
}

$new_post['status'] = $this->strip_excess_blank_lines( $post_details['content'] ) . $this->get_url( $post_details );
$new_post['text'] = $this->strip_excess_blank_lines( $post_details['content'] ) . $this->get_url( $post_details );

return $new_post;
}
Expand Down Expand Up @@ -608,12 +615,14 @@ public function share( $post_details, $args = array() ) {
$hashtags = $this->shuffle_hashtags( $hashtags );
}

$new_post['status'] = $new_post['status'] . $hashtags;
$new_post['text'] = $new_post['text'] . $hashtags;

$this->logger->info( sprintf( 'Before twitter share: %s', json_encode( $new_post ) ) );

$response = $api->post( 'statuses/update', $new_post );
if ( isset( $response->id ) ) {
$api->setApiVersion( '2' );
$response = $api->post( 'tweets', $new_post, true );

if ( isset( $response->data->id ) ) {
$this->logger->alert_success(
sprintf(
'Successfully shared %s to %s on %s ',
Expand Down
2 changes: 1 addition & 1 deletion includes/class-rop.php
Expand Up @@ -68,7 +68,7 @@ class Rop {
public function __construct() {

$this->plugin_name = 'rop';
$this->version = '9.0.14';
$this->version = '9.0.15';

$this->load_dependencies();
$this->set_locale();
Expand Down
2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "tweet-old-post",
"version": "9.0.14",
"version": "9.0.15",
"description": "Tweet Old Posts plugin",
"repository": {
"type": "git",
Expand Down
8 changes: 8 additions & 0 deletions readme.txt
Expand Up @@ -301,6 +301,14 @@ http://revive.social/plugins/revive-old-post

== Changelog ==

##### [Version 9.0.15](https://github.com/Codeinwp/tweet-old-post/compare/v9.0.14...v9.0.15) (2023-07-28)

- Fixed post-sharing issue with post image
- Added Twitter v2 API support




##### [Version 9.0.14](https://github.com/Codeinwp/tweet-old-post/compare/v9.0.13...v9.0.14) (2023-06-06)

- Added LinkedIn new API support
Expand Down
4 changes: 2 additions & 2 deletions tweet-old-post.php
Expand Up @@ -16,7 +16,7 @@
* Plugin Name: Revive Old Posts
* Plugin URI: https://revive.social/
* Description: WordPress plugin that helps you to keeps your old posts alive by sharing them and driving more traffic to them from twitter/facebook or linkedin. It also helps you to promote your content. You can set time and no of posts to share to drive more traffic.For questions, comments, or feature requests, <a href="http://revive.social/support/?utm_source=plugindesc&utm_medium=announce&utm_campaign=top">contact </a> us!
* Version: 9.0.14
* Version: 9.0.15
* Author: revive.social
* Author URI: https://revive.social/
* Requires at least: 4.7
Expand Down Expand Up @@ -162,7 +162,7 @@ function run_rop() {
define( 'ROP_CRON_ALTERNATIVE', $use_remote_cron );

define( 'ROP_PRO_URL', 'http://revive.social/plugins/revive-old-post/' );
define( 'ROP_LITE_VERSION', '9.0.14' );
define( 'ROP_LITE_VERSION', '9.0.15' );
define( 'ROP_LITE_BASE_FILE', __FILE__ );
$debug = false;
if ( function_exists( 'wp_get_environment_type' ) ) {
Expand Down