Drupal 6 Related Content

Submitted by tomo on January 24, 2013 - 11:09pm

Similar Entries 2 (6.2) - http://drupal.org/project/similar - doesn't work. But version 1 works like a charm. Version 2 spits up an error on array_filter. Looking at the code, my guess is it's related to some new Views plugin code in version 2.

Related Block - http://drupal.org/project/related_block - would have been cool too. It's much like Similar Entries. Unfortunately, the search algorithm is way too narrow. At first, I couldn't tell if the module was even working. Then by weening the search terms down to 1 (which means it figures out a single relevant term and then searches for only that) I saw some results, but not on many nodes still.

Relevant Content - http://drupal.org/project/relevant_content - is nice in theory. Currently, it's broken. It's in the middle of a rewrite, but it's looking more and more unlikely that it will ever get rewritten.

Related links - http://drupal.org/project/relatedlinks - is not what it seems. It just finds any referenced links in the content and groups them together. Nothing external.

Other modules are term (taxonomy) based. But ideally, you don't need to specify all the relevant terms, and you don't need to explicitly say that two terms are related. There should be a more intelligent way.

Drupal vs Node.js or Drupal + Node.js

Submitted by tomo on December 25, 2012 - 4:01pm

What do Drupal and Node.js have in common? Besides the word "node" not much. They are both ways to do web development. Drupal is for building websites centered around managing, creating, and viewing mixed types of content. Node.js is optimized for near real-time updates in browsers connected for long periods of time to a website.

Drupal is software that runs PHP on top of a web server. It can run on Apache or nginx or other web servers. But it needs a web server to handle listening on a TCP connection and communicating with connected clients (browsers). Node.js, on the other hand, doesn't need an underlying web server because you can easily write a fast, basic web server using Node. Drupal is limited by the speed of PHP and the (most likely MySQL) database that is returning hundreds of queries per page load, and then limited further by the speed at which the web server can serve the data Drupal returns. Node.js can serve a page as quickly as it takes to run any JavaScript function.

Node.js is therefore much lower level than Drupal. Node.js can be the basis for writing scalable, responsive, real-time, single-page web apps. But it won't help you rapidly build any features used on the website. It won't serve as very expressive or patterned scaffolding for any advanced site structure, or help manage more (Drupal) nodes than you can count on your hands. Node doesn't have the breadth of third party web features that makes modern websites social, play nicely with thousands of APIs, or conduct e-commerce. Node.js isn't a web framework, nor a CMS. It's something very different.

Node.js is a framework for programming network servers. Node.js is also the only remaining mainstream way to run server-side JavaScript (others exist but never gained any following, perhaps because without V8 they were too slow or the idea was too ahead of its time). That may not be reason enough for most people to switch to Node, but for some people who perhaps want to share client-side and server-side code or really like JavaScript (because, well, PHP sucks!) then you might still want to use Node even without using it for its networking/events libraries. Those coming from a Python or Ruby on Rails background will see some similar ideas related to event-driven programming.

Why would you want to integrate some Node.js into your Drupal site? Here are some possible use cases

Dashboard: View realtime stats about your site, maybe from hits to your web server's access log. Think Google Analytics realtime view. The benefits increase the more people you have concurrently viewing the dashboard, and multiply when you allow changes to the dashboard that need to propagate out to all viewers with the dashboard open.

Chat: This is the most common example for Node.js. Chat servers need to support many open connections from different users and then update a lot of them when a message is received from one client. And these updates should happen quickly. Some chat protocols even show what the other person is typing as they're typing.

Multiplayer games: Think MMORPG. Games that are played on a server need to be as realtime as possible otherwise you get problems where different players see different versions of the game world. The server needs to be able to serve many simultaneous connections without taking up ever more server resources, CPU or RAM.

Group buying platforms where buyers need to be updated when the number of other buyers goes up. This also applies when resources are limited and shoppers need to know when inventory or availability decreases.

