How to return the path to an enabled Drupal module or theme

In Drupal 7, it was fairly easy to retrieve the filesystem path for, say, enabled modules.

mysql> SELECT filename, name FROM system WHERE status = 1 AND name = "xmlsitemap";
| filename                                               | name       |
| sites/all/modules/contrib/xmlsitemap/xmlsitemap.module | xmlsitemap |
1 row in set (0.00 sec)

Why would you do that? Simply because sometimes you can run into issues caused by duplicate .info files in the filesystem. A common error is when you’re deleting a duplicate module or changing directories in the filesystem but the module is still registered in the database in its original location. This will make Drupal sad when it bootstraps.

When this happens, you need to know where a particular module is being loaded from. You may compare the results of the above MySQL query with a simple Linux command to find all occurrences of those filenames in your Drupal docroot and try to narrow down the issue (e.g. is the filename being loaded still present on the filesystem?). This could be with the form:

$ find . -type f -name "*.info" | grep -oe "[^/]*\.info" | sort | uniq -d

Let’s say is our culprit. We can refine the Linux find command accordingly:

$ find . -type f -name ""

Which gives the full path to the duplicate .info file.

What matters the most here is we don’t need to bootstrap Drupal, which can be a lifesaver in case the site is down.

Going forward with Drupal 8

In Drupal 8 we still have drupal_get_path() to help if we can bootstrap Drupal.

Psy Shell v0.7.2 (PHP 5.6.24 — cli) by Justin Hileman
>>> drupal_get_path('module', 'xmlsitemap');
=> "modules/xmlsitemap"

However, we can no longer query the {system} table. One workaround I found is to decode the corresponding {key_value} entry. E.g.:

$ drush sqlq "SELECT CONVERT(value USING utf8) FROM key_value WHERE collection = 'state' AND value LIKE ''" | grep --color=auto ''

This will return a huge array, so, having a colored output for grep is helpful to get the filename to the loaded .info.yml file.

This gets the job done but not as cleanly as I would. Do you know of any better way to achieve this?


September 19, 2016