<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[BuddyPress][7205] trunk/bp-templates/bp-legacy/buddypress-functions.php: Allow JS and CSS assets to be stored in folder stacks, akin to template stacks</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://buddypress.trac.wordpress.org/changeset/7205">7205</a></dd>
<dt>Author</dt> <dd>boonebgorges</dd>
<dt>Date</dt> <dd>2013-06-12 21:54:52 +0000 (Wed, 12 Jun 2013)</dd>
</dl>

<h3>Log Message</h3>
<pre>Allow JS and CSS assets to be stored in folder stacks, akin to template stacks

Since BP 1.7 and theme compatibility, it's been possible to override BP's
fallback templates by providing templates in a number of different
subdirectories of your theme: 'buddypress' and 'community', by default. This
functionality was not, however, extended to static theme assets like JS and
CSS files, meaning that theme authors were forced to have orphan 'css' and 'js'
files in their theme roots if they wanted to override bp-legacy's assets.

This changeset mirrors the template_stack() functionality for assets, by
looking inside of 'buddypress' and 'community' theme subdirectories before
looking in root 'css' and 'js' directories (which still work, for backpat).

The implementation adopted in this changset is probably temporary for 1.8.
Future iterations may use an abstracted version of the core template_stack
functionality.

Props hnla for early patches and feedback.