Why do those kinds of projects make sense with Node? They all benefit from high performance despite massive concurrency, realtime or really fast feedback, and the paradigm of event-driven programming on the backend with JavaScript just like in the browser. At least partly it has to do with Websocket in HTML5. Before Websocket, we had to use the hack-ish Comet or long-polling with ajax, but Websocket is the solution that was expressly designed for bidirectional network connections between browser and server. Of course it also has to do with the speed of the V8 JavaScript engine.

So how might we integrate our Node project into our Drupal site? Fortunately there's a module for that: https://drupal.org/project/nodejs

The module uses an independently installed Node.js server that you configure the module to use. Then you have some secret keys set up for the Node server and Drupal to securely communicate with each other. The module comes with some sub-modules with Node servers that can do things like Node-based notifications to Drupal sites and the browsers connected to them. Whatever message you want to broadcast to browsers can be done this way and the browsers can receive them instantly. This could be an actual text message or prices or scores to be updated or whatever data you might want to change in an existing session. And of course the Node server can listen for updates sent from browsers.

In conclusion, Node.js and Drupal are both web technologies with extremely different use cases but which can also work together for both content-ful and massively interactive websites/web apps. Drupal alone has no chance of doing realtime. By itself, Node.js for a blog or ecommerce site would be like programming games in assembly.

JavaScript as a serious programming language?

Unbeknownst to many folks, even those developing websites, JavaScript libraries are hot right now. One reason is that they're being used on both the frontend (browser) as well as the server via Node.js. And so Drupal 8 includes two new JavaScript libraries, beyond the mainstay of jQuery, which are popular because they rewrite how we use JavaScript, much like Drupal changes how we develop PHP software. They are the Backbone.js and Underscore.js JavaScript frameworks. Since they're in core, Drupal itself can use them in its own JavaScript code. However, as far as I can tell nothing in core, besides Backbone, is using Underscore yet.

