get_migration_url();
?>
'
. ''
. '';
}
/**
* URL of the Setup Wizard migration step, when migration is still possible.
*
* The wizard redirects to the dashboard once completed, so the link is
* only offered while the wizard is still accessible and at least one
* detected plugin has a ThinkRank importer.
*
* @return string Migration URL or '' when unavailable
*/
private function get_migration_url(): string {
if (!SEO_Plugin_Detector::has_importable_plugin()) {
return '';
}
if (get_option(Setup_Wizard::OPT_COMPLETED, false)) {
return '';
}
return admin_url('admin.php?page=' . Setup_Wizard::PAGE_SLUG);
}
/**
* Enqueue notice scripts
*
* @param string $hook Current admin page hook
* @return void
*/
public function enqueue_notice_scripts(string $hook): void {
if (!SEO_Plugin_Detector::should_show_notice()) {
return;
}
wp_enqueue_style(
'thinkrank-admin-notices',
THINKRANK_PLUGIN_URL . 'static/css/admin-notices.css',
[],
THINKRANK_VERSION
);
wp_add_inline_script('jquery', '
jQuery(document).ready(function($) {
function thinkrankDismissSeoNotice() {
$.post(ajaxurl, {
action: "thinkrank_dismiss_seo_notice",
nonce: "' . wp_create_nonce('thinkrank_seo_notice_nonce') . '"
}, function(response) {
if (response.success) {
$(".thinkrank-seo-notice").fadeOut();
}
});
}
$(".thinkrank-dismiss-seo-notice").on("click", function(e) {
e.preventDefault();
thinkrankDismissSeoNotice();
});
// Persist dismissal from the core notice X button too
// (delegated — core injects the button after DOM ready)
$(document).on("click", ".thinkrank-seo-notice .notice-dismiss", thinkrankDismissSeoNotice);
$(".thinkrank-deactivate-seo-plugin").on("click", function(e) {
e.preventDefault();
var $button = $(this);
$button.prop("disabled", true);
$.post(ajaxurl, {
action: "thinkrank_deactivate_seo_plugin",
plugin: $button.data("plugin"),
nonce: "' . wp_create_nonce('thinkrank_seo_notice_nonce') . '"
}, function(response) {
if (response.success) {
window.location.reload();
} else {
$button.prop("disabled", false);
}
});
});
});
');
}
/**
* AJAX handler to dismiss SEO notice
*
* @return void
*/
public function ajax_dismiss_notice(): void {
$nonce = sanitize_text_field(wp_unslash($_POST['nonce'] ?? ''));
if (!wp_verify_nonce($nonce, 'thinkrank_seo_notice_nonce')) {
wp_send_json_error('Security check failed');
}
// The notice is an admin-facing plugin-conflict warning — only users who
// can manage the plugin should be able to dismiss it.
if (!current_user_can('edit_posts')) {
wp_send_json_error('Insufficient permissions');
}
SEO_Plugin_Detector::dismiss_notice();
wp_send_json_success();
}
/**
* AJAX handler to deactivate a conflicting SEO plugin.
*
* Only accepts a known-plugin slug; the plugin file(s) — including
* premium companions — are resolved server-side by the detector.
*
* @return void
*/
public function ajax_deactivate_plugin(): void {
$nonce = sanitize_text_field(wp_unslash($_POST['nonce'] ?? ''));
if (!wp_verify_nonce($nonce, 'thinkrank_seo_notice_nonce')) {
wp_send_json_error('Security check failed');
}
if (!current_user_can('deactivate_plugins')) {
wp_send_json_error('Insufficient permissions');
}
$slug = sanitize_key(wp_unslash($_POST['plugin'] ?? ''));
$files = SEO_Plugin_Detector::get_deactivatable_files($slug);
if (empty($files)) {
wp_send_json_error('Unknown plugin');
}
deactivate_plugins($files);
wp_send_json_success();
}
}