I have been asked to removed the /node page from a Drupal site, and I honestly don't know how. Would I disable the page within a theme, or disable it in some kind of admin option? This should be a simple task, but I can't find info about it anywhere.

Comments

dnewkerk’s picture

Good question... I started answering the way I'd think would work (provide a 301 redirect in .htaccess) but decided to test it first, and found that it redirected to ?q=node even though I pointed to the root of the domain (or if Global Redirect is installed, it instead causes an infinite loop). I then tried to write a bit of mod_rewrite based on the www/non-www rule, but I'm not too great at regular expressions yet so my attempt didn't succeed yet. I checked some big Drupal sites and it appears they too forget to deal with this appropriately (and since almost no major Drupal site uses the default front page, this leads to some pretty crazy looking broken pages on major Drupal sites at /node hehe). Of course this is usually denied in robots.txt so search engines are not adversely affected (and won't index the page), but it certainly would be nice to avoid that broken page. Hopefully someone will chime in with a good solution... if not I'll let you know if I figure it out or come across the information.

dnewkerk’s picture

Though it may be possible by other means as well, I found one way that appears to work, and it's not too hard to implement (follow my guide on starting your own very simple custom module).

Here's the code to add to the mini module:

/**
 * Implementation of hook_menu().
 */
function MODULENAME_menu() {
  $items = array();

  // Disable the default /node front page.
  $items['node'] = array (
    'title' => 'node',
    'page callback' => 'drupal_not_found',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
    );

  return $items;
}

After you save this in the module, you need to clear the Menu cache (Site configuration > Performance should do the trick). This only disables the /node path, but not /node/#. For the rest I recommend Global Redirect module, which will redirect any node/# paths automatically to their alias paths.

dman’s picture

Hm.
I tried adding an alias from /node to (eg) node/47.
I thought that may be a quick fix.
Wasn't.

walker2238’s picture

Use hook_menu_alter. Create a module and you can "unset/disable" the page a menu has created.

function modulename_menu_alter(&$items) {
// Disable the page node
$items['node']['access callback'] = FALSE;
}

Remember to clear the cache in performance after you created the module and installed it.

brad.bulger’s picture

at least in 6.14 which is what i'm running - the l() function in includes/common.inc fails because the $options parameter being passed in is NULL

i replaced $items['node'] with a call to my own function that does a redirect with drupal_goto('',null,null,301); - that *seems* to work so far.

i'd sure think there's a better way to do this, though.

brad.bulger’s picture

that was actually a node_breadcrumb bug bollixing up the 403 page! your code works fine.

alduya’s picture

function mymodule_menu_alter(&$items) {
  unset($items['node']);
}

This leads to a page not found instead of an access denied which is a little friendlier.

nlambert’s picture

How about this modification to the .htaccess file

RewriteRule ^/?node$ redir_path [L,R=301]

add the preceding line before the following

# Rewrite URLs of the form 'x' to the form 'index.php?q=x'.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

I personally don't like to use the node core paths. A lot of my content types don't "deserve" a page to themselves, or rather are only to be displayed in a list or gallery (ie. used with views).

Along with the above modification, I have also added the following :

RewriteRule ^/?node/[^a-zA-Z_]+$ redir_path [L,R=301]

With the preceding line, pages are only accessible if I have created an alias. This allows me to control access to content conveniently.

This is however a rather new functionality for me. It has been working well, but I hope not to have overlooked anything. I can only advise to test thoroughly before implementing. Any comment is also welcome.

Cheers

walker2238’s picture

Hmmm, that does seem like a new way of doing things but not really sure if it's the "Drupal" way of doing things. Personally I'd stick to using hook_menu and hook_menu_alter. If you don't want content created pages you can use hook_menu_alter to get rid of them or deny access to them. But that's just my 2 cents.

nlambert’s picture

Hi Walker,

I'm all for the Drupal way, so I tried the following :

function settings_module_menu_alter(&$items) {
$items['node/%']['access callback'] = FALSE;
}

Unfortunately, nodes are no longer available even with the alias. Maybe, I'm not doing this right.

My previous attempt (with the .htaccess) was inspired by the following suggestion found in the path redirect module :

"If you need advanced redirection functionality (i.e. wildcards, etc.), you should be using a webserver rewriting engine rather than this module."

Any more thoughts?

Cheers

walker2238’s picture

Maybe I didn't understand what you are trying to do. I assumed that you didn't want any node pages as you mentioned. The code you have above doesn't remove the page, instead is denies access to all users. Maybe if you explain what your trying to do I can help you a bit.