Backbone.js (http://backbonejs.org/) gives structure to web applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing API over a RESTful JSON interface.

The cool thing about Backbone is it splits the abstract representation from DOM events and HTML rendering in your JavaScript code. This is especially applicable to web apps which constantly get new data via AJAX from a REST server and then update the browser in-page rather than reloading a new URL and rendering the page's html on the server - for example via Drupal and it's normal theme/template system.

If you think of modern web applications like GMail or Trello (which is built on Backbone) they work mostly by not reloading the page but rather with each click of the mouse pulling in data from the server then rendering it somehow in the current page. Backbone is how Rdio, Hulu, and Pitchfork play music and videos continuously across "page loads". This can also be happening in the background independent of user activity to update content or display status messages or maybe show new email.


In Drupal, you'll see a lot of references to AHAH. AHAH is basically AJAX except that it's honest about the X, which in AJAX stands for XML, but in Drupal using AHAH it's actual HTML which can be inserted into a page. Or it could be JavaScriptON that's parsed and, using some custom JavaScript logic, turned into HTML by manipulating the DOM.

Without something like Backbone, this is how AJAXy applications are written in Drupal. We add in #ahah hooks that form elements and their widgets can use (when JavaScript is available.) But the login on the frontend is completely custom and usually is jQuery $.ajax callbacks that use jQuery selectors to find and replace DOM elements manually.

Backbone.js gives us a framework to represent things we want to update on the frontend in a structured way, with clear separation between the model and rendering. The model language directly maps to the MVC of Ruby on Rails. Then by updating the model, which is all the logic we really want, the visual representation is updated for us. Backbone can call Underscore templates, Mustache.js, or directly insert into the DOM server-side rendered (the old way we just mentioned) HTML.

So now our AHAH callbacks can return JSON that's pure data, and allow Backbone to handle rendering the HTML.

So what about Underscore.js?

Backbone itself depends on Underscore, but Underscore by itself is also useful. For example, see how Conway's Game of Life can be implemented in JavaScript without if-statements or loops (for, for-in, while) by using Underscore.js and by programming in a more functional style, with functionality similar to Ruby or Python. jQuery, long since included in Drupal core, also offers some functions like $.map or $.each but Underscore is much more complete. Underscore is a JavaScript utility library, not for writing any specific kinds of apps but for making all of your JavaScript code potentially cleaner, simpler, shorter.

Some _ functions:

Underscore also has some array and object helper functions, deep === comparison (isEqual), etc. See it all at http://documentcloud.github.com/underscore/

You can play around with Underscore.js right now by writing up some code at http://jsfiddle.net/

Views in Drupal 8 Core

Submitted by tomo on December 17, 2012 - 11:30am

With Views now in Drupal core as of D8 the two most common basic contrib modules from previous versions of Drupal, CCK and Views, are now both part of core.

CCK, now called Entities, from one perspective is what allows us to create arbitrary database tables through a web interface where we can hold arbitrary data yet work with it through a common interface, and use Drupal goodies like widgets, theming, content creation forms and pages, etc. on them. Views is the complement to this way of creating custom content. Views in core means we can now retrieve or query that arbitrary, custom content in arbitrary and custom ways.

Views is basically a web UI for an SQL query builder. The fields are the SELECTed database columns and the filters are your WHERE clause.

This isn't just a feature for non-technical dudes and non-developers. Just because you can write SQL queries doesn't mean you should write all of them. Views gives you an interface into various Drupal core and contributed modules and the content they manage, if those modules integrate with Views via hooks. Entities (or CCK) can create a mess of database tables. Sometimes these tables will change structure from under your feet due to some changes via the admin interface. You might not know until your code is broken. But using Views, the query will always be up to date.

Now that Views is in core, other parts of core could possibly depend on and build on Views, just like many other parts of Drupal core use concepts that came from Entities (CCK). So Drupal core can do a lot more out of the box. And contributed modules can be written to depend on only Entity and Views, which are part of core, and so these new modules won't have any other 3rd party dependencies. That's a win for module developers.

Fatal error: Call to undefined function: block_list()

Submitted by tomo on December 17, 2012 - 11:28am

On a Drupal 6 site where I had copied over a database to be used with a freshly checked out tree, I suddenly got this fatal error which stopped any page from loading:

Fatal error: Call to undefined function: block_list() in .../theme.inc on line 935

I'm not sure how it happens. And even after it happens, it's not always immediately a problem. It can be a problem that manifests itself when migrating or copying a database from one site to another. And for some reason, the exact same database worked on another site.

In my case, the problem was the filenames for some core modules and themes and you can see if that's your problem by running this query:

SELECT count(*) FROM system WHERE filename LIKE '%modules/modules%' OR filename LIKE '%themes/themes%';

If that returns anything (like a filename like 'modules/modules/block/block.module') then you have a problem which you can fix by running:

UPDATE system SET filename = replace(filename, 'themes/themes', 'themes');
UPDATE system SET filename = replace(filename, 'modules/modules', 'modules');

Before Drupal 8: Background

In older versions of Drupal, a lot of "developing" a Drupal site was more clicking around in admin pages rather than writing PHP code in files. This was also Drupal's strength in that non-developers could and developers alike could create powerful and expressive features through a web interface. The downside of this is that changes weren't tracked and there was no way to revert changes - something common and easy to do with any code in a source control system.

Drupalists came up with various solutions. For some major contributed modules like Views and CCK it was possible to export and import views and content types. It was also later possible to package up some changes in some more modules into Features using the Features module and API. But many modules didn't use any API and just haphazardly wrote their configurations to various database tables. To track these and be able to push changes out to other Drupal installations one had to write code in hook_update steps to upgrade the database. This was prone to error as it was being written manually.

And so most Drupal sites were staged and then pushed out to production via database dumps and restorations. Unfortunately, there's no clear separation between configuration and content in a Drupal database. And there's no common way to export, push, and import nodes or any other content from a development site to a production site or vice versa.

With Drupal 8 there is now a solution. Now all configuration that goes through the core configuration API will be written to the database but also to regularly named configuration files in YAML format (not XML as some documentation still mentions). So you can now put the directory containing your configuration into git or svn or whatever. Then you can use your version control to revert configuration changes! And pushing Drupal's configuration changes is simply a matter of committing the automatically generated config files and then updating on the receiving end. Once updated config files are in the right directory they can be synced via the admin interface which shows you a list of changed config files.

How does the new Drupal 8 configuration API work?

Some pertinent background files:

core/includes/config.inc: This is the API for configuration storage.

sites/default/default.settings.php: (from the comments)
+ * By default, Drupal configuration files are stored in a randomly named
+ * directory under the default public files path. On install the
+ * named directory is created in the default files directory. For enhanced
+ * security, you may set this variable to a location outside your docroot.

The following is the directory that was automatically created by installation but you can (and probably should) move it to another location, above the web root, and set it in settings.php.

sites/default/files/config_dd-NwbWruIxwygcszFOmRMZgufouo9QDGaG9UufzfxU/staging: (This is in the secret, private, randomly-named directory created by installation whose name is stored in your settings file which should not be readable by anyone else. The directory name there will not be the same on your own installation.)

This directory contains configuration to be imported into your Drupal site. To make this configuration active, see admin/config/development/sync. For information about deploying configuration between servers, see http://drupal.org/documentation/administer/config

sites/default/files/config_dd-NwbWruIxwygcszFOmRMZgufouo9QDGaG9UufzfxU/active/book.settings.yml (same as the file in core/modules/book/config):

Here's what the YAML looks like:

  - book
    mode: 'all pages'
child_type: book

And then this file:

                    ^^^ unreadable          ^^ random, with randomly named PHP class

As noted, "sites/default/files/php/" is not readable.

Instructions on using the configuration API

On your development server, perform whatever configuration changes are needed through the UI. Create Views, check checkboxes, etc. These changes will get written to *both* the database table *and* the file system so the two are in sync (it will also re-generate the digital signatures of the underlying files).

When finished with your edits, review the changes in the config directory with $vcs diff (or your tool of choice) to confirm they look as expected.

If everything looks good, move the changed files to your production server in the usual way (SFTP, $vcs add/commit/push, $vcs update/pull). Nothing will immediately change, as your site will still be reading from the active store.

Finally, go to admin/configuration/system/config or run drush config-update (note: final location/command likely different; making these up right now). This will outline the files that have changed. If the changes seem good, go ahead and confirm to overwrite the content of the active store with the on-disk configuration. The admin tool will offer to regenerate the file signatures if necessary.

So you use the web interface to make configuration changes as you always did. But now those changes will also be written out to disk where you can keep track of changes using git or subversion or whatever VCS you use. Every Drupal 8 module should load and save configuration through the new API and so we get these YAML-format human-readable configuration files for free.

I develop on my MacBook Pro and when building Drupal 6 sites, I had to run PHP 5.2 because there were many conflicts in Drupal 6 core and contributed modules which meant running on PHP 5.3 either threw up errors or didn't run properly. Since I run XAMPP for Mac OS X, I also run phpswitch which lets me switch from XAMPP using PHP 5.2 to PHP 5.3 and back.

Unfortunately, Drupal 8 not only requires PHP 5.3 but PHP 5.3.5 or higher. Drupal 7 ran fine on PHP 5.2.5 or higher with PHP 5.3 recommended.

1) XAMPP Mac OS X 1.7.3 comes with: Apache 2.2.14, MySQL 5.1.44, PHP 5.3.1.

