Setting up a Drupal site: Notes to self
This is just a collection of jots I ( = a Drupal newbie) wrote down as I set up a site with Drupal 7.2. Don’t expect this to be more coherent than a typical shopping list.
March 2019 update: Drupal was a huge mistake. Just in case someone out there still has a chance to escape.
And now I appreciate how easy it is to install and use WordPress. Drupal is definitely not good for my health: Hours of frustration trying to accomplish seemingly simple things can’t do me good. It’s tempting to conclude, that Drupal contributors have some job-security-by-obscurity kind of mind set. And I do understand why they end up with nasty hacks in PHP: The nice menus offer a million features, except what is really needed.
General remarks
- The development module is a blessing. In particular the ability to display the SQL queries related to a page: Under Modules, go to “configure” for the Development Module and check “Display query log”. And there’s an “A” next to each row of SQL, which means “display argument”. That is, show the query with what was inside the placeholders. Soooo nice.
- The “devel” tab (part of the development module?) is great: The metadata, with internal names is all listed there. Everything there is to know about a node.
- Enable the PHP text format. It allows running PHP code within any node, which is sometimes necessary.
- The number of files necessary to display a simple page is absolutely insane: A simple textual home page reaches 46 files (many of which are Javascript and CSS files) with a total of 205 kB (!). No wonder the site is slow.
- Take a look on the module list which is sorted by number of installations by default. The things you want are most likely in the beginning of this list.
- Use URL aliases for every post. A node number says nothing and it’s a clear loss of Google juice.
- CKEditor allows the insertion of a DIV container, for which, among others, the language direction can be chosen. This is a great thing for Hebrew, Arabic and other right-to-left languages.
- Drupal’s taxonomy is hierarchical, so the site’s hierarchy can be implemented by setting up a hierarchy of terms within a certain vocabulary, and then tag nodes (pages) in order to place them in the menu hierarchy.
- Flush the entire cache every now and then when changing things.
- The administrative menu gets less quirky as time goes by. Go figure.
- Structure > Blocks is where blocks are added to or removed from the site globally.
- Special pages are best done as Panels. Note that a panel page is just like a normal page with all the blocks around it.
- Special note to self: I’ve hacked modules/system/html.tpl.php (see below). A Drupal upgrade will require rehacking.
Milestones in setting up the site:
- Enable clean URLs
- Enable book module
- Installing a rich text editor (duh…). I went for the classic WYSIWYG module (see below)
- Remove the “powered by Drupal” footer (with all due respect)
- Themes go to tar -xzf in sites/all/themes. Switch themes through Appearance (not any submenu)
- Downloaded and installed (tar -xzf in sites/all/modules) pathauto, Views, Taxonomy Menu, (
CCKis part of Drupal 7), Administration Menu,IMCE(image uploader, I’ll do that manually), Backup and Migrate, and Panels. Ctools was installed as well for Panels. Same goes with Token for pathauto. And then devel. And Disable messages. (Page Title was downloaded but not used to, since it’s great for everything except what I needed: Set the title from a within a view. It’s maybe possible, but I couldn’t figure out how). Views PHP (dev version!) for setting up page title (see below). - And then enabled the modules, of course.
- Set up cron (run once an hour). I got a lot of “access denied” in the beginning, and then I realized that I should get the link with the cron key under Reports > Status Reports. And then I found out that cron.php denies access when in maintenance mode. So start the cron thing only when the site goes online.
Another thing about cron is that my hosting provider seems to block Curl from running cron jobs with a silly check on the user agent. My updated cron job command hence goes: curl –silent –compressed -A ‘My cronjob’ ‘http://example.com/cron.php?cron_key=(the key supplied on the status page)’ - Set the default page: Configuration > System > Site Information
- Enable statistics: Modules > List > Statistics > Configure. Set to never delete log info (I don’t expect massive traffic).
- Disable Taxonomy term pages for users (see below). Same with node-by-number.
- Ask web host to increase RAM limit (they gave me 128MB, which is OK)
- Enable the “Disable messages” module and configure it to display error messages to admins only (why isn’t this in the core?). This is done by setting permissions (the existence of the module creates new relevant entries). There is no need to configure the module further.
- Edit public_html/sites/all/modules/ctools/includes/cleanstring.inc and replace “\x{d800}” with “\x{e000}” in the expression for CTOOLS_PREG_CLASS_ALNUM. 0xd800 is apparently not a legal Unicode point, and without this change there’s a warning saying exactly that: “Warning: preg_match(): Compilation failed: disallowed Unicode code point (>= 0xd800 && <= 0xdfff) at offset 1811 in ctools_cleanstring() (line 157 of /home/theuser/public_html/sites/all/modules/ctools/includes/cleanstring.inc).”
- Edit sites/all/themes/arthemia/template.php and change arthemia_primary() at the beginning to read
function arthemia_primary() { $output = '<div id="page-bar">'; $the_menu_tree = menu_tree(variable_get('menu_main_links_source','main-menu')); $output .= drupal_render($the_menu_tree); $output .= '</div>'; return $output; }
Originally, drupal_render was called with the return value of menu_tree(), an a strict warning is issued about calling a function expecting a reference with a non-reference. Or something.
- April 2018 update: Patch Drupal against this arbitrary code execution exploit (which, BTW, was relevant for current Drupal versions as well. Just being up to date wouldn’t have helped against this one).
Installing the WYSIWYG module
Spoiler: The clear winners are CKEditor and NicEdit. CKEditor because it has the nicest features, but for some reason it has its own spell checked which contacts a dictionary over the web rather than using the browser’s spell checking. And hence it’s disabled by default. It doesn’t make sense to tell the world what you’re typing as a default setting.
- Downloaded from here.
- tar -xzf at sites/all/modules/.
- Created a “libraries” directory under sites/all (why wasn’t it already there?)
- Downloaded CKEditor and did tar -xzf at the “libraries” just created. Be sure that CKEditor wasn’t released after Drupal, because it may not install, and the message “The version of CKEditor could not be detected” will appear at “Wysiwyg profiles”
- Downloaded NicEdit (default configuration), created a “nicedit” directory under “libraries” and unzipped the file there.
- Downloaded YUI, and unzipped it directly on “libraries”
- On web interface menu: Configuration > Text Formats > Add Text format. Add a new text format, e.g. NicEdit and set it for use only for admins (for example).
- Then on web interface menu: Configuration > Wysiwyg profiles assign NicEdit text format to NicEdit editor
- Then on web interface menu: Configuration > Wysiwyg profiles > edit NicEdit > Buttons and plugins and check all checkboxes (TAB and space bar came handy). Or the rich edit box looks like just a plain text box. Why this extra step was necessary is pretty much beyond me.
- Same procedure for other editors.
Setting up a taxonomy menu structure
The sequence below is based upon the Administration Menu module (things may be found in other places using the core interface):
- Create a new menu: Structure > Menus > Add Menu
- Create a new vocabulary: Structure > Taxonomy > Add Vocabulary.
- Generate a few terms in the new vocabulary
- Edit the new vocabulary. Under “Taxonomy menu” pick the the new menu, and check the “Select to rebuild the menu on submit” checkbox. This copies the taxonomy items into the menu (not very sophisticated, is it).
- Now on Structure > Blocks > { your chosen theme } put the menu somewhere. Or more precisely, find the new menu in the list, and assign it a point of appearance. Don’t forget to submit the form.
- To use the menu items as top-page tabs, go to Structure > Menus > Settings and set the source as the new menu
Note that new vocabulary items don’t appear automatically on the menu, and it’s not a matter of flushing the cache or running cron. The menus need to be updated by rebuilding them as mentioned above.
So the bottom line is that I tend to trash the Taxonomy menu and use the book structure.
Tagging pages
- Go to Structure > Content Type > { The content type to alter } > Manage Fields
- Add a new field of type “Term Reference” and select any of the widgets offered.
- Click Save settings
- On the next page, you’ll be asked to choose the vocabulary to use. Save this as well.
- On the next page set up the number of entries allowed (unlimited?) and default tag.
- You may want to hide this field in the display (if it’s for internal uses): Structure > Content Types > { The content type to alter } > Manage Display and set both label and format to hidden. Be sure to apply this to all view modes, full content in particular.
Custom styling for panes
When the GUI tools don’t do the job, editing the theme’s main CSS file does (or a local.css file in the theme directory, but yet another CSS file?). Then, in the content editing page where the panes appear, pick the inner gear menu > CSS Properties and enter a new class name, say mypane-class. In the CSS file setting the attributes for a header within the pane will look like
.mypane-class h2 { font: Arial, Helvetica, sans-serif; font-weight: bold; font-size: 14px; }
Allowing injected Javascript
Full HTML actually allows Javascript, only it wraps it with CDATA. Which could have been forgiveable, had it done that correctly, and not killed the script on some browsers. The really annoying thing about this is that the purpose of this CDATA statement is merely to silence XHTML validators.
The trick is simple, and explained in a video (I prefer things written down, but anyhow). The idea is to create a new input format. The way Drupal works, it filters the content of the database during page display (the input goes in as is), so the idea is to create a new filter which does nothing. So what is in the database is shown. Not the safest thing in the world for general practice, but sometimes there’s no choice.
Basically, go to the modules list, find “Filter” and click its “configure”. Pick “add text format”, name it “Unfiltered” (or something), make sure none of the filters is checked and that only the administrator has access to this format. That’s it. Now whatever goes in, goes out. Use this format, enter HTML with Javascript and whatever.
Removing the navigation links at the bottom of a book page
As suggested here, don’t edit the original PHP code generating the links, but rather copy /public_html/modules/book/book-navigation.tpl.php to the theme’s directory, edit the copy, and flush the caches.
To retain the links in the lower hierarchy, but remove the navigation links, simply change
<?php if ($has_links): ?>
to
<?php if (0): /* ($has_links): */ ?>
(deleting code is for barbarians)
Disallow access to taxonomy pages
There may be an elegant way to do this with Drupal’s own interface, but I’m yet to discover it. So the trick is to create a custom page, and make it empty. Silly, but it works.
Under Views, clone the view which emulates the core’s taxonomy display (it’s name is simply “Taxonomy”). Add a header, saying whatever you want, which is active even when no items match (who cares). This is merely so you know it’s not the default page you’re watching.
Then set an access rule, saying only admins are allowed: Access > Role > Check administrator.
To get the same effect with nodes, do something similar for node/%. Don’t clone the taxonomy view, since they display taxonomy, and sometimes a page needs to be displayed by node (for admin purposes).
Setting the page title hack
Goal: Set up the page title (the one within <title> tags) based upon the title of a content entry within a view.
I should mention, that what I present here is considered very wrong, in particular because it involves hacking a Drupal core PHP file. But after trying to reach an elegant solution and asking for help, I gave up for something that is ugly but works.
This is the ugly part: modify modules/system/html.tpl.php so that the part saying
<title><?php print $head_title; ?></title>
becomes
<title><?php if (isset($GLOBALS['head_title_override'])) { print $GLOBALS['head_title_override'] ; } else { print $head_title; } ?></title>
While I am ashamed of hacking something under “modules/system”, the usage of PHP global variables may be adequate here, even though I’m sure there are more Drupalish ways to accomplish the same. The advantage of a global variable is that it’s easy to set from any execution context.
Having installed and enabled the “Views PHP” module, there’s now a Global: PHP field. It allows access to the data of fields previously fetched, so having the “title” field already in the list, it’s just
$GLOBALS['head_title_override'] = $row->title;
in the “Value code” window. Note that the available variables are listed just below the window. And this should be excluded from display, of course.
Careful with the PHP: If it’s syntactically wrong, the views edit page may be impossible to reach, so the only way to get out is deleting the view. Disabling auto preview may reduce the risk for this.
Breadcrumbs on Arthemia
For a reason which was beyond me, no breadcrumbs appeared in on my pages. And I ran Arthemia. Until I found the solution here. There’s a bug in Arthemia’s template.php, so
function arthemia_breadcrumb($breadcrumb) {
if (count($breadcrumb) > 1) {
return '<div>'. implode(' › ', $breadcrumb) .'</div>';
}
}
should be replaced with
function arthemia_breadcrumb($breadcrumb) {
if (count($breadcrumb["breadcrumb"]) > 1) {
return '<div>'. implode(' › ', $breadcrumb["breadcrumb"]) .'</div>';
}
}
Looks like the calling convention changed on Drupal 7, but nobody paid attention… This page says a few words about changes in Drupal 7.
Making a local mirror of a site
First, make a copy of the files, of course. Then make a local copy by using a mysqldump backup. Basically, generate the data base with
CREATE DATABASE delme_mirror
from mysql prompt, and then from shell:
mysql -D delme_mirror < databasedump
This can take a few minutes…
Now, allow write-enable on sites/default, make a copy of settings.php within this directory, and make it writable.
Then change the database setting (maybe copy the remote site’s?) so it says something like
$databases = array ( 'default' => array ( 'default' => array ( 'database' => 'delme_xillybus', 'username' => 'username', 'password' => 'password', 'host' => 'localhost', 'port' => '', 'driver' => 'mysql', 'prefix' => '', ), ), );
Well, I think this is the thing to do. I didn’t manage to run this, because Drupal went “Fatal error: Undefined class constant ‘MYSQL_ATTR_USE_BUFFERED_QUERY’” which appears to be a PHP version issue (only cutting edge PHP for Drupal, it seems).
Themes
These are my very shallow impressions of a few selected themes I checked up for a hi-tec site. I checked with Firefox 3.6 and IE6 to get a wide range of compatibility issues.
- 0-point: Beautiful and sleek on Firefox, complete disaster on IE6.
- Aqua Marina: Not bad, and survived IE6 test fairly OK, but still pretty bad. Doesn’t have a hi-tec look, though.
- Danblog: Simple & to-the-face design pretty suitable for a hi-tec site, but looks a bit too simple maybe. Survived the IE6 test very well (no differences).
- Danland: Same impression as Danblog. The differences are possibly deeper in.
- Fusion was obviously not intended to be used out of the box.
- Garland looks great, and not so bad on IE6 (resize issues on the latter). Not really a hi-tec look (top region should be bright)
Views
I wrote a separate post on this.
SQL command for strings search in all pages
This is in particular useful for updating links.
It boils down to this:
SELECT entity_id, alias FROM field_data_body LEFT JOIN url_alias ON source=CONCAT('node/', entity_id) WHERE body_value LIKE '%string-to-search%' ORDER BY entity_id;
And then access the page with the URL like e.g. https://thesite.com/node/114 or use the alias as the path instead (if such exists).
Reader Comments
I have to admit I am a little confused on why we need so many different ways to create a website. It seems like a lot of work for some differences that may not be worth the time invested.
I do agree with this that there must be a single way to create web site and post articles.It should be made very convenient and easy for users.
I’ve just had my drupal interface tell me I need to update ‘manually’ from 7.0 to 7.2. Does anyone know how to do this?
Careful with the PHP: If it’s syntactically wrong, the views edit page may be impossible to reach, so the only way to get out is deleting the view. Disabling auto preview may reduce the risk for this.
I am a little confused on why we need so many different ways to create a website
Aqua Marina: Not bad, and survived IE6 test fairly OK, but still pretty bad. Doesn’t have a hi-tec look, though.
than you very much for you useful information.
I’ve just had my drupal interface tell me I need to update ‘manually’ from 7.0 to 7.2. Does anyone know how to do this?
Wow! This can be one particular of the most beneficial blogs We’ve ever arrive across on this subject. Basically Excellent. I am also an expert in this topic so I can understand your effort.
you should not hack core : copy html.tpl.php to your theme folder, flush caches and edit it.
Never enable php module fo security reasons, there is always a way to put our code; and its far easier to debug than php in a node.
The module nodewords may do what you want with your title attributes in head. Maybe this hook could also do the trick http://api.drupal.org/api/drupal/modules!system!system.api.php/function/hook_html_head_alter/7
these content which i looking for this time
i have intention to reformat into drupal
thanks mate