nlambert’s picture

Well, I've managed to do what I need and it seems to be working fine. However, if this can be done in a more Drupal way, I am willing to go that way.

A lot of my content types are very particular and (in a design sense) should not be displayed on their own. I use Views to wrap my content types in specific ways (for design) and display them in lists.

I wanted a way to control access to my content and prohibit the experienced user from typing the node/# urls (I try this myself when I come across a Drupal site).

I first tested the Path Redirect module. I wanted to redirect any user that typed the node/# url to a 404 page. I wished to use a wildcard such as node/%, but quickly found this note in the Add Path Redirect page :

If you need advanced redirection functionality (i.e. wildcards, etc.), you should be using a webserver rewriting engine rather than this module.

*** They seem to be working on this according to this thread : http://drupal.org/node/182512) ***

So I added the following lines to the .htaccess file :

RewriteRule ^/?node/[^a-zA-Z_]+$ redir_path [L,R=301]
RewriteRule ^/?node$ redir_path [L,R=301]

This allows me to

1. Prohibit experienced users from typing example.com/node or example.com/node/# urls
2. Redirect those users to a 404 page
3. Have Access Control through Path Aliases (pages accessible only via the alias -- i.e. if no alias, no access)

This is working well for me, but I am open to criticism. Maybe the best way will be developed by Mr Reid with the Path Redirect project.

Best regards

walker2238’s picture

Ok, I'm sorry I thought you wanted to get rid of the node pages instead of redirect.

kylehase’s picture

A lot of my content types are very particular and (in a design sense) should not be displayed on their own.

I have this same problem which I've posted here: http://drupal.org/node/846930
Views makes it possible to sculpt content to fit your needs but there's currently no Drupal way to prevent access to the default node page.

mpdonadio’s picture

I have been experimenting with the method I posted at http://drupal.org/node/846930#comment-3451328 and it has been working for my situation.

metalinspired’s picture

This will block access to search and doesn't work for multilingual sites.
Instead I used this:

RewriteCond %{REQUEST_URI} ^(.*)/?node(.*)$ [NC,OR]
RewriteCond %{REQUEST_URI} ^(.*)/?taxonomy(.*)$ [NC]
RewriteCond %{REQUEST_URI} !^(.*)/?search(.*)$ [NC]
RewriteCond %{REQUEST_URI} !^(.*)/?admin(.*)$ [NC]
RewriteRule .* - [F,L]

* Edit: Code above will block you from adding and editing nodes so use this one instead:

  # Prohibit direct access to nodes

  RewriteCond %{REQUEST_URI} ^(.*)/node(.*)?$ [NC]		# block access to nodes...
  RewriteCond %{REQUEST_URI} !^(.*)/node/[a-z/-]+$ [NC]		# ... but allow adding...
  RewriteCond %{REQUEST_URI} !^(.*)/node/[0-9]+/[a-z/-]+$ [NC]	# ... and editing, translating, viewing results...
  RewriteCond %{REQUEST_URI} !^(.*)/search/node(.*)?$ [NC]		# allow searching
  RewriteCond %{REQUEST_URI} !^/modules/node/node\.css$	[NC]	# allow access to core node module css
  RewriteCond %{REQUEST_URI} !^(.*)/admin(.*)$ [NC]		# if there is node keyword in admin path allow access
  RewriteRule .* - [F,L]

  # Prohibit direct access to taxonomy terms
  
  RewriteCond %{REQUEST_URI} ^(.*)/taxonomy(.*)$ [NC]	# block access to taxonomy terms
  RewriteCond %{REQUEST_URI} !^(.*)/admin(.*)$ [NC]	# if there is taxonomy keyword in admin path allow access
  RewriteRule .* - [F,L]
msathesh’s picture

@modesia thanks.. that worked for me too!

mikele’s picture

If you prefer redirect your /node page on a page not found, you could consider this snippet:

function modulename_menu_alter(&$items) {
    $items['node']['page callback'] = 'drupal_not_found';
}
scotjam’s picture

I'm using a template override 'page-front.tpl.php' as my home page, but when I use... $items['node']['page callback'] = 'drupal_not_found'; the home page is returned with the title 'Page not found'. How can I block all access to node without messing up this home page?

Also, I'm trying to block the user/register path using $items['user/register']['page callback'] = 'drupal_not_found'; but the page returned says access denied, rather than page not found. Is there a way around this?