Read the rest of this article...

Say you have a bunch of blocks and you want them to be displayed on certain nodes of varying content type based on some criteria like the content type and some CCK fields or taxonomy. You can't do this with the stock block visibility settings without writing custom PHP code.

But we can implement it using some existing basic Drupal building blocks: CCK and Views

1. Create a content type called Visibility Block.

You might have a field for content type where the possible values are returned from code which returns an array of the content types (using function node_get_types()).

2. Then for any fields you want to match, you'll have the same fields in this content type. For example, if one of your content types has a textfield and the possible values are 1, 2, 3, then do the same for Visibility Block.

When you create a Visibility Block, you'll have your block content in the body as normal (optionally you could use Block Reference and create blocks like usual and then link to them in the node instead, but I see no point in the extra effort and redirection), then select the conditions for the pseudo-block being visible.

3. Now create a view called Visibility Blocks Viewed. You'll create block displays, one for each content type that you have a Visibility Block set for which may only be one or two of your c-types.

Create an overridden argument each block display for the content type -field- in Visibility Block. You want to match the content type of the viewed node with the field in the Visibility Block, which are not the same type of thing. So you'll need to convert the argument in code.

You'll call menu_get_object() to get the $node because it's better than "$node = node_load(arg(1));". For the chosen c-type for that block display you will check that the implied node's c-type is what ever type you want to show in this block display because you will also check any fields that are specific to this c-type. Use PHP to supply a value since no argument will be passed in, and have the code load the current node and return the type. Then use PHP for the Validator Options and if the c-type doesn't match then you will display empty text. If you have multiple c-types which share CCK fields then you can put them into a single block display.

