Blog

How to Make Optionally Hidden Node Titles in Drupal (Using CCK)

How to Make Optionally Hidden Node Titles in Drupal (Using CCK)

In the popular open-source content management system (CMS) Drupal, titles display on every page as part of the Content Management System's functionality. But what if you don't want to have the titles display on some pages? For example, if you want to use a banner instead of the plain title. There's an easy way to make Drupal's node titles optional using the Content Construction Kit (CCK) module.6.x

Presumably you already have Drupal installed if you're reading this. If not, check out Drupal. It's a powerful CMS that is has a great community of developers. Many sites from well-known companies are powered by Drupal. Even the White House's website is powered by Drupal!

What you'll need to get started:

  • Drupal 6.x (something similar should work with 5.x, but I haven't tested it)
  • Content Construction Kit (CCK) for Drupal 6.
  • NOTE: Most of CCK's functionality has been moved to core in Drupal 7, so downloading the CCK module won't be necessary for Drupal 7 once it's released.

If you don't already have CCK installed, download and install it to your Drupal site now.

Step 1 — Finding content types settings
Once you've installed CCK, go to the "content types" section of Drupal admin (found at /admin/content/types).

Admin Panel
Select "content types" in the Drupal admin panel.

Step 2 — Managing a content type's fields
Select "manage fields" for the content type you wish to edit.

Admin Panel
Select "manage fields" for the content type you wish to edit.

Step 3 — Adding a new field
Add a new field to the content type. To do this drag the "new field" row to the position you want and fill in the field information. You'll probably want to drag your new field to right below the title field. You can use whatever label and field name you want, but we use "Title hide" and "titlehide" and we'll refer back to this later. The type should be set to "text" and the form element should be set to "Single on/off checkbox." This field will be used to specify if you want the node's title to be displayed or hidden. Once you're done, click "save."

Admin Panel
Add the field that will be used to specify whether or not to hide the title.

Step 4 — Defining field's allowed values
After you press save, you'll be brought to a new page where you can specify more detailed settings for the field. Here you need only change one setting: the "allowed values list." Enter "display|Display Title" on the first line and "hide|Hide Title" on the second line. These values will be referred to later. Once you've entered this, scroll down to the bottom of the page and save the field settings.

Admin Panel
Complete the allowed values list as it is above.

Once you save, you'll see your new field along with the others.

Admin Panel
Your content type's fields, including the new field you just created

Step 5 — Hiding the new field
Because this field will be used internally to hide or show the title of a page, you don't want this field to display in the node view. To hide the display of this field in the node view, click on the "display fields" tab. Once the display fields settings have loaded, change the label, teaser, and full node display to "" and then save.

Admin Panel
The display fields settings.

Step 5 — Grab a cup of coffee (tea?)... you're almost done

Awesome — you're "title hide" field is all set up (but you're not done yet)! If you go to add a new node of that content type, you'll see you can now tick the box to hide the title.

Admin Panel
You'll now see the title hide option when you add or edit nodes of that content type.

Step 6 — Bring the field to life
In order to make your new title hide field useful, you need to build it into your theme. To do this, I added some PHP code that will insert the value of the field as a CSS class of the title.

Step 7 — Identify the theme file that displays the node's title on the page
Identify the theme file that displays the node's title on the page. For most themes the theme file that is responsible for displaying the title is called page.tpl.php.

Step 8 — Find the PHP code that displays the page's title
Locate the PHP code that displays the title:

<?php print $title; ?>

It may be surrounded by additional related HTML and PHP that define layout, styles, or in which cases the title should load:

<?php if ($title): ?>
<div id="title"><h1><?php print $title; ?></h1></div>
<?php endif; ?>

Step 9 — Insert your title hide field as a class of the title's H1 tag
Insert your title hide field as a class of the H1 tag. This will look something like this:

<?php if ($title): ?>
<div id="title"><h1 class="title <?php if(!empty($node->field_titlehide[0]['value'])) {$titlehide = $node->field_titlehide[0]['value']; print $titlehide;} ?>"><?php print $title; ?></h1></div>
<?php endif; ?>

