Development Tips

Here are some of the "tricky" ways I've manipulated Drupal to get the job done, without resorting to custom modules or theming.


Custom Menus (tabs)

The menus module in Drupal core allows you to manipulate the system menus through the admin GUI interface (admin >> build >> menus)

However, it does not give you control over at least two key aspects of the menu:

  1. Access control - does not allow any specification of who can access the menu item;
  2. Tabbed menu - not possible to add or edit tab-style (local task) menu items;

These can be controlled if the menu is built programmatically.  For these reasons, I created a custom lasqueti menu module (lasqueti_menu).  This module does the following:

  • Creates the menu items for this Design Notes book, and restricts access to only those who have 'access administration pages' privleges.   Otherwise the Design Notes can either not be placed on a menu, or will show up to authenticated users on the site (in their personal menu - the Navigation menu). 
    An alternative would be to use the "menu-per-role" module, but this seemed overkill for hiding one book, and the module requires a core "hack", so not nicely maintainable.
  • Creates the "tabbed" menu pages under the Primary Menu tabs.  The module does two things of interest:
    1. creates the basic structure of the tabbed menu system;
    2. handle display of single node pages that appear on tabs, where required.
    3. handle display of teaser views that appear on tabs, where required.

See the following pages for more information about working with and maintaining these tabbed menus.


Conceptual Overview

The idea behind tabbed navigation is to provide the user with a spatial orientation to the context of the page they are viewing.  The tabbed layout creates its own, implicit "breadcrumb" by always showing the user exactly where they are in the structure.  Thus, you'll notice that the breadcrumb has been removed from these pages.

The tabbed menus only present information that is available elsewhere on the site.  It is meant as a seperate navigational structure, primarily aimed at users who are new to the site, and simply want to browse around.  Thus, the tabs are organized into "categories of interest" - so users can view all content on the site related to their interests.

To this end, tabs "pull-in" two distinct kinds of data:

  • Individual pages - where relevant, single pages exist, these are displayed in their full form on the tab;
  • View of related teasers - where there are multiple pages on the topic, a view of teasers is presented.

The teaser lists are almost all generated by a single view named "by_category".  This view simply lists teasers for all nodes, using a "Taxonomy:term id" as an argument.  The tabbed menu code supplies the relevant taxonomy terms for the Views argument  when the view is built, to pull-in all the related nodes.   In this way, whenever a new node is added or a the categories of a node are modified, it will automatically show up on the right tabbed page.

When a list of teasers is presented, there is always a "heading" node placed at the top of the list (simply by tagging it with the right categories and making it "sticky").  Although this "heading node" is just a normal node with the title set to the tab title and the body containing an overview of the tab's contents, it is not used as a normal node, and should not appear in any other displays (I hope!).   Some special logic was added to template.php and node.tpl.php to handle this node, but ultimately, these may need to be stored in a special node type so their display in other lists can be contolled more easily.  An alternate implementation would be to display the heading node explicitly during _display_view in the custom tabs module.  This way those nodes could be controlled very precisely.

Farmer's Market

Pages in the Farmer's Market, with their associated produce lists, represent a fairly complex set of inter-relations.  Understanding how the various node types, cck fields, categories, and views fit together will take some time.  However, setting up and maintaining a Farmer's Market page is not hard, but you need to be quite careful to get the relationships right:

  • Add a new term to the "Lasqueti Market" category  for the new producer.
    ** This term must be the same as the path of the Market page (case insensitive). 
    These terms are used to create the Farmer's Market (market_products view), listing products for each farm - it shows a list of available products tagged with each term.
  • Add a new Market Page for the new producer.
    ** This must be a Market Page so that the "mini-gallery" (created by template.php using the product_gallery view) can be attached . 
    ** The page must be tagged with Topic category term "Farmer's Market".
    ** The URL path for this page must be the same as the Lasqueti Market category term (case insensitive).  This allows Taxonomy Redirect to redirect links from the category term directly to the page (since the term name and the page's URL path are the same).

Thus, a "Famer's Market page" is a Market Page, tagged with Topic "Farmer's Market, with the same URL path as a term in the Lasqueti Market category.  These rules are used to identify these pages in the code - so pages that don't adhere will not be considered part of the Farmer's Market, and won't work correctly.  This is a little sketchy, perhaps even a bit hacky, and limits the re-use of the Product node type ouside the Farmer's Market - but it was expedient, and seemed cleaner than creating a new node type or yet another taxonomy.  Although the Topic category is used to identify Farmer's Market pages,  the Lasquti Market term and URL path still need to be identical for Taxonomy Redirect to work.
The Author of a correctly configured Farmer's Market page will see two new tabs on their page: 

  • Edit Product List
    This shows the my_products view that allows the author to edit, delete, and change the availability of their produce.
  • Add Product
    This is simply a short-cut to the Add Product form.

These two tabs are created by the custom Lasqueti Menu module - they are "dynamic" local menu items.  It is important to note that only the page author will see these tabs, so once the admin gives authorship over to another user, they won't see these tabs anymore.  I could not figure out how to make this work so admin always sees all.

There are three distinct "Product List" views:

  • market_products view is used to display the "products-by-producer" lists on the Farmer's Market page.  The most staightforward way to create this view was by using a taxonomy (since I already had a module to list nodes-by-term).  This is why each product must be tagged with the correct "Lasqueti Market" category.  The alternative would be some custom code that first finds all Farmer's Market pages, then, for each one, selects all product nodes that have a node reference to that page.  This will be quite a bit slower, and represents a significant effort - thus I adopted the taxonomy route because it was easy to implement, expedient, and efficient.  Note that this view does not use the node reference field at all!
  • product_gallery view is used to display a list of products related to a given producer, in their Market Page's mini-gallery.  Again, I already had the code to produce a mini-gallery using a node reference.  In this case, using the node refernce was the expedient and effiecient way to generate the view, because you already have the Market Page node itself (it is the one being displayed!).   It would be possible to use the taxonomy term (which is the same as the Market Page title, remember!) to create this view, using the term as an argument passed into the view.  That would eliminate the need for the node reference field in the Product node.  Hmmm... seems like a reasonable idea now that I think of it - but that would mean the Product node would lose its "This product is related to...." link - although the Market page would still be linked from the product via the taxonomy term and Taxonomy Redirect.   Perhaps worth investigating to simplify things a bit.
  • my_products view is used to display a list of products authored by an individual, and is shown on the "Edit Product List" tab for Farmer's Market pages.   This could be confusing if one person is "owner" of multiple Market pages, because I could not find a simple way to filter the products by the node being viewed (since I don't have that context).   I suspect this will be possible with Views2.  For now, this lists all of a user's products, regardless of which page they relate to.

The upshot?
When user's create a new product,  they need to select both the correct Lasqueti Market taxonomy (so the product is listed correctly in the Farmer's Market) and the correct Market Page node reference (so the product is added to their mini-gallery).  The node reference selector uses the user_pages view to restict them to selecting references to only pages they own.  This is good because it avoids confusion and mistakes, but it is bad because it means the admin cannot create these node reference links without first "masquarading" as the author of the page.  The Lasqueti Market category terms would be more difficult to restrict in this way, so they are open, and thus prone to error.
This reliance on authorship for a number of the functions (e.g., edit tab availablitity, node editing access, node reference list, etc.) also implies that only one person can manage a given market page.  It is certainly possible to set-up group access and do things based on groups rather than author, but there would be a lot of overhead (and extra work!).  An easy workaround would be to create a group ID for the website that all members of the group could use to update the shared resource.