4. For each content type, in the chosen block display you will create a new argument for each compared against CCK field. You will pick a field from V-block and then use PHP to return a default value of the currently viewed node's field's value. You won't need to do Validation on these arguments.

5. Finally, you may want to limit the number of nodes returned, maybe just one. Now give this block a title and save it and configure its region in the normal block admin.


Why not the normal block visibility settings?

Because there you can't even configure by content type (anymore in D6). You can configure by path glob and by PHP code which overrides the path glob field (including in the database).

So under "Page specific visibility settings", set to "Show if the following PHP code returns TRUE (PHP-mode, experts only).", the field is blocks.pages. Essentially, PHP code works by overriding the pages list.

Why not use Block Page Visibility?

Block Page Visibility (http://drupal.org/project/bpv) enables site developers to centralize the display of blocks to a single PHP function. It is an alternative to controlling display via each block's configure form. The more "sometimes on, sometimes off blocks" that a site uses, the more useful this module becomes.

This takes over the visibility settings of all your blocks by calling:

$sql = 'UPDATE blocks SET visibility = 2, pages = CONCAT("<", "?", "php ", "return bpv_is_visible(\'", module, "-", delta, "\'); ", "?", ">") WHERE status=1 AND theme=\'%s\'';

Sometimes it's easier to configure a block by just whether you're logged in, or whether you're on the front page.

This module doesn't give you any finer grained controls. And you have to configure every block in code. You also lose all your current block visibility settings once you install this module. To use this module you have to implement your own bpv_config or bpv_configuration (I think it's a bug that it's looking for bpv_configuration but actually uses bpv_config).

Taxonomy is normally pretty simple by default except that it's also called vocabulary (but never terminology although the tags are called terms) and that it can be attached to nodes as fields (using Content Taxonomy Fields to make CCK fields which gives you a bit more control) or not, or both.

Adding language makes it complicated though. Drupal can be said to support languages other than English, multiple-language sites, internationalization and translation. But it's not always user friendly or clear even to developers. Such is the case with taxonomies.

Let's say you have a site that's in two languages, English and Vietnamese. You have translated the interface of the site as well as nodes so that URLs are consistent. To switch language you just add the language code to the front of the URL. So you have a taxonomy with terms in your site's primary or default language. But you want to use the same terms by ID rather than a different set of terms.

1) Edit the vocabulary. Set "Localize". This doesn't set a language to any terms or anything, they are just assumed to be in the default language already.

[Look in term_data and confirm the language column is still empty.]

2) Refresh strings in Translate Interface. Now if you search taxonomy for a term it should appear.

[Look in locales_source for location = "term:$termid:name" where $termid is the tid of a term in your vocabulary. This means it's ready to be translated. After translating, it should be in localtes_target with the same lid. But the translation column is a blob so you won't be able to see the translation directly depending on your mysql client.]