Finally, I'm unable to find a way of blocking the node/add path. I've tried to use $items['node/add']['access callback'] = FALSE; hoping that it will help, but the page displayed is an access denied page but using the administrator theme, which doesn't look right.

cheers!
scotjam

mikele’s picture

I'm using a template override 'page-front.tpl.php' as my home page, but when I use... $items['node']['page callback'] = 'drupal_not_found'; the home page is returned with the title 'Page not found'. How can I block all access to node without messing up this home page?

The snippet concern the url "/node" and not the home page. Try to define another url for the home page.

Also, I'm trying to block the user/register path using $items['user/register']['page callback'] = 'drupal_not_found'; but the page returned says access denied, rather than page not found. Is there a way around this?

Are you connected when you try to access "user/register"? Or else have you tried to configure the user settings (admin/user/settings) to do what you need to do?

I'm unable to find a way of blocking the node/add path.

I don't know what you are trying to do, but the access to "node/add" have to be set by the user permissions.

el_topo’s picture

I sorted out by adding custom_url_rewrite_inbound() to settings.php.

This method is better than Apache rewrite rules, as it let you prevent access to node pages depending on user authentication status, or any other condition you may want. You will also get a nice 404 error in drupal reports page every time someone tries to access a node directly and the message will include which was the original page entered.


function custom_url_rewrite_inbound(&$result, $path, $path_language)
{
  global $user;

  // I do not filter url for the admin user
  if($user->uid == 1)
  {
    /* $result=$path; */ Just found out that this creates problems with URL aliases.
    return;
  }

  // I don't want people accessing pages through HOST/node/number
  if (preg_match('|^node/(.*)$|', $path, $matches))
  {
    $result='notfound_node/'.$matches[1];
    return;
  }

  // Prevent accessing main node page (HOST/node and HOST/node/)
  if (preg_match('|^node/?$|', $path))
  {
    $result='notfound_node';
    return;
  }
}

AlonGoldberg’s picture

/**
 * Implementation of hook_menu_alter().
 */
function YOUR_MODULE_NAME_HERE_menu_alter(&$items) {
  $items['node']['page callback'] = '_internal_custom_function_name_here_redirect_to_frontpage';
}

/**
 * Redirect back to the frontpage for specific pages.
 */
function _internal_custom_function_name_here_redirect_to_frontpage() {
  if($_GET['q'] == 'node') {
    $_REQUEST['destination'] = "<front>";
    drupal_goto();
  }
}
afagioli’s picture

OnkelTem’s picture

I've cooked a simple module for Drupal 7 which disables "/node" page if its not configured as a website's front page.
Default front page disabler
It is sandboxed project.

ACD’s picture

I have Redirect module installed (http://drupal.org/project/redirect). So, I just added one 301 redirect from node to <front>. And it works!
Any comments about this method?

P.S. Sorry, I did not pay attention to the Drupal version in this post. I use 7.

jkingsnorth’s picture

I received a warning from the module that advised me to create a URL alias instead. I did this, and it did the trick!

aklump’s picture

nicolaj.knudsen@gmail.com’s picture

There is another module now with similar functionality: https://www.drupal.org/project/restrict_node_page_view
It has the advantage that you can restrict access based on content types in the permission settings.

Edit: I seems that there is a lot of options, might as well list some of them here for future googlers:
https://www.drupal.org/project/rabbit_hole
https://www.drupal.org/project/internal_nodes

Edit 2: And of course, this effect can be achieved with Rules: https://www.drupal.org/project/rules
That might be the most future proof method anyway, even though it's a bit more work to set it up correctly.

medhatayar’s picture

URL alias is easy solution

jaypan’s picture

In a module:

function HOOK_menu_alter(&$menu)
{
  unset($menu['node']);
}

Clear your cache, and the page is gone.

Contact me to contract me for D7 -> D10/11 migrations.

dman’s picture

unset($menu['node']);

Looks like a quick fix, but I found a site that someone had done this to once - it produced some unexpected, unpleasant side-effects.
For some reason, the title and breadcrumbs of deeper node/n/* pages were being corrupted strangely. (not node pages themselves, but something deeper, like nod/n/revisions etc IIRC). There may have been a combination of other modules in play as well.

I recommend that a cleaner fix-up is not to unset that code menu router link, but instead block it, with

function HOOK_menu_alter(&$menu) {
  $menu['node']['access'] = FALSE;
}
alexecus’s picture

I believe it should be:

$menu['node']['access callback'] = FALSE;