<!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][5460] trunk: Introduces automatic meta cache features.</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, #logmsg > ol { margin-left: 0; 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/5460">5460</a></dd>
<dt>Author</dt> <dd>boonebgorges</dd>
<dt>Date</dt> <dd>2011-12-08 02:57:38 +0000 (Thu, 08 Dec 2011)</dd>
</dl>

<h3>Log Message</h3>
<pre>Introduces automatic meta cache features.
Introduces bp_update_meta_cache(), for collecting all metadata associated with an object or with multiple objects in one fell swoop, and adding it to the WP cache for quicker access later
Introduces bp_groups_update_meta_cache(), for collecting groupmeta at the beginning of a group loop
Modifies the BP_Groups_Group object so that groupmeta is fetched in the populate() and get() methods
Fixes <a href="http://buddypress.trac.wordpress.org/ticket/3799">#3799</a></pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkbpcorebpcorecachephp">trunk/bp-core/bp-core-cache.php</a></li>
<li><a href="#trunkbpgroupsbpgroupscachephp">trunk/bp-groups/bp-groups-cache.php</a></li>
<li><a href="#trunkbpgroupsbpgroupsclassesphp">trunk/bp-groups/bp-groups-classes.php</a></li>
<li><a href="#trunkbpgroupsbpgroupsfunctionsphp">trunk/bp-groups/bp-groups-functions.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkbpcorebpcorecachephp"></a>
<div class="modfile"><h4>Modified: trunk/bp-core/bp-core-cache.php (5459 => 5460)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/bp-core/bp-core-cache.php        2011-12-08 02:31:08 UTC (rev 5459)
+++ trunk/bp-core/bp-core-cache.php        2011-12-08 02:57:38 UTC (rev 5460)
</span><span class="lines">@@ -48,4 +48,82 @@
</span><span class="cx"> add_action( 'wp_login',              'bp_core_clear_cache' );
</span><span class="cx"> add_action( 'bp_core_render_notice', 'bp_core_clear_cache' );
</span><span class="cx"> 
</span><ins>+/**
+ * Update the metadata cache for the specified objects.
+ *
+ * @since 1.6
+ * @uses $wpdb WordPress database object for queries.
+ * @uses $bp BuddyPress global object.
+ *
+ * @param array $args See $defaults definition for more details
+ * @return mixed Metadata cache for the specified objects, or false on failure.
+ */
+function bp_update_meta_cache( $args = array() ) {
+        global $bp, $wpdb;
+        
+        $defaults = array(
+                'object_ids'            =&gt; array(), // Comma-separated list or array of item ids
+                'object_type'            =&gt; '',      // Canonical component id: groups, members, etc
+                'meta_table'            =&gt; '',      // Name of the table containing the metadata
+                'object_column'    =&gt; '',      // DB column for the object ids (group_id, etc)
+                'cache_key_prefix' =&gt; ''       // Prefix to use when creating cache key names. Eg
+                                               //    'bp_groups_groupmeta'
+        );
+        $r = wp_parse_args( $args, $defaults );
+        extract( $r );
+                
+        if ( empty( $object_ids ) || empty( $object_type ) || empty( $meta_table ) ) {
+                return false;
+        }
+        
+        if ( empty( $cache_key_prefix ) ) {
+                $cache_key_prefix = $meta_table;
+        }
+        
+        if ( empty( $object_column ) ) {
+                $object_column = $object_type . '_id';
+        }
+
+        if ( !is_array( $object_ids ) ) {
+                $object_ids = preg_replace( '|[^0-9,]|', '', $object_ids );
+                $object_ids = explode( ',', $object_ids );
+        }
+
+        $object_ids = array_map( 'intval', $object_ids );
+
+        $cache = array();
+        
+        // Get meta info
+        $id_list   = join( ',', $object_ids );
+        $meta_list = $wpdb-&gt;get_results( $wpdb-&gt;prepare( &quot;SELECT $object_column, meta_key, meta_value FROM $meta_table WHERE group_id IN ($id_list)&quot; ), ARRAY_A );
+
+        if ( !empty( $meta_list ) ) {
+                foreach ( $meta_list as $metarow ) {
+                        $mpid = intval( $metarow[$object_column] );
+                        $mkey = $metarow['meta_key'];
+                        $mval = $metarow['meta_value'];
+
+                        // Force subkeys to be array type:
+                        if ( !isset( $cache[$mpid] ) || !is_array( $cache[$mpid] ) )
+                                $cache[$mpid] = array();
+                        if ( !isset( $cache[$mpid][$mkey] ) || !is_array( $cache[$mpid][$mkey] ) )
+                                $cache[$mpid][$mkey] = array();
+
+                        // Add a value to the current pid/key:
+                        $cache[$mpid][$mkey][] = $mval;
+                }
+        }
+        
+        foreach ( $object_ids as $id ) {
+                if ( ! isset($cache[$id]) )
+                        $cache[$id] = array();
+        
+                foreach( $cache[$id] as $meta_key =&gt; $meta_value ) {
+                        wp_cache_set( $cache_key_prefix . '_' . $id . '_' . $meta_key, $meta_value, 'bp' );
+                }
+        }
+
+        return $cache;
+}
+
</ins><span class="cx"> ?&gt;
</span><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkbpgroupsbpgroupscachephp"></a>
<div class="modfile"><h4>Modified: trunk/bp-groups/bp-groups-cache.php (5459 => 5460)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/bp-groups/bp-groups-cache.php        2011-12-08 02:31:08 UTC (rev 5459)
+++ trunk/bp-groups/bp-groups-cache.php        2011-12-08 02:57:38 UTC (rev 5460)
</span><span class="lines">@@ -12,6 +12,33 @@
</span><span class="cx"> // Exit if accessed directly
</span><span class="cx"> if ( !defined( 'ABSPATH' ) ) exit;
</span><span class="cx"> 
</span><ins>+/**
+ * Slurps up groupmeta
+ *
+ * This function is called in two places in the BP_Groups_Group class:
+ *   - in the populate() method, when single group objects are populated
+ *   - in the get() method, when multiple groups are queried
+ *
+ * It grabs all groupmeta associated with all of the groups passed in $group_ids and adds it to
+ * the WP cache. This improves efficiency when using groupmeta inline
+ *
+ * @param int|str|array $group_ids Accepts a single group_id, or a comma-separated list or array of
+ *    group ids
+ */
+function bp_groups_update_meta_cache( $group_ids = false ) {
+        global $bp;
+        
+        $cache_args = array(
+                'object_ids'            =&gt; $group_ids,
+                'object_type'            =&gt; $bp-&gt;groups-&gt;id,
+                'object_column'    =&gt; 'group_id',
+                'meta_table'            =&gt; $bp-&gt;groups-&gt;table_name_groupmeta,
+                'cache_key_prefix' =&gt; 'bp_groups_groupmeta'
+        );
+        
+        bp_update_meta_cache( $cache_args );
+}
+
</ins><span class="cx"> function groups_clear_group_object_cache( $group_id ) {
</span><span class="cx">         wp_cache_delete( 'bp_total_group_count', 'bp' );
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkbpgroupsbpgroupsclassesphp"></a>
<div class="modfile"><h4>Modified: trunk/bp-groups/bp-groups-classes.php (5459 => 5460)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/bp-groups/bp-groups-classes.php        2011-12-08 02:31:08 UTC (rev 5459)
+++ trunk/bp-groups/bp-groups-classes.php        2011-12-08 02:57:38 UTC (rev 5460)
</span><span class="lines">@@ -30,7 +30,9 @@
</span><span class="cx">         function populate() {
</span><span class="cx">                 global $wpdb, $bp;
</span><span class="cx"> 
</span><del>-                if ( $group = $wpdb-&gt;get_row( $wpdb-&gt;prepare( &quot;SELECT g.*, gm.meta_value as last_activity, gm2.meta_value as total_member_count FROM {$bp-&gt;groups-&gt;table_name} g, {$bp-&gt;groups-&gt;table_name_groupmeta} gm, {$bp-&gt;groups-&gt;table_name_groupmeta} gm2 WHERE g.id = gm.group_id AND g.id = gm2.group_id AND gm.meta_key = 'last_activity' AND gm2.meta_key = 'total_member_count' AND g.id = %d&quot;, $this-&gt;id ) ) ) {
</del><ins>+                if ( $group = $wpdb-&gt;get_row( $wpdb-&gt;prepare( &quot;SELECT g.* FROM {$bp-&gt;groups-&gt;table_name} g WHERE g.id = %d&quot;, $this-&gt;id ) ) ) {                        
+                        bp_groups_update_meta_cache( $this-&gt;id );
+                                                
</ins><span class="cx">                         $this-&gt;id                 = $group-&gt;id;
</span><span class="cx">                         $this-&gt;creator_id         = $group-&gt;creator_id;
</span><span class="cx">                         $this-&gt;name               = stripslashes($group-&gt;name);
</span><span class="lines">@@ -39,8 +41,8 @@
</span><span class="cx">                         $this-&gt;status             = $group-&gt;status;
</span><span class="cx">                         $this-&gt;enable_forum       = $group-&gt;enable_forum;
</span><span class="cx">                         $this-&gt;date_created       = $group-&gt;date_created;
</span><del>-                        $this-&gt;last_activity      = $group-&gt;last_activity;
-                        $this-&gt;total_member_count = $group-&gt;total_member_count;
</del><ins>+                        $this-&gt;last_activity      = groups_get_groupmeta( $this-&gt;id, 'last_activity' );
+                        $this-&gt;total_member_count = groups_get_groupmeta( $this-&gt;id, 'total_member_count' );
</ins><span class="cx">                         $this-&gt;is_member          = BP_Groups_Member::check_is_member( bp_loggedin_user_id(), $this-&gt;id );
</span><span class="cx"> 
</span><span class="cx">                         // Get group admins and mods
</span><span class="lines">@@ -367,13 +369,19 @@
</span><span class="cx">                 $total_groups_sql = apply_filters( 'bp_groups_get_total_groups_sql', join( ' ', (array)$t_sql ), $t_sql );
</span><span class="cx">                 $total_groups     = $wpdb-&gt;get_var( $total_groups_sql );
</span><span class="cx"> 
</span><ins>+                $group_ids = array();
+                foreach ( (array)$paged_groups as $group ) {
+                        $group_ids[] = $group-&gt;id;
+                }
+                
</ins><span class="cx">                 /* Populate some extra information instead of querying each time in the loop */
</span><span class="cx">                 if ( !empty( $populate_extras ) ) {
</span><del>-                        $group_ids = array();
-                        foreach ( (array)$paged_groups as $group ) $group_ids[] = $group-&gt;id;
</del><span class="cx">                         $group_ids = $wpdb-&gt;escape( join( ',', (array)$group_ids ) );
</span><span class="cx">                         $paged_groups = BP_Groups_Group::get_group_extras( $paged_groups, $group_ids, $type );
</span><span class="cx">                 }
</span><ins>+                
+                // Grab all groupmeta
+                bp_groups_update_meta_cache( $group_ids );
</ins><span class="cx"> 
</span><span class="cx">                 unset( $sql, $total_sql );
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkbpgroupsbpgroupsfunctionsphp"></a>
<div class="modfile"><h4>Modified: trunk/bp-groups/bp-groups-functions.php (5459 => 5460)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/bp-groups/bp-groups-functions.php        2011-12-08 02:31:08 UTC (rev 5459)
+++ trunk/bp-groups/bp-groups-functions.php        2011-12-08 02:57:38 UTC (rev 5460)
</span><span class="lines">@@ -46,7 +46,7 @@
</span><span class="cx">         
</span><span class="cx">         if ( !$group = wp_cache_get( $cache_key, 'bp' ) ) {
</span><span class="cx">                 $group = new BP_Groups_Group( $group_id, true, $load_users );
</span><del>-                wp_cache_set( $cache_key, $group, 'bp' );
</del><ins>+                wp_cache_set( $cache_key, $group, 'bp' );        
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         return apply_filters( 'groups_get_group', $group );
</span><span class="lines">@@ -918,7 +918,7 @@
</span><span class="cx">         if ( !empty($meta_key) ) {
</span><span class="cx">                 $meta_key = preg_replace( '|[^a-z0-9_]|i', '', $meta_key );
</span><span class="cx"> 
</span><del>-                $metas = wp_cache_get( 'bp_groups_groupmeta_' . $group_id . '_' . $meta_key, 'bp' );                
</del><ins>+                $metas = wp_cache_get( 'bp_groups_groupmeta_' . $group_id . '_' . $meta_key, 'bp' );
</ins><span class="cx">                 if ( false === $metas ) {
</span><span class="cx">                         $metas = $wpdb-&gt;get_col( $wpdb-&gt;prepare(&quot;SELECT meta_value FROM &quot; . $bp-&gt;groups-&gt;table_name_groupmeta . &quot; WHERE group_id = %d AND meta_key = %s&quot;, $group_id, $meta_key) );
</span><span class="cx">                         wp_cache_set( 'bp_groups_groupmeta_' . $group_id . '_' . $meta_key, $metas, 'bp' );
</span></span></pre>
</div>
</div>

</body>
</html>