Skip to content

Instantly share code, notes, and snippets.

@bgrgicak
Created November 4, 2025 08:40
Show Gist options
  • Select an option

  • Save bgrgicak/4b3e386918b8e283fbf86635c4cb6d74 to your computer and use it in GitHub Desktop.

Select an option

Save bgrgicak/4b3e386918b8e283fbf86635c4cb6d74 to your computer and use it in GitHub Desktop.
<?php
/**
* Plugin Name: Menu URL Cleaner (MU)
* Description: Automatically removes /scope:ANYTHING/ prefix from WordPress menu item URLs
* Version: 1.0.0
* Author: Your Name
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
/**
* Clean menu URLs automatically on page load
*/
function mu_clean_menu_urls() {
global $wpdb;
// Use transient to avoid running on every page load
// Check every 5 minutes if there are URLs to clean
$transient_key = 'menu_url_cleaner_check';
if (get_transient($transient_key)) {
return; // Already checked recently
}
// Set transient for 5 minutes
set_transient($transient_key, true, 5 * MINUTE_IN_SECONDS);
// Query all menu items with URLs that start with /scope:
$menu_items = $wpdb->get_results("
SELECT pm.meta_id, pm.meta_value as url
FROM {$wpdb->posts} p
INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
WHERE p.post_type = 'nav_menu_item'
AND pm.meta_key = '_menu_item_url'
AND pm.meta_value LIKE '/scope:%'
");
if (empty($menu_items)) {
return; // Nothing to clean
}
// Clean the URLs
foreach ($menu_items as $item) {
// Check if URL starts with /scope: and capture the rest
if (preg_match('#^/scope:[^/]+/(.*)$#', $item->url, $matches)) {
$new_url = '/' . $matches[1];
// Update the URL
$wpdb->update(
$wpdb->postmeta,
array('meta_value' => $new_url),
array('meta_id' => $item->meta_id),
array('%s'),
array('%d')
);
}
}
}
// Hook into WordPress init
add_action('init', 'mu_clean_menu_urls');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment