Half-Elf on Tech

Thoughts From a Professional Lesbian

Category: How To

  • wp-cron it up

    wp-cron it up

    CronIf you’ve spent much time mastering *nix servers, you’ve run into cron. I love cron. Cron is a special command that lets you schedule jobs. I use it all the time for various commands I want to run regularly, like the hourly check for new posts in RSS on TinyRSS or RSS2Email, or the nightly backups, or any other thing I want to happen repeatedly. Cron is perfect for this, it runs in the background and it’s always running.

    My first thought, when I heard about wp-cron, was that it clearly tapped into cron! If I scheduled a post, it must write a one-time cron job for that. I was wrong. Among other reasons, not everyone has cron on their servers (Windows, I’m looking at you), but more to the point, cron is a bit overkill here. Instead WordPress has a file called wp-cron.php which it calls under special circumstances. Every time you load a page, WordPress checks if there’s anything for WP-Cron to run and, if so, calls wp-cron.php.

    Some hosts get a little snippy about that, claiming it overuses resources and ask that you disable cron. One might argue that checking on every pageload is overkill, but realistically, with all the other checks WordPress puts in for comments and changes, that seems a bit off. In the old WordPress days, this actually was a little true. If you have a server getting a lot of traffic, it was possible to accidentally loop multiple calls at the same time. This was fixed quite a bit in WordPress 3.3 with better locking (so things only run once). Multisite was a hassle for a lot of people, but seems to have been sorted out.

    StopwatchWe already know that WordPress only calls wp-cron if it needs to, so if you disable it, you have to run that manually (which ironically you could do via a cron job (Read How to Disable WordPress WP-Cron for directions on how to disable and then use real cron.)). To disable wp-cron, just toss this in your wp-config.php:

    define('DISABLE_WP_CRON', true);

    Now, remember, you still want to run a ‘cron’ job to fire off anything scheduled, so you have to add in your own cron-job for this, which I actually do! I have cron turned off, and a ‘real’ cron job runs at 5 and 35 past the hour to call wp-cron with a simple command:

    curl http://example.com/wp-cron.php
    

    Now since I have multiple domains on this install, I actually have that for every site on my Multisite. After all, wp-cron.php on Ipstenu.org doesn’t run for photos.ipstenu.org and so on. Doing this sped up my site, and put the strain back where I felt it should be. The server.

    By the way, wp-cron does more than schedule posts. That’s what checks for plugin, theme and core updates, and you can write code to hook into it to schedule things like backups. Remember before how I said that WP checks to see if there’s anything scheduled? This is a good thing, since if you have your server run a long job (like backing up a 100meg site), you don’t want to wait for that to be done before you page loaded, right?

    For most people, on most sites, this is all fine to leave alone and let it run as is. For the rest, if you chose to use cron instead, keep in mind how things are scheduled. Like I set my cron to run and 5 and 35, so I tend to schedule posts for 30 and the hour. That means my posts will go up no later that 5 minutes after. That’s good, but if I use my DreamObjects plugin, the ‘Backup ASAP’ button schedules a backup to run in 60 seconds (so as not to stop you from doing anything else, eh?), which means I’d have to manually go to example.com/wp-cron.php in order to kick it off. Clearly there are issues doing this for a client.

  • Backwards Settings API

    Backwards Settings API

    backwardsThe biggest problem with documentation is that if you don’t think the same way the doc was written, the examples will frustrate you to the point where you want to cry. If you’re not techy at all, directions to move WordPress to a subfolder will piss you off. If you’re a basic webmaster, who can edit posts and maybe FTP, they’re scary but doable. It’s all a measure of leveling up and seeing things in a way you understand.

    Recently I was banging around with the Settings API in WordPress to fix some debug errors in a plugin. It took me about 5 hours to figure out what it was I was doing, and how to fix it. Actual fixing? About half an hour, including the time it took to make fresh coffee.

    What was my problem? I was looking at code from a different angle. If you start ‘right’ it’s really easy to follow tutorials, but when you start from an already functioning plugin and want to correct it, it’s a nightmare. Reverse engineering things isn’t easy. You’re used to looking at things in one way, and changing that is a headache. What I had was working, up until you turned on debug, which is why I got away with it for so long, and why I hated having to change it.

    But I did. I had a plugin admin page that let you enter two text strings, an access key and a secret key, which the rest of the code used to do it’s magic. Because of that, I couldn’t just be lazy and use a basic register_setting() call like this:

    register_setting( 'myplugin-retain-settings', 'myplugin-retain');
    

    That’s easy, you put it in, you call it with settings_fields('myplugin-retain-settings');, and you go to the races. But I have two strings, and if you call the settings fields twice, you’ll find all sorts of fun errors.

    To explain, let me show you what I did wrong, and what right is.

    Doing It Wrong

    <form method="post" action="options.php">
    <input type="hidden" name="action" value="update" />
    <?php wp_nonce_field('update-options'); ?>
    <input type="hidden" name="page_options" value="myplugin-accesskey,myplugin-secretkey" />
    
    <table class="form-table">
        <tbody>
            <tr valign="top"><th colspan="2"><h3><?php _e('MyPlugin Settings', myplugin); ?></h3></th></tr>
            <tr valign="top">
                <th scope="row"><label for="myplugin-accesskey"><?php _e('Access Key', myplugin); ?></label></th>
                <td><input type="text" name="myplugin-accesskey" value="<?php echo get_option('myplugin-accesskey'); ?>" class="regular-text"/></td>
            </tr>
    
            <tr valign="top">
                <th scope="row"><label for="myplugin-secretkey"><?php _e('Secret Key', myplugin); ?></label></th>
                <td><input type="text" name="myplugin-secretkey" value="<?php echo get_option('myplugin-secretkey'); ?>" class="regular-text"/></td>
            </tr>
    </tbody>
    </table>
    
    <p class="submit"><input class='button-primary' type='Submit' name='update' value='<?php _e("Update Options", dreamobjects); ?>' id='submitbutton' /></p>
    </form>
    

    Doing It Right

    <form method="post" action="options.php">
    	<?php
            settings_fields( 'myplugin-keypair-settings' );
            do_settings_sections( 'myplugin-keypair_page' );
            submit_button();
    	?>
    </form>
    

    Making Wrong Right

    As you can tell, there’s a huge difference between the two, and one is a lot easier to look at than the other.

    First you have to set up registering settings. Since I already had an admin action for my settings page, I wanted to just add to that:

    function add_settings_page() {
            load_plugin_textdomain(myplugin, MYPLUG::getPath() . 'i18n', 'i18n');
            add_menu_page(__('MyPlugin Settings'), __('MyPlugin'), 'manage_options', 'myplugin-menu', array('MYPLUG', 'settings_page'), plugins_url('myplugin/images/myplugin-color.png'));
    }
    

    I added this in(I’m using an array to isolate my plugin functions, so I don’t have to worry as much about namespace clases.):

            add_action('admin_init', array('MYPLUG', 'add_register_settings'));
    

    That was the easy part. The hard part is converting all my table information into settings. Making another new function, I want to add a setting section, just as you would for a one-off. But in this case I need to make a group. Since I named my settings field myplugin-keypair-settings, and my section myplugin-keypair_page, that’s the first important information I need. But backwards.

    First I have to add my section using add_settings_section():

    add_settings_section( 'myplugin-keypair_id', 'MyPlugin Settings', 'myplugkeypair_callback', 'myplugin-keypair_page' );
    

    Once you do that, you want to register the setting, just like normal:

    register_setting( 'myplugin-keypair-settings','myplugin-key');
    

    The complete function

    function add_register_settings() {
         // Keypair settings
            add_settings_section( 'myplugin-keypair_id', 'MyPlugin Settings', 'myplugkeypair_callback', 'myplugin-keypair_page' );
            
            register_setting( 'myplugin-keypair-settings','myplugin-key');
            add_settings_field( 'myplugin-key_id', 'Access Key', 'myplugkey_callback', 'myplugin-keypair_page', 'myplugin-keypair_id' );
            
            register_setting( 'myplugin-keypair-settings','myplugin-secretkey');
            add_settings_field( 'myplugin-secretkey_id', 'Secret Key', 'myplugsecretkey_callback', 'myplugin-keypair_page', 'myplugin-keypair_id' );
    
            function myplugkeypair_callback() { 
                echo '<p>'. _e("Once you've configured your keypair here, you'll be able to use the features of this plugin.", MyPlugins).'</p>';
            }
        	function myplugkey_callback() {
            	echo '<input type="text" name="myplugin-key" value="'. get_option('myplugin-key') .'" class="regular-text"/>';
        	}
        	function myplugsecretkey_callback() {
            	echo '<input type="text" name="myplugin-secretkey" value="'. get_option('myplugin-secretkey') .'" class="regular-text"/>';
        	}
    
    }
    

    imagesWhen I got around to the massive amounts of design I put into things, I ended up making a file called lib/settings.php where I stored everything related to the settings. For me, that’s easier to manage than one massive file with lots of different calls. Easier to debug and edit too, without panicing that I broke something.

    I don’t know if it was so much I think backwards, or the API was backwards, but whatever it was, I had a massive brain-block about all this for about a day. I really have to thank Kailey and Pippin for pointing me at examples that ‘clicked’ in a way that I suddenly could figure it all out.

  • Kick PageSpeed Up A Notch

    If you’re using Apache and PHP 5.3 on your DreamHost domain, you have the magical power to enable Google PageSpeed. Just go and edit your domain and make sure you check the box for “Page Speed Optimization”:

    PageSpeed Option

    But what does that even mean, I hear you ask?

    partnersPageSpeed is Google’s way to speed up the web (yeah, that was redundant), and it serves as a way for your server to do the work of caching and compressing, taking the load off your webapps. Like WordPress. Anyone can install this on their apache server, and it’s free from Google Developers: PageSpeed Mod. Since you’re on DreamHost, you lucky ducky you, we did it for you. Now you can sit back and relax.

    The first thing to notice when you turn on PageSpeed is that it minifies your webpage. That means it takes your pretty formatted source code and gets rid of the extra spaces you don’t use. This is called by using the PageSpeed filter “collapse_whitespace.” Another filter we use is “insert_ga” which is how we’re magically able to insert your Google Analytics for you from your panel. That filter automatically inserts your GA code on every page on your domain. That’s right! No more plugins!

    If you’re like me, you may start to wonder what other filters you should use, and that entirely depend on what you want to remove. I knew I wanted to remove code comments like the following:

    <!-- #site-navigation -->
    

    That’s easy! There’s a filter for “remove_comments” so I can just use that. They have a whole mess of filters listed in the Filter Documentation and reading through it took a while. If you read each one, at the bottom they talk about how risky a certain filter is. Taking that into account, I went ahead and added some low and some high risk filters, since I know what I’m using.

    The magic sauce to add all this is just to edit your .htaccess and put in the following near the top:

    <IfModule pagespeed_module>
        ModPagespeed on
        ModPagespeedEnableFilters remove_comments,rewrite_javascript,rewrite_css,rewrite_images
        ModPagespeedEnableFilters elide_attributes,defer_javascript,move_css_to_head
        ModPagespeedJpegRecompressionQuality -1
    </IfModule>
    

    Really, that’s it.

    The ones I picked are:

    • remove_comments – Remove HTML comments (low risk)
    • rewrite_javascript – minifies JS (med. to high risk, depending on your site)
    • rewrite_css – parses linked and inline CSS, rewrites the images found and minifies the CSS (med. risk)
    • rewrite_images – compresses and optomizes images (med. risk)
    • elide_attributes – removing attributes from tags (med. risk)
    • defer_javascript – combines JS and puts it at the end of your file (high risk AND experimental!)
    • move_css_to_head – combines CSS and moves it to the head of your file (low risk)

    Now keep in mind, not all of the features will work. While DreamHost is on a pretty cutting edge version of PageSpeed, they’re constantly innovating over there and improving. The best thing about these changes is, if you do it right, you can speed your site up faster than any plugin could do for you. And that? Is pretty cool right there.

  • CentOS and PHP 5.4

    CentOS and PHP 5.4

    PHP ElephantsI finally got around to PHP 5.4

    Alas this meant reinstalling certain things, like ImageMagick and APC.

    This also brought up the question of pagespeed, which I keep toying with. I use it at work, but since this server’s on CentOS with EasyApache, there’s no ‘easy’ way to install PageSpeed yet (not even a yum install will work), so it’s all manual work plus fiddling. I don’t mind installing ImageMagick and APC, but Google’s own ‘install from source’ aren’t really optimized for CentOS, even though they say they are, and I’m nervous about the matter. Well… I did it anyway. It’s at the bottom.

    The only reason I had to do this all over is that I moved to a new major version of PHP. If I’d stayed on 5.3 and up’d to 5.3.21, that wouldn’t have mattered. But this changed a lot of things, and thus, a reinstall.

    ImageMagick

    ImageMagick I started using ImageMagick shortly after starting with DreamHost, since my co-worker Shredder was working on the ‘Have WP support ImageMagick’ project. It was weird, since I remembered using it before, and then everyone moved to GD. I used to run a photo gallery with Gallery2, and it had a way to point your install to ImageMagick. Naturally I assumed I still had it on my server, since I used to (in 2008). Well since 2008, I’ve moved servers. Twice. And now it’s no longer default.

    Well. Let’s do one of the weirder installs.

    First you install these to get your dependancies:

    yum install ImageMagick
    yum install ImageMagick-devel
    

    Then you remove them, because nine times out of ten, the yum packages are old:

    yum remove ImageMagick
    yum remove ImageMagick-devel
    

    This also cleans out any old copies you may have, so it’s okay.

    Now we install ImageMagick latest and greatest from ImageMagick:

    cd ~/tmp/
    wget http://imagemagick.mirrorcatalogs.com/ImageMagick-6.8.1-10.tar.gz
    tar zxf ImageMagick-6.8.1-10.tar.gz
    cd ImageMagick-6.8.1-10
    ./configure --with-perl=/usr/bin/perl
    make
    make install
    

    Next we install the -devel again, but this time we tell it where from:

    rpm -i --nodeps http://www.imagemagick.org/download/linux/CentOS/x86_64/ImageMagick-devel-6.8.1-10.x86_64.rpm
    

    Finally we can install the PHP stuff. Since I’m on PHP 5.4, I have to use imagick-3.1.0RC2 – Normally I’m not up for RCs on my live server, but this is a case where if I want PHP 5.4, I have to. By the way, next time you complain that your webhost is behind on PHP, this is probably why. If they told you ‘To get PHP 5.4, I have to install Release Candidate products, so your website will run on stuff that’s still being tested,’ a lot of you would rethink the prospect.

    cd ~/tmp/
    wget http://pecl.php.net/get/imagick-3.1.0RC2.tgz
    tar zxf imagick-3.1.0RC2.tgz
    cd imagick-3.1.0RC2
    phpize
    ./configure
    make
    make install
    

    Next, edit your php.ini to add this:

    extension=imagick.so
    

    Restart httpd (service httpd restart) and make sure PHP is okay (php -v), and you should be done! I had to totally uninstall and start over to make it work, since I wasn’t starting from clean.

    Speaking of clean, cleanup is:

    yum remove ImageMagick-devel
    rm -rf ~/tmp/ImageMagick-6.8.1-10*
    rm -rf ~/tmp/imagick-3.1.0RC2*
    

    APC

    APCI love APC. I can use it for so many things, and I’m just more comfortable with it than xcache. Part of it stems from a feeling that if PHP built it, it’s more likely to work. Also it’s friendly with my brand of PHP, and after 15 years, I’m uninclined to change. I like DSO, even if it makes WP a bit odd.

    Get the latest version and install:

    cd ~/tmp/
    wget http://pecl.php.net/get/APC-3.1.14.tgz
    tar -xzf APC-3.1.14.tgz
    cd APC-3.1.14
    phpize
    ./configure
    make
    make install
    

    Add this to your php.ini:

    extension = "apc.so"
    

    Restart httpd again, clean up that folder, and then one more…

    mod_pagespeed

    mod_pagespeedI hate Google. Well, no I don’t, but I don’t trust them any more than I do Microsoft, and it’s really nothing personal, but I have issues with them. Now, I use PageSpeed at work, so I’m more comfortable than I was, and first I tried Google’s installer. The RPM won’t work, so I tried to install from source, but it got shirty with me, fast, and I thought “Why isn’t this as easy as the other two were!?” I mean, APC was stupid easy, and even easier than that would be yum install pagespeed right?

    Thankfully for my sanity, someone else did already figure this out for me, Jordan Cooks, and I’m reproducing his Installing mod_pagespeed on a cPanel/WHM server notes for myself.(By the way, I keep a copy of this article saved to DropBox since invariably I will half-ass this and break my site.) Prerequisite was to have mod_deflate, which I do.

    The commands are crazy simple:

    cd /usr/local/src
    mkdir mod_pagespeed
    cd mod_pagespeed
    wget https://dl-ssl.google.com/dl/linux/direct/mod-pagespeed-beta_current_x86_64.rpm
    rpm2cpio mod-pagespeed-beta_current_x86_64.rpm | cpio -idmv
    cp usr/lib64/httpd/modules/mod_pagespeed.so /usr/local/apache/modules/
    chmod 755 /usr/local/apache/modules/mod_pagespeed.so
    mkdir -p /var/mod_pagespeed/cache
    chown nobody:nobody /var/mod_pagespeed/*
    

    Once you do this, you have to edit the file, and this is where I differ from Jordan’s direction. He just copied this over /usr/local/apache/conf/pagespeed.conf but I had an older version from a ‘Let’s try Google’s way….’ attempt and someone else’s directions, so I made a backup and then took out the ModPagespeedGeneratedFilePrefix line since I know that’s deprecated. I also added in a line to tell it to ignore wp-admin.

    Here’s my pagespeed.conf (edited):

    LoadModule pagespeed_module modules/mod_pagespeed.so
    
    	# Only attempt to load mod_deflate if it hasn't been loaded already.
    <IfModule !mod_deflate.c>
    	LoadModule deflate_module modules/mod_deflate.so
    </IfModule>
    
    <IfModule pagespeed_module>
    	ModPagespeed on
    
    	AddOutputFilterByType MOD_PAGESPEED_OUTPUT_FILTER text/html
    
    	ModPagespeedFileCachePath "/var/mod_pagespeed/cache/"
    
        ModPagespeedEnableFilters rewrite_javascript,rewrite_css
        ModPagespeedEnableFilters collapse_whitespace,elide_attributes
        ModPagespeedEnableFilters rewrite_images
        ModPagespeedEnableFilters remove_comments
    
    	ModPagespeedFileCacheSizeKb 102400
    	ModPagespeedFileCacheCleanIntervalMs 3600000
    	
    	# Bound the number of images that can be rewritten at any one time; this
    	# avoids overloading the CPU. Set this to 0 to remove the bound.
    	#
    	# ModPagespeedImageMaxRewritesAtOnce 8
    
    	<Location /mod_pagespeed_beacon>
    		SetHandler mod_pagespeed_beacon
    	</Location>
    
    	<Location /mod_pagespeed_statistics>
    		Order allow,deny
    		# You may insert other "Allow from" lines to add hosts you want to
    		# allow to look at generated statistics. Another possibility is
    		# to comment out the "Order" and "Allow" options from the config
    		# file, to allow any client that can reach your server to examine
    		# statistics. This might be appropriate in an experimental setup or
    		# if the Apache server is protected by a reverse proxy that will
    		# filter URLs in some fashion.
    		Allow from localhost
    		Allow from 127.0.0.1
    		SetHandler mod_pagespeed_statistics
    	</Location>
    
    	ModPagespeedMessageBufferSize 100000	
    	ModPagespeedDisallow */wp-admin/*
    	ModPagespeedXHeaderValue "Powered By mod_pagespeed"
    
    	<Location /mod_pagespeed_message>
    		Allow from localhost
    		Allow from 127.0.0.1
    		SetHandler mod_pagespeed_message
    	</Location>
    	<Location /mod_pagespeed_referer_statistics>
    		Allow from localhost
    		Allow from 127.0.0.1
    		SetHandler mod_pagespeed_referer_statistics
    	</Location>
    </IfModule>
    

    To tell Apache to run this, edit /usr/local/apache/conf/includes/pre_main_global.conf and add:

    Include conf/pagespeed.conf

    Note: We put this code here because EasyApache and httpd.conf will eat your changes.

    Finally you rebuild Apache config and restart apache and test your headers to see goodness! My test was a success.

    HTTP/1.1 200 OK
    Date: Mon, 21 Jan 2013 03:12:13 GMT
    Server: Apache
    X-Powered-By: PHP/5.4.10
    Set-Cookie: PHPSESSID=f4bcdae48a1e5d5c5e8868cfef35593a; path=/
    Cache-Control: max-age=0, no-cache
    Pragma: no-cache
    X-Pingback: https://ipstenu.org/xmlrpc.php
    X-Mod-Pagespeed: Powered By mod_pagespeed
    Vary: Accept-Encoding
    Content-Length: 30864
    Content-Type: text/html; charset=UTF-8
    

    For those wondering why I’m ignoring wp-admin, well … sometimes, on some servers, in some setups, if you don’t do this, you can’t use the new media uploader. It appears that PageSpeed is compressing the already compressed JS files, and changing their names, which makes things go stupid. By adding in the following, I can avoid that:

    	ModPagespeedDisallow */wp-admin/*
    

    Besides, why do I need to cache admin things anyway, I ask you?

    So there you are! Welcome to PHP 5.4!

  • Dumping ms-files

    Dumping ms-files

    Trash Can On It's SideNOTE: You do not, under any circumstances, have to do this to continue using WordPress Multisite. I just wanted to see if I could.

    I have been toying around with this. Since WP 3.5 doesn’t use ms-files anymore, I wanted to see how much of a pain this would be. While I was at the DMV (I now have a California Drivers License), I started sketching out the methods and possibilities for how one might do this as safely as possible, without bolluxing up your site. I got about 90% successful with it, so this is something I would never suggest you do on a massive, live site. If you compare it to what I did to move images from uploads to blogs.dir for the main site, it’s far more complex and annoying.

    Do you have to do this? Again, no! Everything will work just fine. Can you do it? Sure. Why did I? Support. I already know all the mishegas with blogs.dir, but the new location, and it’s lack of ms-files, promises other, weird, errors. I want to repeat, you don’t need to do anything. The Core Team was fantastic with the work they did to turn off ms-files for fresh 3.5 and up installs is nothing short of phenomenal. This was just to assuage my curious nature, and learn more about the way things work.

    You ready? Here we go.

    I decided to move the images at http://test.ipstenu.org/ to start with, so everything will use that as my example. This is after I played with it on a local site and got my steps mostly solid. I knew that live is always different than test, so I backed up the DB first (always, always, backup first!) and went to town.

    Move the images

    This is obvious. Move your images from blogs.dir/SITENUM/files/ to /uploads/sites/SITENUM/ (or make an alias). I went and did it via command line in the /uploads/sites/ folder, doing this:

    $ cp -r ~/public_html/wp-content/blogs.dir/10/files .
    $ mv files 10
    

    Lather, rinse, repeat. I could have scripted it, but I was working out the kinks until I had two left.

    Edit all sites

    Upload Path, Upload URL Path and Fileupload Url. You can blank them all out.(Corrected thanks to Nacin.)

    Blank me out

    Since you’re blanking it out for everyone you can probably do this via SQL, but since I was doing the sites one at a time, I did them one at a time.

    Fix the Database
    Search/replace each posts table for each site, changing /files/ to /uploads/SITENUM/

    UPDATE wp_10_posts SET post_content = REPLACE (
    post_content,
    '=&quot;http://test.ipstenu.org/files/',
    '=&quot;http://test.ipstenu.org/wp-content/uploads/sites/10/');
    

    Full Trash, ColorWhy did I do it that way? Because of this blog. I talk a lot about code here, and I know I’ve talked about moving files around before. If you don’t do that, you’re okay with a less precise search, but why bother? This works, it’s safe, and I’d use it again.

    That got annoying really fast. I went and grabbed my favorite Search And Replace for WordPress (and any other database) tool. Seriously I love that. I used that to follow up, change everything, and it actually worked really well for me.

    Another DB Fix!

    One of the changes in 3.5 was turning off rewriting. This took me forever and a day to find. After I did that, my images showed up fine, but the little buggers kept uploading to /files! Turns out it was all because of the site option ms_files_rewriting

    The way I got around this was by putting the following in my wp-config.php file:

    define( 'UPLOADBLOGSDIR', 'wp-content/uploads/sites' );

    And then I ran this in SQL to turn off ms_files_rewriting. Or so I thought. More in a second.

    INSERT INTO `my_database`.`wp_sitemeta` (`meta_id`, `site_id`, `meta_key`, `meta_value`) VALUES (NULL, '1', 'ms_files_rewriting', '0');
    

    I came up with that after reading through /wp-includes/functions.php line 1515.

    For most sites, this worked, but in my later work, I determined that it actually wasn’t working. It was ignoring this. I don’t know why, but every test I did merrily ignored this setting, so I finally growled and wrote this mu-plugin function:

    function stupid_ms_files_rewriting() {
            $url = '/wp-content/uploads/sites/' . get_current_blog_id();
            define( 'BLOGUPLOADDIR', $url );
    }
    add_action('init','stupid_ms_files_rewriting');
    

    It’s stupid simple, it’s probably not a good idea, but it works for the three sites that have the stupids.

    Finish up .htaccess.

    .htaccess, remove the ms-files.php line for ms-files, or comment it out. This is pretty simple.

    Empty TrashWhy not move the main site to /uploads/?

    Because of the way I fixed the uploadblogsdir. It defaulted everyone to /sites/ and after an hour I said fuck it.

    Any weird problems?

    Yeah, two sites (this one and my grandmothers) decided that they wanted to be repetitious and spat out URLs like this: wp-content/uploads/sites/8/sites/8/

    Since that wasn’t right at all, and I was a little too eggnoggy to parse why, I did this:

    RewriteCond %{HTTP_HOST} ^taffys\.org
    RewriteRule ^wp-content/uploads/sites/8/sites/8/(.*) /wp-content/uploads/sites/8/$1 [L,R=301]
    

    I swear I have no idea why three sites got stuck with /files/ and two more decided to double down, Vegas style, but frankly I’m pleased I got through this far on my own.

    I can’t stress enough that you do not have to do this!

  • Domain Registration, No Hosting

    Just want to use DreamHost for DNS? You can do that!

    Login into your Panel and go into Domain > Registrations.

    Click the “Add Hosting” button on the far right.

    It will redirect you to a new page and from that page you can select from “Fully Hosted, Redirect, etc”. The very last one is “DNS Only”.

    Go ahead and select that and there you go!

    You can also go to the Manage Domains page and click on (Add New Domain / Sub-Domain button), and scroll to the bottom of the next page to set it up for DNS Only.