Step 10 — Add the CSS class that hides the title
Hiding the h1 tag is based on CSS style rules. Add a CSS rule like the following anywhere in your theme's stylesheets:

h1.hide{
display: none;
}

Step 11 — Finito
Congratulations! You now have optional Drupal node titles.

Troubleshooting

Nothing seems to be happening...
Hiding the h1 tag is based on CSS style rules. Did you remember to add a CSS style rule like the following in order to hide your title?

h1.hide{
display: none;
}

This style can be added anywhere to any of your site's CSS stylesheets.

The CSS class isn't being added to the title
Here are a few suggestions...

  • First try clearing your theme's cache! If Drupal is running on old, cached theme files, changes might not take effect.
  • The php code is based on calling the right CCK variable. You need to make sure you named your CCK field the same as I did or if you named it differently, you need to make those adjustments in my code. You also want to make sure you used the same CCK field type that I used, a checkbox, or you may not be calling the contents of the variable properly.
  • If you did everything right and the variable is still not being written as a CSS class to the H1 element, there's probably a issue with your theme accessing and displaying the CCK field using PHP variables. I'd recommend using the Devel contributed module in order to see what variables are being loaded and in order to help diagnose theme problems.
DiggThis

Comments

Anonymous's picture

I read your post about "How to Make Optionally Hide Node Titles in Drupal (Using CCK)" and I evaluated it very interesting but unfortunately it don't work for me.

I have made all the change in drupal and i think that the problem is in my page.tpl.php.

Can you see my code (if i understand where is the problem i can share your metod with italian drupal community)?

Isaac's picture

My theme is a custom theme based off the Zen starter theme, although I don't see why it wouldn't work with your theme.

To make sure the proper CCK variable is available to the template, I recommend installing the Devel module. Once you install it, you can view all of the template variables that are loading (including CCK template variables). You'll be able to see the value of the CCK field you're using to switch the title hide on and off and then verify that the php code you're using is actually calling the variable to load.

Try this and let me know how it goes.

Anonymous's picture

Thanks, that's awesome!

I've been scratching my head on this small problem for a while!

You're tute works just perfect.

One question however: my Title Hide field offers a third (and default) radio box saying "N/A". How do i get rid of it?

Thanks again!

Simon

Isaac's picture

I used the "Single on/off checkbox" for the widget type rather than "Check boxes/radio buttons." This provides just one checkbox where the default (unchecked) option is the first allowed value and the checked option is the second allowed value.

Anonymous's picture

Thanks for all the great information. I am glad I ran across your blog. I look forward to reading your next post.

Anonymous's picture

How would I hide a field title? I am just getting into Drupal.....

Cliff

Isaac's picture

Hey Cliff,

Refer to step five above to hide the field's label. As you can see, you want to set "Label" to "" in the "Display Fields" section.

Good luck and let me know if this answers your question.

Anonymous's picture

Nice tutorial, thanks.
If I promote the node to display on front page, it will still show the title.
Any idea where that code would be?

thanks

Isaac's picture

Node titles are displayed through page.tpl.php. I'd recommend using the Views module to achieve better display of nodes (on the front page for example). Virtually all of my homepage is displayed using views from the Views modules.

Anonymous's picture

I have the Drupal acquia installation (which includes cck), with the zen theme, and cannot get it to work. Any thoughts?

Anonymous's picture

For my use case I need the actual div "<div id="title">" to not be printed at all when hidden. How could this be accomplished?

Isaac's picture

Bryan, you'll need to put a PHP if statement around the H1 tag. Basically, the statement would specify that if the do-not-display setting is turned off, the H1 tag will be loaded.

Anonymous's picture

So I figured out how to do this with basically the same setup (except my CCK field is titled "field_title_hide")

Instead of changing anything in your page.tpl.php file, add the following to your template.php file. Change "THEMETITLE" to the title of your theme and "field_title_hide" to the name of your cck field.

function THEMETITLE_preprocess_page(&$vars) {
	if($vars['node']->field_title_hide[0]['value'] == 'hide')
	{
		unset($vars['title']);
	}else{
		$vars['title'];
	}
}
Anonymous's picture

Thanks for the clearly written tutorial.

If you have time, it would be really useful to know how to use a similar process to add a CSS tag to a Views field.

I have a Product content type with a single on/off checkbox. First value is empty, second value displays a "New Product" checkbox in node/edit.

allowed values look like this:
|
New | New Product

Products are searchable via exposed filters in views, and I'd like to display "NEW" next to the title (in the filtered results) for any product that's checked New Product.

If I could get the view to add a "new" class to "field-content", I could add a NEW image using specific CSS. I copied views-view-fields.tpl.php and tried adding your code above:

 <<?php print $field->element_type; ?> class="field-content <?php if(!empty($node->field_new_product[0]['value'])):?>new<?php endif; ?>"><?php print $field->content; ?></<?php print $field->element_type; ?>>

but it may be obvious that I really have no idea how to get it to read the node's value for field_new_product. A conditional statement that reads the value? And is this whole thing more doable in template.php? Thanks in advance!

Isaac's picture

Hey Keva, in order to affect the output of a theme, you need to use a theme override template. In Drupal 6, there is an automatic structure for theme override templates. In Drupal 5, you have to inform the theme via template.php that you are overriding the View.

So when editing a View in Views 2 for Drupal 6, you can click "Theme Information" in order to see a list of overrides. You can theme individual fields/rows of content, or if you want to, you can theme the entire view from scratch.

But there's actually an easier way to do what you're looking to do. You can actually rewrite the output of a particular field in a theme by clicking on that field and checking "Rewrite the output of this field." You'll then be prompted to enter in a text box how the field should be rewritten. The key thing here is that you can use fields listed prior to the field you're currently editing as tokens. So make sure you have the "new" field load before the field you want the CSS class to be applied to (i.e., put the "new" field first).

Then using the replacement patterns, you can construct something that looks like this:

<h1 class="[field_new_value]">[title]</h1>

Finally, don't forget to set the "new" field to be hidden since you only want it to show up as the CSS class.

You can also do it via the template method, but you'll have to create a template file that overrides one of the theme's outputs as described above, and you'll have to call the content with PHP. Also, I included the if statement for semantic purposes, but it's technically not necessary. You can just output the value of the field, and then only define the CSS class for the particular value you care about.

Anonymous's picture

Very cool! Thanks for sharing. Now I'm following you..

Anonymous's picture

thanks for your time.! I've used the rewrite before, but didn't think to apply here.

regarding the template, I had gotten as far as theming views-view-field--field-new-product-value.tpl.php with an if/then, but couldn't get it to work right (only "then" was applied). Your solution is MUCH easier.

just read your About page. I can't believe you just graduated from high school last year!! Amazing!

Isaac's picture

Glad you got it to work, and thanks for the kind words!

Anonymous's picture

Superb! Generally I never read whole articles but the way you wrote this information is simply amazing and this kept my interest in reading and I enjoyed it. You have got good writing skills.

Anonymous's picture

Greatly written article but for some reason it doesn't seem to be working for me. I copied the code into the area I thought it belonged in the page.tpl.php file.

I'm using a zen based sub theme as well: Here's the code snippet:

<?php if ($breadcrumb || $title || $tabs || $help || $messages): ?>
          <div id="content-header">
            <?php print $breadcrumb; ?>
            <?php if ($title): ?>
              <div id="title"><h1 class="title <?php if(!empty($node->field_titlehide[0]['value'])) {$titlehide = $node->field_titlehide[0]['value']; print $titlehide;} ?>"><?php print $title; ?></h1></div>
            <?php endif; ?>
            <?php print $messages; ?>
            <?php if ($tabs): ?>
              <div class="tabs"><?php print $tabs; ?></div>
            <?php endif; ?>
            <?php print $help; ?>
          </div> <!-- /#content-header -->
        <?php endif; ?>

Not much of a coder so I'm not sure if I put it in the right place. But that was the only instance of <?php print $title; ?> I found. Thanks for your help.