Fixes <a href="http://buddypress.trac.wordpress.org/ticket/4949">#4949</a></pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkbptemplatesbplegacybuddypressfunctionsphp">trunk/bp-templates/bp-legacy/buddypress-functions.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkbptemplatesbplegacybuddypressfunctionsphp"></a>
<div class="modfile"><h4>Modified: trunk/bp-templates/bp-legacy/buddypress-functions.php (7204 => 7205)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/bp-templates/bp-legacy/buddypress-functions.php    2013-06-12 21:49:54 UTC (rev 7204)
+++ trunk/bp-templates/bp-legacy/buddypress-functions.php       2013-06-12 21:54:52 UTC (rev 7205)
</span><span class="lines">@@ -195,26 +195,15 @@
</span><span class="cx">  public function enqueue_styles() {
</span><span class="cx"> 
</span><span class="cx">          // LTR or RTL
</span><del>-               $file = is_rtl() ? 'css/buddypress-rtl.css' : 'css/buddypress.css';
</del><ins>+                $file = is_rtl() ? 'buddypress-rtl.css' : 'buddypress.css';
</ins><span class="cx"> 
</span><del>-               // Check child theme
-               if ( file_exists( trailingslashit( get_stylesheet_directory() ) . $file ) ) {
-                       $location = trailingslashit( get_stylesheet_directory_uri() );
-                       $handle   = 'bp-child-css';
</del><ins>+                // Locate the BP stylesheet
+               $asset = $this->locate_asset_in_stack( $file, 'css' );
</ins><span class="cx"> 
</span><del>-               // Check parent theme
-               } elseif ( file_exists( trailingslashit( get_template_directory() ) . $file ) ) {
-                       $location = trailingslashit( get_template_directory_uri() );
-                       $handle   = 'bp-parent-css';
-
-               // BuddyPress Theme Compatibility
-               } else {
-                       $location = trailingslashit( $this->url );
-                       $handle   = 'bp-legacy-css';
</del><ins>+                // Enqueue BuddyPress-specific styling, if found
+               if ( isset( $asset['location'], $asset['handle'] ) ) {
+                       wp_enqueue_style( $asset['handle'], $asset['location'], array(), $this->version, 'screen' );
</ins><span class="cx">           }
</span><del>-
-               // Enqueue the BuddyPress styling
-               wp_enqueue_style( $handle, $location . $file, array(), $this->version, 'screen' );
</del><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">  /**
</span><span class="lines">@@ -224,28 +213,17 @@
</span><span class="cx">   */
</span><span class="cx">  public function enqueue_scripts() {
</span><span class="cx"> 
</span><del>-               // LTR or RTL
-               $file = 'js/buddypress.js';
</del><ins>+                $file = 'buddypress.js';
</ins><span class="cx"> 
</span><del>-               // Check child theme
-               if ( file_exists( trailingslashit( get_stylesheet_directory() ) . $file ) ) {
-                       $location = trailingslashit( get_stylesheet_directory_uri() );
-                       $handle   = 'bp-child-js';
</del><ins>+                // Locate the BP JS file
+               $asset = $this->locate_asset_in_stack( $file, 'js' );
</ins><span class="cx"> 
</span><del>-               // Check parent theme
-               } elseif ( file_exists( trailingslashit( get_template_directory() ) . $file ) ) {
-                       $location = trailingslashit( get_template_directory_uri() );
-                       $handle   = 'bp-parent-js';
-
-               // BuddyPress Theme Compatibility
-               } else {
-                       $location = trailingslashit( $this->url );
-                       $handle   = 'bp-legacy-js';
</del><ins>+                // Enqueue the global JS, if found - AJAX will not work
+               // without it
+               if ( isset( $asset['location'], $asset['handle'] ) ) {
+                       wp_enqueue_script( $asset['handle'], $asset['location'], array( 'jquery' ), $this->version );
</ins><span class="cx">           }
</span><span class="cx"> 
</span><del>-               // Enqueue the global JS - Ajax will not work without it
-               wp_enqueue_script( $handle, $location . $file, array( 'jquery' ), $this->version );
-
</del><span class="cx">           // Add words that we need to use in JS to the end of the page so they can be translated and still used.
</span><span class="cx">          $params = array(
</span><span class="cx">                  'my_favs'           => __( 'My Favorites', 'buddypress' ),
</span><span class="lines">@@ -261,7 +239,7 @@
</span><span class="cx">                  'remove_fav'        => __( 'Remove Favorite', 'buddypress' ),
</span><span class="cx">                  'unsaved_changes'   => __( 'Your profile has unsaved changes. If you leave the page, the changes will be lost.', 'buddypress' ),
</span><span class="cx">          );
</span><del>-               wp_localize_script( $handle, 'BP_DTheme', $params );
</del><ins>+                wp_localize_script( $asset['handle'], 'BP_DTheme', $params );
</ins><span class="cx"> 
</span><span class="cx">          // Maybe enqueue comment reply JS
</span><span class="cx">          if ( is_singular() && bp_is_blog_page() && get_option( 'thread_comments' ) ) {
</span><span class="lines">@@ -270,6 +248,80 @@
</span><span class="cx">  }
</span><span class="cx"> 
</span><span class="cx">  /**
</span><ins>+        * Get the URL and handle of a web-accessible CSS or JS asset
+        *
+        * We provide two levels of customizability with respect to where CSS
+        * and JS files can be stored: (1) the child theme/parent theme/theme
+        * compat hierarchy, and (2) the "template stack" of /buddypress/css/,
+        * /community/css/, and /css/. In this way, CSS and JS assets can be
+        * overloaded, and default versions provided, in exactly the same way
+        * as corresponding PHP templates.
+        *
+        * We are duplicating some of the logic that is currently found in
+        * bp_locate_template() and the _template_stack() functions. Those
+        * functions were built with PHP templates in mind, and will require
+        * refactoring in order to provide "stack" functionality for assets
+        * that must be accessible both using file_exists() (the file path)
+        * and at a public URI.
+        *
+        * This method is marked private, with the understanding that the
+        * implementation is subject to change or removal in an upcoming
+        * release, in favor of a unified _template_stack() system. Plugin
+        * and theme authors should not attempt to use what follows.
+        *
+        * @since BuddyPress (1.8)
+        * @access private
+        * @param string $file A filename like buddypress.cs
+        * @param string $type css|js
+        * @return array An array of data for the wp_enqueue_* function:
+        *   'handle' (eg 'bp-child-css') and a 'location' (the URI of the
+        *   asset)
+        */
+       private function locate_asset_in_stack( $file, $type = 'css' ) {
+               // Child, parent, theme compat
+               $locations = array();
+
+               // No need to check child if template == stylesheet
+               if ( is_child_theme() ) {
+                       $locations['bp-child'] = array(
+                               'dir' => get_stylesheet_directory(),
+                               'uri' => get_stylesheet_directory_uri(),
+                       );
+               }
+
+               $locations['bp-parent'] = array(
+                       'dir' => get_template_directory(),
+                       'uri' => get_template_directory_uri(),
+               );
+
+               $locations['bp-legacy'] = array(
+                       'dir' => bp_get_theme_compat_dir(),
+                       'uri' => bp_get_theme_compat_url(),
+               );
+
+               // Subdirectories within the top-level $locations directories
+               $subdirs = array(
+                       'buddypress/' . $type,
+                       'community/' . $type,
+                       $type,
+               );
+
+               $retval = array();
+
+               foreach ( $locations as $location_type => $location ) {
+                       foreach ( $subdirs as $subdir ) {
+                               if ( file_exists( trailingslashit( $location['dir'] ) . trailingslashit( $subdir ) . $file ) ) {
+                                       $retval['location'] = trailingslashit( $location['uri'] ) . trailingslashit( $subdir ) . $file;
+                                       $retval['handle']   = $location_type . '-' . $type;
+                                       break 2;
+                               }
+                       }
+               }
+
+               return $retval;
+       }
+
+       /**
</ins><span class="cx">    * Put some scripts in the header, like AJAX url for wp-lists
</span><span class="cx">   *
</span><span class="cx">   * @since BuddyPress (1.7)
</span></span></pre>
</div>
</div>

</body>
</html>