8

In Drupal 7, I can use drupal_add_js within a theme's template.php file as a theme_preprocess_html(&$vars) function:

   drupal_add_js(drupal_get_path('theme', 'mytheme') . '/js/scripts.js',
        array(
          'group' => JS_THEME,
          'preprocess' => TRUE,
          'weight' => '999',
        ));

  $vars['scripts'] = drupal_get_js();

In Drupal 8, I've tried converting this using attached in my theme's .theme file as such:

  $vars['#attached']['js'] = array(
    array(
      'data' => drupal_get_path('theme', 'mytheme') . '/js/scripts.js',
      'options' => array(
        'group' => JS_THEME,
        'preprocess' => TRUE,
        'every_page' => TRUE,
      ),
    ),
  );

... but that did not work and there were no errors in watchdog / console or otherwise.

According to the D8 API page for drupal_add_js:

Deprecated - as of Drupal 8.0. Use the #attached key in render arrays instead.

There was not much more info that that however. It seems that drupal_add_css will also use this method. I know it's still early days for Drupal 8 but I was hoping to get a jump on this.

  • 1
    Just a guess - maybe you should try library approach? And please refrain from using "did not work" statement. Don't you hate it when you have to guess what does it mean? Warnings? Errors? Nothing and the file is not included? – Mołot Nov 28 '13 at 7:38
  • @Mołot - there were no warnings or errors and I checked watchdog as well. I also looked at console in Chrome and simply no errors, so all I can report is "it did not work." Full error reporting is turned on and I've certainly got my fair share of them while porting this theme to Drupal 8. At any rate, I think the library approach seems to be the way to go and not the answer given below. I'm going to pick apart some Drupal 8 modules to see if I can figure it out. – Danny Englander Nov 28 '13 at 14:08
  • You could have reported "it failed to work with no errors in ..." - then we would know there wasn't any, and you actually did your part of work before asking. That's all I wanted from you :) Too many guys here asks without even checking... – Mołot Nov 28 '13 at 14:11
  • 1
    Ok thanks, updated with a better issue summary. :) – Danny Englander Nov 28 '13 at 14:17
7

It seems you can use hook_preprocess_page with attached as such:

function MYTHEME_preprocess_page(&$vars, $hook) {
  $path = drupal_get_path('theme', 'MYTHEME');
     // Render the main scripts file.
  $local_js = array(
    '#attached' => array(
      'js' => array(
        $path . '/js/scripts.js' => array(
          'group' => JS_THEME,
          'weight' => 9999),
      ),
    ),
  );
  \Drupal::service('renderer')->renderRoot($local_js);
}

This works great (theme.inc uses this method), note the extra nested array around the weight.

  • Code updated to reflect a fully working version, weight and all. – Danny Englander Nov 30 '13 at 2:10
  • Exactly what I needed, much appreciated!!! – Yassin Tahtah Jan 30 '15 at 11:57
3

As of Drupal 8.0.x-beta2 you can attach CSS and JS from preprocess functions.

See https://www.drupal.org/node/2352319

0

Though the OP is about Drupal 8, this could be done in a similar way in Drupal 7 without using drupal_add_js() to start getting used to not having drupal_add_js() around:

/**
 * Implements hook_preprocess_page().
 */
function YOURMODULE_preprocess_page(&$variables) {
  $module_path = drupal_get_path('module', 'YOURMODULE');
  $variables['page']['content']['#attached']['js'][$module_path . '/js/YOURMODULE.js'] = array();
}

Options can be defined in the empty array, see https://api.drupal.org/api/drupal/includes%21common.inc/function/drupal_add_js/7.

2

In this example you are using a real render array and not one that is rendered in the function itself.

This way other modules, themes etc can alter it.

/**
 * Implements hook_page_alter().
 */
function db_jacket_page_alter(&$page) {
  $page['#attached']['js'][] = drupal_get_path('theme', 'db_jacket') . '/js/jquery.image-depth.js';
}
4

The key point in the documentation is this bit

Use the #attached key in render arrays instead.

Emphasis mine.

The $variables array in a theme/preprocess function isn't a render array, it's just an array holding variables. To use #attached you'll need something like this in the preprocess function:

$vars['foo'] = array(
  '#markup' => '<p>Bar</p>',
  '#attached' => array(
    'data' => drupal_get_path('theme', 'mytheme') . '/js/scripts.js',
    'options' => array(
      'group' => JS_THEME,
      'preprocess' => TRUE,
      'every_page' => TRUE,
    ),
  ),
);

And this in the template file:

{ foo }

In other words, more or less the same as in Drupal 7 (at this point in time, at least).

hook_preprocess_html() is likely not the right place for this code by the way; don't forget the js/css files are actually rendered in that template, so it's too late to add any more hook_preprocess_page(), hook_preprocess_node() or equivalent will probably get you more reliable results.

See the Twig best practices - preprocess functions and templates page for more information on preprocessing variables.

  • 1
    This is correct: The variables passed to preprocess/process functions are never a render array. – kiamlaluno Nov 28 '13 at 11:26
  • With all due respect, I'm simply trying to find a replacement in Drupal 8 for adding a js file to a theme, I'm not trying to render a variable in it. Even if I were, it would be done as {{ foo }} in the Twig world, there's no more php / print render in theme templates, i.e. node.html.twig / page.html.twig – Danny Englander Nov 28 '13 at 14:03
  • 1
    Yeah brain freeze there, my bad. The answer's the same though. You can only use #attached in the context of a render array; the documentation is correct. You either need to use the method above, along with this to preprocess and pre-render the variable, or to use your theme's .info.yml file to include the JS. Those are the only options as I can tell so far, without going down the library route – Clive Nov 28 '13 at 14:08
  • 1
    I think the approach is going to be something similar to this: drupalcode.org/project/drupal.git/blob/refs/heads/8.x:/core/… -- see line 564 which uses hook_library_info and which Mołot implied above. I'll have to play around with that a bit. Thanks. – Danny Englander Nov 28 '13 at 14:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.