Isaac's picture

Hey, your code appears to be fine. Did you add the css style rule that would hide the title element if the setting is turned on? If not, you'll need to go ahead and add this rule. If so, and the css class isn't showing up at all, there's a problem with Drupal calling a variable.

You can use the Devel module (this is a contributed model, not a core module) in order to see what variables are being loaded through the template and are available to use.

Since you're using a zen-based template, the variable should be available to the page.tpl.php theme file.

Anonymous's picture

I've tried doing this, but the title is still there. I am using the Zen starter theme. I replaced the code in the page.tpl.php form, but nothing seems to change.

Isaac's picture

Hey Dave, to help diagnose your problem, if you look at the source code, is the CSS class "hide" being added to the h1 title element?

If so:
You only need to add a CSS class to hide the element, like this:

h1.hide{
display: none;
}

If not:
There's a problem with you're template calling the variable. You may find the Devel contributed module useful in diagnosing your problem and make sure your new CCK variable is available to use in theming. You might try adding a snippet of code to your template.php file (see one of my comments above); I'm not sure if this will work, but it's worth a try. Also, keep in mind that if you named your CCK field something other than what I used, you'll need to change the PHP code accordingly.

Anonymous's picture

On the source I see this

<div id="content-header">
<div id="title"><h1 class="title hide">Home</h1></div>
</div> <!-- /#content-header -->

Pardon my ignorance, I'm still learning, but where would would I add the CSS class too?

Isaac's picture

Hey Dave, that's great news! That means that the PHP is working properly -- all you're missing is the CSS style rule that instructs the h1 to be hidden. You can add the sample style I posted above anywhere in any of your sites style sheets. My site's primary style sheet is called style.css, but yours may be called something else. Look for a .css file in your theme's directory.

Anonymous's picture

Outstanding! That looks like that took care of that. I will definitely check out your site for other tips and tricks as I learn my way through drupal. Thanks!

Anonymous's picture

Okay awesome got it to work for individually generated Page, Blog and Forum titles. Thanks, turns out I had forgotten to add the CSS class.

How do I go about hiding the title for the main Blog and Forums pages?

site.com/blog
site.com/forums

Both still have their titles (Blog, Forums) visible. And I'm not sure where to turn those off. Thanks again for your help.

Isaac's picture

Unfortunately my method only works for nodes. There is however, an alternate method that can be applied to any page:

