How can I throw a 404 error from within hook_menu_get_item_alter()?
If I call drupal_not_found() then it keeps calling itself, and I don't know an other way to do this.
I was able to do this in hook_menu_get_item() by getting the status of the node from a simple query, and, when status isn't NODE_PUBLISHED, I change the router item's load function from node_load() to is_null(), which will always return FALSE when a node ID is passed to it. A FALSE from a load function will result in a 404 response from Drupal. This is a bit dirty, but it uses the Drupal API properly, and it seems to work!
/**
* Implements hook_menu_get_item_alter().
*/
function mymodule_menu_get_item_alter(&$router_item, $path, $map) {
if ($path == $_GET['q']) {
if (isset($map[0]) && $map[0] == 'node' && isset($map[1]) && is_numeric($map[1])) {
$status = db_query('SELECT n.status FROM {node} n WHERE n.nid = :nid', array(':nid' => $map[1]))->fetchField();
if ($status != NODE_PUBLISHED) {
// Replace node_load() with is_null() as load function, to ensure the
// output of the load function is FALSE, so we get a 404 response.
$router_item['load_functions'] = array('is_null');
}
}
}
}
You can't directly - data from hook_menu()
and hook_menu_alter()
are cached, so the decision can't be made there for individual page requests.
Instead, you need to override the page callback, e.g.
function MYMODULE_menu_alter(&$items) {
$items['foo']['page callback'] = 'MYMODULE_foo';
}
function MYMODULE_foo() {
drupal_not_found();
}