Overall, I think you have it right. I'm wondering if there is a conflicting plugin or something changing the menu order. I wouldn't rely on the hard coding the menu index (as it is in the question $menu[1][2] = ...
, rather I'd search through the menu to find your matching unique slug. Here is a function I whipped up real quick that should help...
function add_menu_url ($page_title, $menu_title, $capability, $dest_url, $function = '', $icon_url = '', $position = NULL) {
global $menu;
$temp_slug = uniqid('my_random_temp_slug_');
add_menu_page($page_title, $menu_title, $capability, $temp_slug, $function, $icon_url, $position);
foreach ($menu as $position => &$page) {
if ($page[2] === $temp_slug) {
$page[2] = $dest_url;
break;
}
}
}
And it's usage...
add_action('admin_menu', function () {
add_menu_url('linked_url', 'Roster', 'read', '/wp-admin/tools.php?page=some-user-page#tab1', '', 'dashicons-calendar-alt', 3);
});
It functions exactly the same as add_menu_page but allows you to put any custom destination url (which I think is what you're trying to do) instead of a relative admin url.
NOTE: the $dest_url
param can be any url. It does not have to strictly be a wordpress admin url. It could be an external link as well
The key is that it's assigning a unique random slug to the add_menu_page function, then after that's set, looping through the global $menu to find it's match. The loop is passing by reference, so we make the update in the loop, then break.
I also forgot to note that 2 is reserved for the main 'Dashboard' link and if you use 2, it will get re-indexed to another number. I would suggest using 3 to avoid this collision. Although the code I wrote above will take that into account regardless.