Conflict with a Custom Plugin
-
Hello Team,
Currently I am facing the following problem due to a possible conflict between Rank Math SEO plugin and a custom Keyword Linker plugin.
The custom plugin is working fine, but now when I try to save any post, I get the following warning message:
Could not update the meta value of _genesis_hide_title in database
Upon deactivating plugins individually, I found that when Rank Math plugin is deactivated, the problem goes away.
I also tried installing other popular SEO plugins, and could not see this issue happening.
So I am curious to know what is causing this conflict only with Rank Math plugin?
Below given is my full php code of custom plugin for your kind reference:
<?php
/*
Plugin Name: Random Keyword Auto Linker
Description: Links up to five manually entered keywords across all posts in a selected category, in batches of 20. Links only unlinked keyword instances, randomly picks unique related posts to link. Avoids linking the same keyword more than once per post or repeating target links. Skips posts already linked. Tracks last used category, offset, and last entered keywords.
Version: 1.6.0
Author: Captain
*/
if (!defined('ABSPATH')) exit;
class Random_Keyword_Auto_Linker {
private $max_links_per_post = 5;
private $batch_size = 20;
private $option_state = 'rk_auto_linker_last_state';
private $option_keywords = 'rk_auto_linker_last_keywords';
public function __construct() {
add_action('admin_menu', [$this, 'add_admin_menu']);
add_action('admin_post_run_random_keyword_linking', [$this, 'process_keyword_linking']);
}
public function add_admin_menu() {
add_menu_page('Keyword Linker', 'Keyword Linker', 'manage_options', 'random-keyword-linker', [$this, 'admin_page']);
}
public function admin_page() {
if (!current_user_can('manage_options')) wp_die('Unauthorized user');
$categories = get_categories(['hide_empty' => false]);
$last_state = get_option($this->option_state, ['category_id' => '', 'offset' => '']);
$last_keywords = get_option($this->option_keywords, [
'keyword1' => '', 'keyword2' => '', 'keyword3' => '', 'keyword4' => '', 'keyword5' => ''
]);
echo '<div class="wrap"><h1>Random Keyword Auto Linker</h1>';
echo '<form method="post" action="' . admin_url('admin-post.php') . '">';
wp_nonce_field('run_random_keyword_linking', 'random_keyword_nonce');
echo '<input type="hidden" name="action" value="run_random_keyword_linking">';
// 5 keyword fields
for ($i = 1; $i <= 5; $i++) {
echo '<p><strong>Enter Keyword ' . $i . ':</strong> <input type="text" name="keyword' . $i . '" value="' . esc_attr($last_keywords['keyword' . $i]) . '"></p>';
}
echo '<p><strong>Select Category:</strong> <select name="category_id">';
foreach ($categories as $cat) {
$selected = $cat->term_id == $last_state['category_id'] ? ' selected' : '';
echo '<option value="' . $cat->term_id . '"' . $selected . '>' . esc_html($cat->name) . '</option>';
}
echo '</select></p>';
echo '<p><strong>Offset (use 0 for first batch, then 20, 40, etc.):</strong>
<input type="number" name="offset" value="' . esc_attr($last_state['offset']) . '" step="20"></p>';
submit_button('Run Linking for This Batch');
echo '</form>';
echo '<h3>Last Scan Info</h3>';
if ($last_state['category_id']) {
$cat_name = get_cat_name($last_state['category_id']);
echo '<p><strong>Category:</strong> ' . esc_html($cat_name) . '</p>';
echo '<p><strong>Last Offset Used:</strong> ' . intval($last_state['offset']) . '</p>';
} else {
echo '<p>No previous scan data found.</p>';
}
echo '</div>';
}
public function process_keyword_linking() {
if (!current_user_can('manage_options')) wp_die('Unauthorized user');
if (!isset($_POST['random_keyword_nonce']) || !wp_verify_nonce($_POST['random_keyword_nonce'], 'run_random_keyword_linking')) wp_die('Nonce check failed');
// Collect up to 5 keywords
$keywords = [];
$keywords_option = [];
for ($i = 1; $i <= 5; $i++) {
$kw = sanitize_text_field($_POST['keyword' . $i] ?? '');
$keywords_option['keyword' . $i] = $kw;
if (!empty($kw)) $keywords[] = $kw;
}
$category_id = (int)($_POST['category_id'] ?? 0);
$offset = (int)($_POST['offset'] ?? 0);
if (empty($keywords) || !$category_id) wp_die('At least one keyword and category are required');
update_option($this->option_state, ['category_id' => $category_id, 'offset' => $offset]);
update_option($this->option_keywords, $keywords_option);
$args = [
'post_type' => 'post',
'posts_per_page' => $this->batch_size,
'offset' => $offset,
'cat' => $category_id,
'post_status' => 'publish',
];
$batch_posts = get_posts($args);
if (empty($batch_posts)) {
wp_redirect(admin_url('admin.php?page=random-keyword-linker&done=1'));
exit;
}
// Gather candidate links for each keyword
$all_links = [];
foreach ($keywords as $kw) {
$linked_candidates = get_posts([
'post_type' => 'post',
'posts_per_page' => -1,
'post_status' => 'publish',
'cat' => $category_id,
's' => $kw,
]);
foreach ($linked_candidates as $p) {
if (stripos($p->post_content, $kw) !== false) {
$all_links[$kw][$p->ID] = get_permalink($p->ID);
}
}
}
foreach ($batch_posts as $post) {
$content = $post->post_content;
$original_content = $content;
// Find all already linked URLs in the post
preg_match_all('/<a[^>]+href=["\']([^"\']+)["\']/i', $content, $matches);
$already_linked_urls = $matches[1] ?? [];
// Use a DOMDocument only for finding tags, but do replacements on the raw HTML to preserve everything
$used_targets = [];
$used_keywords = [];
$links_added = 0;
foreach ($keywords as $kw) {
if (in_array($kw, $used_keywords)) continue;
$self_removed_links = $all_links[$kw] ?? [];
unset($self_removed_links[$post->ID]);
$available_links = array_diff($self_removed_links, $already_linked_urls, $used_targets);
if (empty($available_links)) continue;
// Only link if the keyword is not already linked
$pattern = '/(<a\b[^>]*>[^<]*?)(' . preg_quote($kw, '/') . ')(.*?<\/a>)/i';
$plain_pattern = '/\b(' . preg_quote($kw, '/') . ')\b/i';
// Find all <a>...</a> and mark their positions
$skip_positions = [];
if (preg_match_all('/<a\b[^>]*>.*?<\/a>/is', $content, $a_matches, PREG_OFFSET_CAPTURE)) {
foreach ($a_matches[0] as $a_match) {
$skip_positions[] = [$a_match[1], $a_match[1] + strlen($a_match[0])];
}
}
// Find first unlinked keyword occurrence not inside <a>
$offset_pos = 0;
$found = false;
while (preg_match($plain_pattern, $content, $m, PREG_OFFSET_CAPTURE, $offset_pos)) {
$kw_pos = $m[0][1];
$inside_link = false;
foreach ($skip_positions as $range) {
if ($kw_pos >= $range[0] && $kw_pos < $range[1]) {
$inside_link = true;
break;
}
}
if (!$inside_link) {
// Replace this occurrence
$linked_url = $available_links[array_rand($available_links)];
$used_targets[] = $linked_url;
$replace = '<a href="' . esc_url($linked_url) . '">' . $m[0][0] . '</a>';
$content = substr_replace($content, $replace, $kw_pos, strlen($m[0][0]));
$links_added++;
$used_keywords[] = $kw;
$found = true;
break;
}
$offset_pos = $kw_pos + strlen($m[0][0]);
}
if ($links_added >= $this->max_links_per_post) break;
}
if ($content !== $original_content) {
wp_update_post([
'ID' => $post->ID,
'post_content' => $content
]);
}
}
wp_redirect(admin_url('admin.php?page=random-keyword-linker&done=1'));
exit;
}
}
new Random_Keyword_Auto_Linker();
The topic ‘Conflict with a Custom Plugin’ is closed to new replies.