Add the following code to your template.php file (anywhere will do as long as you don't break up another piece of code), making sure to change any instance of 'magic' to the actually name of your own theme. Note that this name is the name of your theme's .info file, omitting the .info extension.

/**
 * Override or insert variables into the page templates.
 *
 * @param $vars
 *   An array of variables to pass to the theme template.
 * @param $hook
 *   The name of the template being rendered ("page" in this case.)
 */
function magic_preprocess_page(&$vars, $hook) {
  // Add conditional stylesheets.
  if (!module_exists('conditional_styles')) {
    $vars['styles'] .= $vars['conditional_styles'] = variable_get('conditional_styles_' . $GLOBALS['theme'], '');
  }

  // Classes for body element. Allows advanced theming based on context
  // (home page, node of certain type, etc.)
  $classes = split(' ', $vars['body_classes']);
  // Remove the mostly useless page-ARG0 class.
  if ($index = array_search(preg_replace('![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s', '', 'page-'. drupal_strtolower(arg(0))), $classes)) {
    unset($classes[$index]);
  }
  if (!$vars['is_front']) {
    // Add unique class for each page.
    $path = drupal_get_path_alias($_GET['q']);
    $classes[] = magic_id_safe('page-' . $path);
    // Add unique class for each website section.
    list($section, ) = explode('/', $path, 2);
    if (arg(0) == 'node') {
      if (arg(1) == 'add') {
        $section = 'node-add';
      }
      elseif (is_numeric(arg(1)) && (arg(2) == 'edit' || arg(2) == 'delete')) {
        $section = 'node-' . arg(2);
      }
    }
    $classes[] = magic_id_safe('section-' . $section);
  }
  if (theme_get_setting('magic_wireframes')) {
    $classes[] = 'with-wireframes'; // Optionally add the wireframes style.
  }
  $vars['body_classes_array'] = $classes;
  $vars['body_classes'] = implode(' ', $classes); // Concatenate with spaces.
}

/**
 * Override or insert variables into the node templates.
 *
 * @param $vars
 *   An array of variables to pass to the theme template.
 * @param $hook
 *   The name of the template being rendered ("node" in this case.)
 */
function magic_preprocess_node(&$vars, $hook) {
  // Special classes for nodes
  $classes = array('node');
  if ($vars['sticky']) {
    $classes[] = 'sticky';
  }
  if (!$vars['status']) {
    $classes[] = 'node-unpublished';
    $vars['unpublished'] = TRUE;
  }
  else {
    $vars['unpublished'] = FALSE;
  }
  if ($vars['uid'] && $vars['uid'] == $GLOBALS['user']->uid) {
    $classes[] = 'node-mine'; // Node is authored by current user.
  }
  if ($vars['teaser']) {
    $classes[] = 'node-teaser'; // Node is displayed as teaser.
  }
  // Class for node type: "node-type-page", "node-type-story", "node-type-my-custom-type", etc.
  $classes[] = magic_id_safe('node-type-' . $vars['type']);
  $vars['classes'] = implode(' ', $classes); // Concatenate with spaces
}

/**
 * Override or insert variables into the comment templates.
 *
 * @param $vars
 *   An array of variables to pass to the theme template.
 * @param $hook
 *   The name of the template being rendered ("comment" in this case.)
 */
function magic_preprocess_comment(&$vars, $hook) {
  include_once './' . drupal_get_path('theme', 'magic') . '/template.comment.inc';
  _magic_preprocess_comment($vars, $hook);
}

/**
 * Override or insert variables into the block templates.
 *
 * @param $vars
 *   An array of variables to pass to the theme template.
 * @param $hook
 *   The name of the template being rendered ("block" in this case.)
 */
function magic_preprocess_block(&$vars, $hook) {
  $block = $vars['block'];

  // Special classes for blocks.
  $classes = array('block');
  $classes[] = 'block-' . $block->module;
  $classes[] = 'region-' . $vars['block_zebra'];
  $classes[] = $vars['zebra'];
  $classes[] = 'region-count-' . $vars['block_id'];
  $classes[] = 'count-' . $vars['id'];

  $vars['edit_links_array'] = array();
  $vars['edit_links'] = '';
  if (theme_get_setting('magic_block_editing') && user_access('administer blocks')) {
    include_once './' . drupal_get_path('theme', 'magic') . '/template.block-editing.inc';
    magic_preprocess_block_editing($vars, $hook);
    $classes[] = 'with-block-editing';
  }

  // Render block classes.
  $vars['classes'] = implode(' ', $classes);
}

/**
 * Converts a string to a suitable html ID attribute.
 *
 * http://www.w3.org/TR/html4/struct/global.html#h-7.5.2 specifies what makes a
 * valid ID attribute in HTML. This function:
 *
 * - Ensure an ID starts with an alpha character by optionally adding an 'id'.
 * - Replaces any character except alphanumeric characters with dashes.
 * - Converts entire string to lowercase.
 *
 * @param $string
 *   The string
 * @return
 *   The converted string
 */
function magic_id_safe($string) {
  // Replace with dashes anything that isn't A-Z, numbers, dashes, or underscores.
  $string = strtolower(preg_replace('/[^a-zA-Z0-9-]+/', '-', $string));
  // If the first character is not a-z, add 'id' in front.
  if (!ctype_lower($string{0})) { // Don't use ctype_alpha since its locale aware.
    $string = 'id' . $string;
  }
  return $string;
}

// Allows theming of individual nodes
// function phptemplate_preprocess_node(&$vars) {
//    $vars['template_files'][] = 'node-' . $vars['nid'];
//    return $vars;
// }

And then make sure you're page.tpl.php file's body tag looks like this:

<body class="<?php print $body_classes; ?>">

This will add relevant classes to the body tag about the content you're on. You can use these classes to create CSS style rules to hide h1 tags on specific pages.

Anonymous's picture

Okay so I added that code to the template.php folder.

I see how it creates:

body class="not-front logged-in no-sidebars page-blog section-blog lightbox-processed"

But from there I'm lost. I added a .page-blog class to the style.css and I can make the whole page disappear with display: none; but I haven't been able to come up with the code to make just the page title disappear.

Thanks for your help. *sigh* Chose Drupal because I thought I wouldn't have to code anything. :P

Isaac's picture

Drupal's an awesome and very powerful CMS, but it can be pretty technically intensive (that's something they're trying to address with Drupal 7).

You need to use the .page-blog class as a parent to the h1. By adding the rule ".page-blog" set to hide, you're telling the page to hide any element that has the class "page-blog."

Here's what you need:

body.page-blog h1.title{
display: none;
}

Here's what that code specifies:
Set the display mode to hide for h1 elements with the class "title" that are child to (nested within) the body element with the class of "page-blog."

If the title is an h2, you'll have to replace h1 with h2 in the rule.

Anonymous's picture

Awesome. Got it. And I even understand it.

If I end up saying screw it and decide to have someone else do all the work for me I'm calling you guys for a quote :)

Isaac's picture

No problem and sounds good, haha. Good luck with your project.

Anonymous's picture

Our theme uses this code for the page title.
<?php if ($title): echo ''. $title .''; endif; ?>
Any idea how to code it for this to work? THANKS

Isaac's picture

That code right there just calls a variable called "title" and outputs it. Just wrap a span, h2, or div around your title code. Then just add the following PHP code in the class attribute of your HTML element that's wrapped around your title code:

<?php if(!empty($node->field_titlehide[0]['value'])) {$titlehide = $node->field_titlehide[0]['value']; print $titlehide;} ?>
Anonymous's picture

Hi,

I'm trying this again, but I switched to the wabi theme. I can't get it to work, and the title function in the page.tpl.php page has a bit more code. Is it possible to get it to function in this theme? Here is what the code looks like

    <?php print $breadcrumb ?>
    <?php if(!empty($node) && $page == 0) { ?>
      <div id="cr8"></div>
    <?php } else { ?>
      <?php if($title) { ?>
        <table border="0" cellpadding="0" cellspacing="0" class="pagetitle">
        <tr>
          <td class="pagetitle-l"></td>
          <td class="pagetitle-c">
              <h1><?php print $title ?></h1>
          </td>
          <td class="pagetitle-r"></td>
        </tr>
        </table>
      <?php } ?>
Isaac's picture

Hey Dave,

You need to add the following code as a class to an HTML element surrounding the title:

<?php if(!empty($node->field_titlehide[0]['value'])) {$titlehide = $node->field_titlehide[0]['value']; print $titlehide;} ?>

Important things to remember:
1. This assumes your CCK field is titled "titlehide"
2. You still need to add the CSS rule to actually hide the element

Apart from that, that coding seems a bit sloppy.

First, the use of tables for layout is deprecated for a number of reason, primarily poor accessibility and lack of flexibility in CSS styling and layout. All layout should be done with spans and divs. Tables should really only be used for data/content.

Second, the php syntax is not correct. If you want to break up PHP conditional statements with HTML code, you should use this syntax:

<?php if(!empty($node) && $page == 0): ?>
<h1>your HTML code here</h1>
<?php else: ?>
<h1>some other HTML code</h1>
<?php endif; ?>

Curly brackets "{" should be used to declare what happens if a statement is true when you're using a continuous block of php code.

Anonymous's picture

Thats too bad. I found the zen starter theme to be a bit too much work when the wabi theme got me 95% percent of the way there. I'll give it a try, thanks!

Anonymous's picture

This is what I was looking for. Thanks a lot!

Post new comment

The content of this field is kept private and will not be shown publicly. If you have a Gravatar account, used to display your avatar.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

More information about formatting options

CAPTCHA
The following question helps us prevent spam submissions.
14 + 0 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.