Plugin Already Installed
You have already installed this plugin. It might have a different name but it has the same functionality - it might be called something like "SEO One-Click Publishing".
If you would like to replace the existing plugin with this version, please remove the old one first. Keep in mind you might have to set up the integration again.
Go to Plugins Page
Settings saved.
';
}
if (isset($_POST['create_application_password'])) {
create_application_password_for_user();
echo 'Application password created.
';
}
if (isset($_POST['delete_application_password'])) {
delete_application_password_for_user();
echo 'Application password deleted.
';
}
$enable_meta_sync = get_option('adaptify_seo_enable_meta_sync', '1');
?>
SEO Settings
Application Password Management
The application password is used to securely connect your WordPress site with SEO tools. This password should be treated with the same level of security as any other password.
get_param('yoast_meta');
if (is_array($yoast_meta)) {
if (isset($yoast_meta['yoast_wpseo_metadesc'])) {
update_post_meta($post->ID, 'rank_math_description', $yoast_meta['yoast_wpseo_metadesc']);
}
if (isset($yoast_meta['yoast_wpseo_metakeywords'])) {
update_post_meta($post->ID, 'rank_math_focus_keyword', $yoast_meta['yoast_wpseo_metakeywords']);
}
if (isset($yoast_meta['yoast_wpseo_title'])) {
update_post_meta($post->ID, 'rank_math_title', $yoast_meta['yoast_wpseo_title']);
}
}
}
}, 10, 3);
if (!class_exists('Yoast_To_REST_API')) {
class Yoast_To_REST_API {
protected $keys = array(
'yoast_wpseo_focuskw',
'yoast_wpseo_title',
'yoast_wpseo_metadesc',
'yoast_wpseo_linkdex',
'yoast_wpseo_metakeywords',
'yoast_wpseo_meta-robots-noindex',
'yoast_wpseo_meta-robots-nofollow',
'yoast_wpseo_meta-robots-adv',
'yoast_wpseo_canonical',
'yoast_wpseo_redirect',
'yoast_wpseo_opengraph-title',
'yoast_wpseo_opengraph-description',
'yoast_wpseo_opengraph-image',
'yoast_wpseo_twitter-title',
'yoast_wpseo_twitter-description',
'yoast_wpseo_twitter-image'
);
function __construct() {
add_action( 'rest_api_init', array( $this, 'add_yoast_data' ) );
}
function add_yoast_data() {
// Posts
register_rest_field( 'post',
'yoast_meta',
array(
'get_callback' => array( $this, 'wp_api_encode_yoast' ),
'update_callback' => array( $this, 'wp_api_update_yoast' ),
'schema' => null,
)
);
// Pages
register_rest_field( 'page',
'yoast_meta',
array(
'get_callback' => array( $this, 'wp_api_encode_yoast' ),
'update_callback' => array( $this, 'wp_api_update_yoast' ),
'schema' => null,
)
);
// Category
register_rest_field( 'category',
'yoast_meta',
array(
'get_callback' => array( $this, 'wp_api_encode_yoast_category' ),
'update_callback' => null,
'schema' => null,
)
);
// Tag
register_rest_field( 'tag',
'yoast_meta',
array(
'get_callback' => array( $this, 'wp_api_encode_yoast_tag' ),
'update_callback' => null,
'schema' => null,
)
);
// Public custom post types
$types = get_post_types( array(
'public' => true,
'_builtin' => false
) );
foreach ( $types as $key => $type ) {
register_rest_field( $type,
'yoast_meta',
array(
'get_callback' => array( $this, 'wp_api_encode_yoast' ),
'update_callback' => array( $this, 'wp_api_update_yoast' ),
'schema' => null,
)
);
}
}
/**
* Updates post meta with values from post/put request.
*
* @param array $value
* @param object $data
* @param string $field_name
*
* @return array
*/
function wp_api_update_yoast( $value, $data, $field_name ) {
foreach ( $value as $k => $v ) {
if ( in_array( $k, $this->keys ) ) {
! empty( $k ) ? update_post_meta( $data->ID, '_' . $k, $v ) : null;
}
}
return $this->wp_api_encode_yoast( $data->ID, null, null );
}
function wp_api_encode_yoast( $p, $field_name, $request ) {
$wpseo_frontend = WPSEO_Frontend_To_REST_API::get_instance();
$wpseo_frontend->reset();
query_posts( array(
'p' => $p['id'], // ID of a page, post, or custom type
'post_type' => 'any'
) );
the_post();
$yoast_meta = array(
'yoast_wpseo_title' => $wpseo_frontend->get_content_title(),
'yoast_wpseo_metadesc' => $wpseo_frontend->metadesc( false ),
'yoast_wpseo_canonical' => $wpseo_frontend->canonical( false ),
);
/**
* Filter the returned yoast meta.
*
* @since 1.4.2
* @param array $yoast_meta Array of metadata to return from Yoast.
* @param \WP_Post $p The current post object.
* @param \WP_REST_Request $request The REST request.
* @return array $yoast_meta Filtered meta array.
*/
$yoast_meta = apply_filters( 'wpseo_to_api_yoast_meta', $yoast_meta, $p, $request );
wp_reset_query();
return (array) $yoast_meta;
}
private function wp_api_encode_taxonomy() {
$wpseo_frontend = WPSEO_Frontend_To_REST_API::get_instance();
$wpseo_frontend->reset();
$yoast_meta = array(
'yoast_wpseo_title' => $wpseo_frontend->get_taxonomy_title(),
'yoast_wpseo_metadesc' => $wpseo_frontend->metadesc( false ),
);
/**
* Filter the returned yoast meta for a taxonomy.
*
* @since 1.4.2
* @param array $yoast_meta Array of metadata to return from Yoast.
* @return array $yoast_meta Filtered meta array.
*/
$yoast_meta = apply_filters( 'wpseo_to_api_yoast_taxonomy_meta', $yoast_meta );
return (array) $yoast_meta;
}
function wp_api_encode_yoast_category( $category ) {
query_posts( array(
'cat' => $category['id'],
) );
the_post();
$res = $this->wp_api_encode_taxonomy();
wp_reset_query();
return $res;
}
function wp_api_encode_yoast_tag( $tag ) {
query_posts( array(
'tag_id' => $tag['id'],
) );
the_post();
$res = $this->wp_api_encode_taxonomy();
wp_reset_query();
return $res;
}
}
}
if (!function_exists('WPAPIYoast_init')) {
function WPAPIYoast_init() {
if ( class_exists( 'WPSEO_Frontend' ) ) {
include __DIR__ . '/classes/class-wpseo-frontend-to-rest-api.php';
$yoast_To_REST_API = new Yoast_To_REST_API();
}
}
}
if (!function_exists('create_application_password_for_user')) {
function create_application_password_for_user() {
global $plugin_error_message;
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$user_id = get_current_user_id();
$custom_date = date('YmdHis');
$app_name = 'adaptify' . $custom_date;
$user = get_userdata($user_id);
if (!$user) {
$plugin_error_message = "Can't access your username, please contact support.";
add_action( 'admin_notices', 'application_password_fail' );
return;
}
$new_password = WP_Application_Passwords::create_new_application_password( $user_id, array( 'name' => $app_name ) );
if ( is_wp_error( $new_password ) ) {
$plugin_error_message = "Error creating application password.";
add_action( 'admin_notices', 'application_password_fail' );
return;
}
$post_data = array(
'user_name' => $user->user_login,
'application_pw' => $new_password[0],
'site_url' => get_site_url()
);
$response = wp_remote_post( 'https://api.ttsp4712.ai/add-wp-pw', array(
'method' => 'POST',
'headers' => array('Content-Type' => 'application/json; charset=utf-8'),
'body' => json_encode($post_data),
'data_format' => 'body'
));
if ( is_wp_error( $response ) ) {
$plugin_error_message = "Error in sending POST request: " . $response->get_error_message();
add_action( 'admin_notices', 'application_password_fail' );
}
}
}
if (!function_exists('delete_application_password_for_user')) {
function delete_application_password_for_user() {
global $plugin_error_message;
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$user_id = get_current_user_id();
$user = get_userdata($user_id);
if (!$user) {
$plugin_error_message = "Can't access your username, please contact support.";
add_action( 'admin_notices', 'application_password_fail' );
return;
}
$app_passwords = WP_Application_Passwords::get_user_application_passwords( $user_id );
if ( !empty($app_passwords) ) {
foreach ( $app_passwords as $app_password ) {
WP_Application_Passwords::delete_application_password( $user_id, $app_password['uuid'] );
}
} else {
$plugin_error_message = "No application passwords found to delete.";
add_action( 'admin_notices', 'application_password_fail' );
}
}
}
if (!function_exists('application_password_fail')) {
function application_password_fail() {
global $plugin_error_message;
printf(
'',
esc_html( $plugin_error_message )
);
}
}
// ============================================
// WP-CRON FALLBACK PUBLISHING (429 Recovery)
// ============================================
// Add custom cron interval (15 minutes)
add_filter('cron_schedules', function($schedules) {
$schedules['fifteen_minutes'] = array(
'interval' => 900,
'display' => __('Every 15 Minutes')
);
return $schedules;
});
// Ensure cron is always scheduled (self-heals if cron was cleared by DB issues, migrations, etc.)
// This is the recommended pattern per WordPress Plugin Handbook
if (!function_exists('adaptify_schedule_fallback_cron')) {
function adaptify_schedule_fallback_cron() {
if (!wp_next_scheduled('adaptify_fallback_publish_hook')) {
wp_schedule_event(time(), 'fifteen_minutes', 'adaptify_fallback_publish_hook');
error_log('[adaptify-fallback] Scheduled fallback cron job');
}
}
}
add_action('init', 'adaptify_schedule_fallback_cron');
// Unschedule fallback cron on plugin deactivation
if (!function_exists('adaptify_unschedule_fallback_cron')) {
function adaptify_unschedule_fallback_cron() {
$timestamp = wp_next_scheduled('adaptify_fallback_publish_hook');
if ($timestamp) {
wp_unschedule_event($timestamp, 'adaptify_fallback_publish_hook');
error_log('[adaptify-fallback] Unscheduled fallback cron job');
}
}
}
register_deactivation_hook(__FILE__, 'adaptify_unschedule_fallback_cron');
// Hook the fallback processing function
add_action('adaptify_fallback_publish_hook', 'adaptify_process_fallback_articles');
// Main function to process fallback articles
if (!function_exists('adaptify_process_fallback_articles')) {
function adaptify_process_fallback_articles() {
error_log('[adaptify-fallback] Starting fallback article check');
$site_url = get_site_url();
// Fetch pending articles from Adaptify API
$response = wp_remote_post('https://api.ttsp4712.ai/open/wp-pending-articles', array(
'method' => 'POST',
'headers' => array('Content-Type' => 'application/json'),
'body' => json_encode(array('site_url' => $site_url)),
'timeout' => 30
));
if (is_wp_error($response)) {
error_log('[adaptify-fallback] Error fetching pending articles: ' . $response->get_error_message());
return;
}
$body = json_decode(wp_remote_retrieve_body($response), true);
if (empty($body['articles']) || !is_array($body['articles'])) {
error_log('[adaptify-fallback] No pending articles found');
return;
}
error_log('[adaptify-fallback] Found ' . count($body['articles']) . ' pending articles');
foreach ($body['articles'] as $article) {
adaptify_publish_article_locally($article, $site_url);
}
}
}
// Publish a single article locally using wp_insert_post
if (!function_exists('adaptify_publish_article_locally')) {
function adaptify_publish_article_locally($article, $site_url) {
error_log('[adaptify-fallback] Publishing: ' . $article['title']);
// Prepare post data
$post_data = array(
'post_title' => sanitize_text_field($article['title']),
'post_content' => wp_kses_post($article['content']),
'post_status' => isset($article['status']) ? $article['status'] : 'publish',
'post_type' => 'post',
'comment_status'=> isset($article['comment_status']) ? $article['comment_status'] : 'closed',
'ping_status' => 'closed'
);
// Set excerpt if provided
if (!empty($article['excerpt'])) {
$post_data['post_excerpt'] = sanitize_text_field($article['excerpt']);
}
// Set category if provided
if (!empty($article['category_id'])) {
$post_data['post_category'] = array(intval($article['category_id']));
}
// Set author if provided
if (!empty($article['author_id'])) {
$post_data['post_author'] = intval($article['author_id']);
}
// Set slug if provided
if (!empty($article['slug'])) {
$post_data['post_name'] = sanitize_title($article['slug']);
}
// Set tags if provided
if (!empty($article['tag_ids']) && is_array($article['tag_ids'])) {
$post_data['tags_input'] = array_map('intval', $article['tag_ids']);
}
// Insert the post
$post_id = wp_insert_post($post_data, true);
if (is_wp_error($post_id)) {
error_log('[adaptify-fallback] Failed to create post: ' . $post_id->get_error_message());
adaptify_send_callback($article, $site_url, 'failed', 0, '', $post_id->get_error_message());
return;
}
error_log('[adaptify-fallback] Created post ID: ' . $post_id);
// Handle featured image if provided
if (!empty($article['featured_image_url'])) {
require_once(ABSPATH . 'wp-admin/includes/media.php');
require_once(ABSPATH . 'wp-admin/includes/file.php');
require_once(ABSPATH . 'wp-admin/includes/image.php');
$image_alt = !empty($article['featured_image_alt']) ? sanitize_text_field($article['featured_image_alt']) : sanitize_text_field($article['title']);
$image_id = media_sideload_image($article['featured_image_url'], $post_id, $article['title'], 'id');
if (!is_wp_error($image_id)) {
set_post_thumbnail($post_id, $image_id);
// Set alt text on the attachment
update_post_meta($image_id, '_wp_attachment_image_alt', $image_alt);
error_log('[adaptify-fallback] Set featured image: ' . $image_id);
} else {
error_log('[adaptify-fallback] Failed to set featured image: ' . $image_id->get_error_message());
}
}
// Set SEO meta fields for all major SEO plugins
$meta_description = !empty($article['meta_description']) ? sanitize_text_field($article['meta_description']) : '';
$focus_keyword = !empty($article['focus_keyword']) ? sanitize_text_field($article['focus_keyword']) : '';
$meta_title = !empty($article['meta_title']) ? sanitize_text_field($article['meta_title']) : sanitize_text_field($article['title']);
$secondary_keywords = !empty($article['secondary_keywords']) && is_array($article['secondary_keywords'])
? implode(',', array_map('sanitize_text_field', $article['secondary_keywords']))
: $focus_keyword;
$og_article_section = !empty($article['og_article_section']) ? sanitize_text_field($article['og_article_section']) : '';
$og_article_tags = !empty($article['og_article_tags']) ? sanitize_text_field($article['og_article_tags']) : $focus_keyword;
$og_image = !empty($article['og_image']) ? esc_url_raw($article['og_image']) : '';
$twitter_image = !empty($article['twitter_image']) ? esc_url_raw($article['twitter_image']) : '';
// Yoast SEO meta
if ($meta_description) {
update_post_meta($post_id, '_yoast_wpseo_metadesc', $meta_description);
}
if ($focus_keyword) {
update_post_meta($post_id, '_yoast_wpseo_focuskw', $focus_keyword);
}
if ($meta_title) {
update_post_meta($post_id, '_yoast_wpseo_title', $meta_title);
}
if ($secondary_keywords) {
update_post_meta($post_id, '_yoast_wpseo_metakeywords', $secondary_keywords);
}
// RankMath SEO meta
if ($meta_description) {
update_post_meta($post_id, 'rank_math_description', $meta_description);
}
if ($focus_keyword) {
update_post_meta($post_id, 'rank_math_focus_keyword', $focus_keyword);
}
if ($meta_title) {
update_post_meta($post_id, 'rank_math_title', $meta_title);
}
// AIOSEO meta
if ($meta_title) {
update_post_meta($post_id, '_aioseo_title', $meta_title);
update_post_meta($post_id, '_aioseo_og_title', $meta_title);
update_post_meta($post_id, '_aioseo_twitter_title', $meta_title);
}
if ($meta_description) {
update_post_meta($post_id, '_aioseo_description', $meta_description);
update_post_meta($post_id, '_aioseo_og_description', $meta_description);
update_post_meta($post_id, '_aioseo_twitter_description', $meta_description);
}
if ($og_article_section) {
update_post_meta($post_id, '_aioseo_og_article_section', $og_article_section);
}
if ($og_article_tags) {
update_post_meta($post_id, '_aioseo_og_article_tags', $og_article_tags);
}
if ($og_image) {
update_post_meta($post_id, '_aioseo_og_image', $og_image);
}
if ($twitter_image) {
update_post_meta($post_id, '_aioseo_twitter_image', $twitter_image);
}
// SEOPress meta
if ($meta_title) {
update_post_meta($post_id, '_seopress_titles_title', $meta_title);
update_post_meta($post_id, '_seopress_social_fb_title', $meta_title);
update_post_meta($post_id, '_seopress_social_twitter_title', $meta_title);
}
if ($meta_description) {
update_post_meta($post_id, '_seopress_titles_desc', $meta_description);
update_post_meta($post_id, '_seopress_social_fb_desc', $meta_description);
update_post_meta($post_id, '_seopress_social_twitter_desc', $meta_description);
}
if ($focus_keyword) {
update_post_meta($post_id, '_seopress_analysis_target_kw', $focus_keyword);
}
if ($og_image) {
update_post_meta($post_id, '_seopress_social_fb_img', $og_image);
}
if ($twitter_image) {
update_post_meta($post_id, '_seopress_social_twitter_img', $twitter_image);
}
// Custom author name meta (used by some themes)
if (!empty($article['custom_author_name'])) {
update_post_meta($post_id, 'custom_author_name', sanitize_text_field($article['custom_author_name']));
}
// Schema markup (JSON-LD) - store for RankMath/AIOSEO
if (!empty($article['schema_markup'])) {
// RankMath stores schema as serialized array
update_post_meta($post_id, 'rank_math_schema_Article', $article['schema_markup']);
// Also store as raw JSON for themes that use it
update_post_meta($post_id, '_schema_json_ld', $article['schema_markup']);
}
// Get the post URL
$post_url = get_permalink($post_id);
// Send success callback
adaptify_send_callback($article, $site_url, 'success', $post_id, $post_url, '');
error_log('[adaptify-fallback] Successfully published: ' . $post_url);
}
}
// Send callback to Adaptify API
if (!function_exists('adaptify_send_callback')) {
function adaptify_send_callback($article, $site_url, $status, $post_id, $post_url, $error_message) {
$callback_data = array(
'site_url' => $site_url,
'article_id' => $article['article_id'],
'keyword_id' => $article['keyword_id'],
'post_id' => $post_id,
'post_url' => $post_url,
'status' => $status,
'error_message' => $error_message
);
$response = wp_remote_post('https://api.ttsp4712.ai/open/wp-publish-callback', array(
'method' => 'POST',
'headers' => array('Content-Type' => 'application/json'),
'body' => json_encode($callback_data),
'timeout' => 15
));
if (is_wp_error($response)) {
error_log('[adaptify-fallback] Callback failed: ' . $response->get_error_message());
} else {
error_log('[adaptify-fallback] Callback sent successfully');
}
}
}
?>