<!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" /><style type="text/css"><!--
#msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer { 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 #fc0 solid; padding: 6px; }
#msg ul, pre { overflow: auto; }
#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>
<title>[17576] trunk/wp-admin/includes: Be a party-pooper;
  No more Akismet Dancing upon upgrade;
  Respect custom WP_CONTENT_DIR for bundled plugins/theme installation;
  Respect custom WP_CONTENT_DIR/
 WP_LANG_DIR for Language files when upgrading;
  Standardise WP_Filesystem path method returns (They're trailing slash'd).</title>
</head>
<body>

<div id="msg">
<dl>
<dt>Revision</dt> <dd><a href="http://trac.wordpress.org/changeset/17576">17576</a></dd>
<dt>Author</dt> <dd>dd32</dd>
<dt>Date</dt> <dd>2011-03-31 13:28:36 +0000 (Thu, 31 Mar 2011)</dd>
</dl>

<h3>Log Message</h3>
<pre>Be a party-pooper; No more Akismet Dancing upon upgrade; Respect custom WP_CONTENT_DIR for bundled plugins/theme installation; Respect custom WP_CONTENT_DIR/WP_LANG_DIR for Language files when upgrading; Standardise WP_Filesystem path method returns (They're trailing slash'd). Adds an exclusion list to copy_dir() as well as WP_Filesystem_Base::wp_lang_dir().  See <a href="http://trac.wordpress.org/ticket/14484">#14484</a> See <a href="http://trac.wordpress.org/ticket/11495">#11495</a></pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkwpadminincludesclasswpfilesystembasephp">trunk/wp-admin/includes/class-wp-filesystem-base.php</a></li>
<li><a href="#trunkwpadminincludesfilephp">trunk/wp-admin/includes/file.php</a></li>
<li><a href="#trunkwpadminincludesupdatecorephp">trunk/wp-admin/includes/update-core.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkwpadminincludesclasswpfilesystembasephp"></a>
<div class="modfile"><h4>Modified: trunk/wp-admin/includes/class-wp-filesystem-base.php (17575 => 17576)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-admin/includes/class-wp-filesystem-base.php        2011-03-31 08:11:30 UTC (rev 17575)
+++ trunk/wp-admin/includes/class-wp-filesystem-base.php        2011-03-31 13:28:36 UTC (rev 17576)
</span><span class="lines">@@ -82,8 +82,19 @@
</span><span class="cx">          * @return string The location of the remote path.
</span><span class="cx">          */
</span><span class="cx">         function wp_themes_dir() {
</span><del>-                return $this-&gt;wp_content_dir() . '/themes';
</del><ins>+                return $this-&gt;wp_content_dir() . 'themes/';
</ins><span class="cx">         }
</span><ins>+        /**
+         * Returns the path on the remote filesystem of WP_LANG_DIR
+         *
+         * @since 3.2
+         * @access public
+         *
+         * @return string The location of the remote path.
+         */
+        function wp_lang_dir() {
+                return $this-&gt;find_folder(WP_LANG_DIR);
+        }
</ins><span class="cx"> 
</span><span class="cx">         /**
</span><span class="cx">          * Locates a folder on the remote filesystem.
</span></span></pre></div>
<a id="trunkwpadminincludesfilephp"></a>
<div class="modfile"><h4>Modified: trunk/wp-admin/includes/file.php (17575 => 17576)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-admin/includes/file.php        2011-03-31 08:11:30 UTC (rev 17575)
+++ trunk/wp-admin/includes/file.php        2011-03-31 13:28:36 UTC (rev 17576)
</span><span class="lines">@@ -716,9 +716,10 @@
</span><span class="cx">  *
</span><span class="cx">  * @param string $from source directory
</span><span class="cx">  * @param string $to destination directory
</span><ins>+ * @param array $skip_list a list of files/folders to skip copying
</ins><span class="cx">  * @return mixed WP_Error on failure, True on success.
</span><span class="cx">  */
</span><del>-function copy_dir($from, $to) {
</del><ins>+function copy_dir($from, $to, $skip_list = array() ) {
</ins><span class="cx">         global $wp_filesystem;
</span><span class="cx"> 
</span><span class="cx">         $dirlist = $wp_filesystem-&gt;dirlist($from);
</span><span class="lines">@@ -726,7 +727,18 @@
</span><span class="cx">         $from = trailingslashit($from);
</span><span class="cx">         $to = trailingslashit($to);
</span><span class="cx"> 
</span><ins>+        $skip_regex = '';
+        foreach ( (array)$skip_list as $key =&gt; $skip_file )
+                $skip_regex .= preg_quote($skip_file, '!') . '|';
+
+        if ( !empty($skip_regex) )
+                $skip_regex = '!(' . rtrim($skip_regex, '|') . ')$!i';
+
</ins><span class="cx">         foreach ( (array) $dirlist as $filename =&gt; $fileinfo ) {
</span><ins>+                if ( !empty($skip_regex) )
+                        if ( preg_match($skip_regex, $from . $filename) )
+                                continue;
+
</ins><span class="cx">                 if ( 'f' == $fileinfo['type'] ) {
</span><span class="cx">                         if ( ! $wp_filesystem-&gt;copy($from . $filename, $to . $filename, true, FS_CHMOD_FILE) ) {
</span><span class="cx">                                 // If copy failed, chmod file to 0644 and try again.
</span><span class="lines">@@ -739,7 +751,7 @@
</span><span class="cx">                                 if ( !$wp_filesystem-&gt;mkdir($to . $filename, FS_CHMOD_DIR) )
</span><span class="cx">                                         return new WP_Error('mkdir_failed', __('Could not create directory.'), $to . $filename);
</span><span class="cx">                         }
</span><del>-                        $result = copy_dir($from . $filename, $to . $filename);
</del><ins>+                        $result = copy_dir($from . $filename, $to . $filename, $skip_list);
</ins><span class="cx">                         if ( is_wp_error($result) )
</span><span class="cx">                                 return $result;
</span><span class="cx">                 }
</span></span></pre></div>
<a id="trunkwpadminincludesupdatecorephp"></a>
<div class="modfile"><h4>Modified: trunk/wp-admin/includes/update-core.php (17575 => 17576)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-admin/includes/update-core.php        2011-03-31 08:11:30 UTC (rev 17575)
+++ trunk/wp-admin/includes/update-core.php        2011-03-31 13:28:36 UTC (rev 17576)
</span><span class="lines">@@ -246,6 +246,30 @@
</span><span class="cx"> );
</span><span class="cx"> 
</span><span class="cx"> /**
</span><ins>+ * Stores new files in wp-content to copy
+ *
+ * The contents of this array indicate any new bundled plugins/themes which
+ * should be installed with the WordPress Upgrade. These items will not be
+ * re-installed in future upgrades, this behaviour is controlled by the 
+ * introduced version present here being older than the current installed version.
+ *
+ * The content of this array should follow the following format:
+ *  Filename (relative to wp-content) =&gt; Introduced version
+ * Directories should be noted by suffixing it with a trailing slash (/)
+ *
+ * @since 3.2
+ * @global array $_new_bundled_files
+ * @var array
+ * @name $_new_bundled_files
+ */
+global $_new_bundled_files;
+
+$_new_bundled_files = array(
+'plugins/akismet/' =&gt; '2.0',
+'themes/twentyten/' =&gt; '3.2',
+);
+
+/**
</ins><span class="cx">  * Upgrade the core of WordPress.
</span><span class="cx">  *
</span><span class="cx">  * This will create a .maintenance file at the base of the WordPress directory
</span><span class="lines">@@ -255,12 +279,18 @@
</span><span class="cx">  * The files in the {@link $_old_files} list will be removed and the new files
</span><span class="cx">  * copied from the zip file after the database is upgraded.
</span><span class="cx">  *
</span><ins>+ * The files in the {@link $_new_bundled_files} list will be added to the installation
+ * if the version is greater than or equal to the old version being upgraded.
+ *
</ins><span class="cx">  * The steps for the upgrader for after the new release is downloaded and
</span><span class="cx">  * unzipped is:
</span><span class="cx">  *   1. Test unzipped location for select files to ensure that unzipped worked.
</span><span class="cx">  *   2. Create the .maintenance file in current WordPress base.
</span><span class="cx">  *   3. Copy new WordPress directory over old WordPress files.
</span><span class="cx">  *   4. Upgrade WordPress to new version.
</span><ins>+ *     4.1. Copy all files/folders other than wp-content
+ *     4.2. Copy any language files to WP_LANG_DIR (which may differ from WP_CONTENT_DIR
+ *     4.3. Copy any new bundled themes/plugins to their respective locations
</ins><span class="cx">  *   5. Delete new WordPress directory path.
</span><span class="cx">  *   6. Delete .maintenance file.
</span><span class="cx">  *   7. Remove old files.
</span><span class="lines">@@ -286,7 +316,7 @@
</span><span class="cx">  * @return WP_Error|null WP_Error on failure, null on success.
</span><span class="cx">  */
</span><span class="cx"> function update_core($from, $to) {
</span><del>-        global $wp_filesystem, $_old_files, $wpdb;
</del><ins>+        global $wp_filesystem, $_old_files, $_new_bundled_files, $wpdb;
</ins><span class="cx"> 
</span><span class="cx">         @set_time_limit( 300 );
</span><span class="cx"> 
</span><span class="lines">@@ -311,10 +341,10 @@
</span><span class="cx">         // Sanity check the unzipped distribution
</span><span class="cx">         apply_filters('update_feedback', __('Verifying the unpacked files&amp;#8230;'));
</span><span class="cx">         $distro = '';
</span><del>-        $roots = array( '/wordpress', '/wordpress-mu' );
</del><ins>+        $roots = array( '/wordpress/', '/wordpress-mu/' );
</ins><span class="cx">         foreach( $roots as $root ) {
</span><del>-                if ( $wp_filesystem-&gt;exists($from . $root . '/wp-settings.php') &amp;&amp; $wp_filesystem-&gt;exists($from . $root . '/wp-admin/admin.php') &amp;&amp;
-                        $wp_filesystem-&gt;exists($from . $root . '/wp-includes/functions.php') ) {
</del><ins>+                if ( $wp_filesystem-&gt;exists($from . $root . 'wp-settings.php') &amp;&amp; $wp_filesystem-&gt;exists($from . $root . 'wp-admin/admin.php') &amp;&amp;
+                        $wp_filesystem-&gt;exists($from . $root . 'wp-includes/functions.php') ) {
</ins><span class="cx">                         $distro = $root;
</span><span class="cx">                         break;
</span><span class="cx">                 }
</span><span class="lines">@@ -333,7 +363,56 @@
</span><span class="cx">         $wp_filesystem-&gt;put_contents($maintenance_file, $maintenance_string, FS_CHMOD_FILE);
</span><span class="cx"> 
</span><span class="cx">         // Copy new versions of WP files into place.
</span><del>-        $result = copy_dir($from . $distro, $to);
</del><ins>+        $result = copy_dir($from . $distro, $to, array('wp-content') );
+
+        // Custom Content Directory needs updating now.
+        // Copy Languages
+        if ( !is_wp_error($result) &amp;&amp; $wp_filesystem-&gt;is_dir($from . $distro . 'wp-content/languages') ) {
+                if ( !@is_dir(WP_LANG_DIR) &amp;&amp; 0 === strpos(WP_LANG_DIR, ABSPATH) ) { // Check the language directory exists first
+                        $wp_filesystem-&gt;mkdir($to . str_replace(WP_LANG_DIR, ABSPATH, ''), FS_CHMOD_DIR); // If it's within the ABSPATH we can handle it here, otherwise they're out of luck.
+                        clearstatcache(); // for FTP, Need to clear the stat cache
+                }
+
+                if ( @is_dir(WP_LANG_DIR) ) {
+                        $wp_lang_dir = $wp_filesystem-&gt;wp_lang_dir();
+                        $result = copy_dir($from . $distro . 'wp-content/languages/', $wp_lang_dir);
+                }
+        }
+
+        // Copy New bundled plugins &amp; themes
+        // This gives us the ability to install new plugins &amp; themes bundled with future versions of WordPress whilst avoiding the re-install upon upgrade issue.
+        if ( !is_wp_error($result) &amp;&amp; ( ! defined('CORE_UPGRADE_SKIP_NEW_BUNDLED') || ! CORE_UPGRADE_SKIP_NEW_BUNDLED ) ) {
+                $old_version = $GLOBALS['wp_version']; // $wp_version in local scope == new version
+                foreach ( (array) $_new_bundled_files as $file =&gt; $introduced_version ) {
+                        // If $introduced version is greater than what the site was previously running
+                        if ( version_compare($introduced_version, $old_version, '&gt;') ) {
+                                $directory = ('/' == $file[ strlen($file)-1 ]);
+                                list($type, $filename) = explode('/', $file, 2);
+                                if ( 'plugins' == $type )
+                                        $dest = $wp_filesystem-&gt;wp_plugins_dir();
+                                elseif ( 'themes' == $type )
+                                        $dest = $wp_filesystem-&gt;wp_themes_dir();
+
+                                if ( ! $directory ) {
+                                        if ( $wp_filesystem-&gt;exists($dest . '/' . $filename) )
+                                                continue;
+
+                                        if ( ! $wp_filesystem-&gt;copy($from . $distro . 'wp-content/' . $file, $dest . '/' . $filename, FS_CHMOD_FILE) )
+                                                $result = new WP_Error('copy_failed', __('Could not copy file.'), $dest . '/' . $filename);
+                                } else {
+                                        if ( $wp_filesystem-&gt;is_dir($dest . '/' . $filename) )
+                                                continue;
+
+                                        $wp_filesystem-&gt;mkdir($dest . $filename, FS_CHMOD_DIR);
+                                        $_result = copy_dir( $from . $distro . 'wp-content/' . $file, $dest . $filename);
+                                        if ( is_wp_error($_result) ) //If a error occurs partway through this final step, keep the error flowing through, but keep process going.
+                                                $result = $_result;
+                                }
+                        }
+                } //end foreach
+        }
+
+        // Handle $result error from the above blocks
</ins><span class="cx">         if ( is_wp_error($result) ) {
</span><span class="cx">                 $wp_filesystem-&gt;delete($maintenance_file);
</span><span class="cx">                 $wp_filesystem-&gt;delete($from, true);
</span></span></pre>
</div>
</div>

</body>
</html>