Clear all cached pages with menus associated with a node on insert/update/delete
chadd - October 22, 2009 - 14:05
| Project: | Boost |
| Version: | 6.x-1.x-dev |
| Component: | Caching logic |
| Category: | feature request |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | closed |
Description
just wanted to throw this out there as an idea for future releases.
don't know if it is in the 6.x roadmap or not...

#1
Menu's are sorta like blocks, they are on every page, so your best bet is to clear the entire cache. What your asking can be done programmatically though... this is how I see it working. Find all nodes in a menu, when a node in that menu is changed or a new item is added to the menu, flush all nodes in the menu.
How do you see this working? Flush where menu is displayed (hard problem to do correctly) or Flush nodes inside menu (not as hard to do).
#2
flushing the entire menu would basically be flushing our entire site, so that wouldn't be any more helpful than the current clear cache.
i would want it to find what parent item the changed node has, and then flush all the pages that are under that parent.
the farther "down the line" the edited node is, the fewer other nodes would be flushed along with it.
and as an added fun bonus, just to make it a little more complex, it would only flush it's 'sibling' pages, if the menu, title or alias was edited.
that would prevent flushing other pages when all that was edited was body content or some other field that had no impact on the menu or url...
#3
Detecting that only the title, alias or menu has changed is a problem I don't want to solve.
Can you describe this feature request in more detail? Diagrams help.
Menu Tree-Top
-Middle
-Bottom
-Deep
-Very Deep
-Middle
-Bottom
-Deep
-Deep
-Deep
-Very Deep
-Bottom
-Bottom
-Top
#4
based upon the below chart ( i added numbers to keep things straight):
example 1: if you update 'deep 1' then you would have to flush it's siblings, deep 2, deep 3, and it's children, very deep 1, and it's parent, bottom 1
example 2: if you update very deep 2, only deep 4 would be flushed
example 3: if you update bottom 2, flush the following: (parent:) middle 2, (siblings:) bottom 3, bottom 4, (children:) Deep 2, Deep 3, Deep4, Very Deep 2
Menu Tree-Top 1
-Middle 1
-Bottom 1
-Deep 1
-Very Deep 1
-Middle 2
-Bottom 2
-Deep 2
-Deep 3
-Deep4
-Very Deep 2
-Bottom 3
-Bottom 4
-Top 2
basically, everytime you edit a page, you'd flush it's parent nodes, children nodes, and sibling nodes. (cool would be the option to choose which of these 3 to flush, for example, i only want to flush sibling and children, or only parents, etc)
having it flush *only* after menu specific changes (title, menu, alias) would be awesome, but i know that would be a huge challenge.
#5
example 2 Wouldn't you also flush Very Deep 1?
example 3 Bottom 1?
Help me understand why I need to flush sibling nodes. I get flushing the parent and all child, but why the siblings in another tree like example 1?
#6
no, those aren't siblings to the edited node because they don't have the same parent node, i would call them "cousin's"
i guess it would help if i define siblings: pages at the same level and with the same parent menu item would be "siblings"
pages at the same level but with different menu parent items i'm going to call "cousins"
i think you would have to flush siblings because they share the same "displayed menu"
for example (from above):
if you added a page called "bottom 5" and gave it the parent menu of "middle 2" then that "bottom 5" page menu item should display in the menu on the "bottom 2, 3 & 4"
#7
ok cool, I'll add this to the roadmap. I understand the expected results now.
#8
Drupal menu system (Drupal 6.x)
Code to load any nodes menu items
<?php$nid = 12;
$node = node_load($nid);
menu_nodeapi($node, 'prepare');
echo print_r($node, TRUE);
?>
This is the start of the rabbit trail for figuring out the parent, siblings and all children of a node in the menu system.
http://api.drupal.org/api/function/menu_secondary_links/6
http://api.drupal.org/api/function/menu_overview_form/6
http://api.drupal.org/api/function/menu_tree_all_data/6 <- Looks like a winner...
#9
Test case is node/12
<?php
require_once './includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
$nid = 12;
$node = node_load($nid);
menu_nodeapi($node, 'prepare');
$output = $node->menu['menu_name'];
$menu = menu_tree_all_data($output);
echo "\n\n";
$out = build_menu_structure($menu);
echo print_r($out, TRUE);
function build_menu_structure($menu) {
foreach ($menu as $item) {
if (!empty($item['below'])) {
$str[$item['link']['link_path']] = build_menu_structure($item['below']);
}
else {
$str[$item['link']['link_path']] = '';
}
}
return $str;
}
?>
Output
Array
(
[node/3] => Array
(
[node/10] => Array
(
[node/21] =>
[node/12] => Array
(
[node/13] => Array
(
[node/14] => Array
(
[node/15] => Array
(
[node/16] => Array
(
[node/17] => Array
(
[node/18] =>
[node/19] =>
)
)
)
)
)
)
[node/20] =>
)
[node/4] =>
[node/8] =>
[node/9] =>
[node/11] =>
)
[node/1] =>
[node/2] =>
[node/7] =>
)
With this I need to expire
Self: node/12
Parent: node/10
Siblings: node/21, node/20
Children: node/13, node/14, node/15, node/16, node/17, node/18, node/19
<?php
require_once './includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
$nid = 12;
$node = node_load($nid);
menu_nodeapi($node, 'prepare');
$output = $node->menu['menu_name'];
$menu = menu_tree_all_data($output);
echo "\n\n";
$out = build_menu_structure($menu, 'node/12');
//print_r($out);
$GLOBALS['_test'] = array_unique($GLOBALS['_test']);
sort($GLOBALS['_test']);
print_r($GLOBALS['_test']);
function build_menu_structure($menu, $needle, $found = FALSE) {
$GLOBALS['_test_found'] = FALSE;
foreach ($menu as $item) {
if ($item['link']['link_path'] == $needle || $found) {
$GLOBALS['_test'][] = $item['link']['link_path'];
$found = TRUE;
}
}
foreach ($menu as $item) {
if ($item['link']['link_path'] == $needle || $found) {
$GLOBALS['_test'][] = $item['link']['link_path'];
$found = TRUE;
}
if (!empty($item['below'])) {
$str[$item['link']['link_path']] = build_menu_structure($item['below'], $needle, $found);
if ($GLOBALS['_test_found']) {
$GLOBALS['_test'][] = $item['link']['link_path'];
}
}
else {
$str[$item['link']['link_path']] = '';
}
}
$str = array_unique($str);
$GLOBALS['_test_found'] = $found;
return $str;
}
?>
Outputs what I need
Array(
[0] => node/10
[1] => node/12
[2] => node/13
[3] => node/14
[4] => node/15
[5] => node/16
[6] => node/17
[7] => node/18
[8] => node/19
[9] => node/20
[10] => node/21
)
#10
Make this a radio option. Your desired effect or clear all items in the menu if using something like DHTML Menu.
#11
I got Parent, Sibling, Children done. Well At least I think I did, I need some sleep. I should also Place these into a relationship fieldset or something like that.
#12
This is still ugly code, no more global variables though... it works too!
#13
committed
#14
Automatically closed -- issue fixed for 2 weeks with no activity.