The problems (they're intertwined though):
file_create_url()
result for the CSS file itself abused to generate the URLs for files referenced by CSS files- Drupal 7 core's CSS aggregation does call
file_create_url()
(and thus allowinghook_file_url_alter()
to modify that URL) on the aggregate CSS file that's being built (e.g.http://site.com/subdir/sites/default/foobar.css
). It then proceeds to strip the filename away, the result (http://site.com/subdir/sites/default/
) of which it then uses to prepend to the referenced files. So e.g. iffoobar.css
referencescat.png
, it will concatenatehttp://site.com/subdir/sites/default
andcat.png
.
This breaks down as soon as each file gets a unique file URL. e.g. when it is rewritten to be served from a CDN with Far Future expiration headers:http://cdn.com/last-modified:2012-03-10/foobar.css
works fine, but because of the above logic, the same URL will be forced upon each referenced file, which is of course very wrong. - Fix:
- // Build the base URL of this CSS file: start with the full URL.
- $css_base_url = file_create_url($stylesheet['data']);
- // Move to the parent.
- $css_base_url = substr($css_base_url, 0, strrpos($css_base_url, '/'));
- // Simplify to a relative URL if the stylesheet URL starts with the
- // base URL of the website.
- if (substr($css_base_url, 0, strlen($GLOBALS['base_root'])) == $GLOBALS['base_root']) {
- $css_base_url = substr($css_base_url, strlen($GLOBALS['base_root']));
- }
-
+ // Get the parent directory of this file, relative to the Drupal root.
+ $css_base_url = drupal_substr($stylesheet['data'], 0, strrpos($stylesheet['data'], '/')); file_create_url()
not applied to files referenced by CSS files- Drupal 7 core's CSS aggregation breaks modules that want to alter file URLs via
hook_file_url_alter()
because it does not route file URLs of files referenced by aggregated CSS files (e.g. background images, fonts). - So: inability to have
hook_file_url_alter()
process files referenced by a CSS file. - Fix:
- return 'url(' . $path . ')';
+ return 'url(' . file_create_url($path) . ')'; - This breaks the CDN module, and forces many other modules (e.g. to use data URIs) to apply crazy hackery in the theme layer to parse HTML and then modify it.
The CDN module has been shipping with an override for Drupal core's CSS aggregation for over a year, but there are unsolvable compatibility problems with certain modules (e.g. http://drupal.org/project/css_emimage, see #1532178-10: Integrate with CSS Embedded Images module) and themes (e.g. http://drupal.org/project/omega, see #1790348: Far-Future mode: background images and font files referenced in CSS files incorrectly rewritten, but only in an Omega subtheme) because Drupal core forces us to use crazy theme layer hackery to achieve what we need to achieve.
On Drupal 8
This code is still identical in D8, so in theory this patch should be against D8, but asset handling in D8 is still going to have to change completely because of the new Symfony-based render system. So it's rather pointless to apply it to D8. If that's desired though, then I'd be happy to do so.