3) I recommend installing the Translation Table module instead of searching for each new term in the regular translate interface. Translation table shows up as a new tab in the translate interface and you can select a vocabulary to see all of its terms in one place.

4) If you use terms in arguments in URLs you'll need something further. Otherwise, all URLs will use the term in the site's default language.

5) One last thing: Don't use t() to translate a term. Use i18ntaxonomy_translate_term_name on a term object (like if you get a vocabulary object from taxonomy_get_tree).

Before I begin: I'm a Drupal guy. What I say could be construed as being biased. I'll try to be honest though.

When building a website you or your developers have some decisions to make: what language to use, whether to use a framework and which one (depending on language - Zend/CodeIgniter/Symfony/CakePHP for PHP, Ruby on Rails, Django for Python, etc.), whether to use a CMS (WordPress, Joomla, Drupal), whether to self-host or use a blogging service (WordPress.com, Drupal Gardens, Tumblr, Blogger). There is no single right answer.

First, go with the language that is most comfortable. Previously, I had several years experience with both PHP and Python with Python actually being more recent. But few people in Vietnam know Python where many know PHP. But Drupal being in PHP sealed the deal.

Next, is it mostly about managing news-like content? Then go with a blog. Does it need some popular features like user logins and full accounts, social media integration, voting, storing meta-information besides blog text, or otherwise some customization of what kind of content you are storing? Then it's no longer a blog and you should use Drupal. Is it purely ecommerce? Drupal Commerce or Ubercart can do the job, but Magento might be all you need if you are not a developer and as long as you can afford to buy the yearly license fee for it and your website only needs a store of physical items without any other content or custom design.

Do you need something that is more like a web app that's unlike any existing blog, news site, social media site, online store, or corporate website out there? Then maybe you should have a team of developers starting with a web framework (Drupal, as well as being a content management system, is also a content management framework) and start from more basic building blocks.

Some specific use cases:

1) An intranet website for managing some internal corporate data that is really custom to your company. WordPress would not be adequate none of its strong points would apply. Drupal's theming weak points would no longer hurt you here since you just need a professional-looking tool. Best of all Drupal easily gives you and novice users a way to manage your data.

2) Brochure website - like a business card for a store or business with a dozen or so pages of information and some links and a contact form. If you don't already know Drupal then use WordPress. WordPress also has many available commercial themes which can be used. However, a Drupal expert can just as quickly and easily build brochure sites in Drupal.

3) Social network - There are open source packages that are like social-network-in-a-box solutions. But nowadays, social networking is a feature, not a sufficient product alone. In my experience, using these off the shelf packages ends up being too limiting because you will always want to do new things and come up against the limits of the software, even if its open source. This applies to social news software like Pligg, school software like OpenSIS, Open Source Q&A software, forums like vBulletin, etc. Those kinds of sites were once novel and rare but are now just features to be added to larger sites, but they can not reasonable be used to build those larger sites.

WordPress's strong points:

1) Being a blog. It does one thing really well. I have run many WordPress blogs in the past. This blog is built with Drupal though because it's possible to blog with Drupal, and because I've also extended it far beyond blogging with many experiments.

2) Availability of commercial themes. There are a lot of companies making and selling themes for WordPress (this is also a point where Joomla wins over Drupal). There are also plenty of free themes. This is good for people who don't want to put money down on a fully custom design yet and are just happy to use something that looks professional.

3) Usability. Out of the box, WordPress is user friendly and makes it easy to get up and running. Drupal improves at this with every major version but is still something a developer more easily loves than an end user.

Honorable mentions

Mezzanine (http://mezzanine.jupo.org/) is a promising-looking CMS built with Django/Python. If you like Python (like I do) then consider giving it a shot, although it doesn't have nearly the depth and breadth of free modules that Drupal offers nor the size of community.

Cartridge (http://cartridge.jupo.org) is Mezzanine's ecommerce/shopping cart solution. Again, you won't get the community and support like you would with Ubercart but at least you would get to hack in Python!

Syndicate content
© 2010-2014 Saigonist.