Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: coding

  • Cloud Experiment

    Cloud Experiment

    While I’ve mentioned that I don’t ‘get’ CloudFlare, I took the time to buttonhole the guys at DreamCon and explain my issues. Many thanks to Maria Karaivanova for her presentation at DreamCon, too, which helped me a lot.

    Now, in so far as a ‘traditional’ CDN (where they host my images) goes, I don’t need it, but as a Cloud Proxy, I both understand and like it! The deal with a proxy is pretty simple: It’s an extra firewall between your server and users. Why is this faster? Because they have more servers than I do, which means they can handle a DDoS better than pretty much anything on Shared Servers will ever be able to do.

    Keep in mind, a VPS can handle a lot of this on it’s own. I could install Varnish and use that for caching, but it wouldn’t give me the ability to have multiple servers serving my content, and that’s what I’m looking for with my experiment here.

    It would be remiss if I didn’t note the more well known alternatives: Incapsula (starts at $19.99/month), Sucuri’s Cloud Proxy (starts at $9.99/month), MaxCDN (starts at $9.99/month), and Fastly (starts at $50/month). CloudFlare starts at ‘Free’ but its first paid offering is $20 a month for one website, $5 for each additional.

    On My Server

    I use ConfigFirewall (CSF) so I had to add in the CloudFlare IPs into csf.allow and csf.ignore. Yes, both, otherwise I got weird alert. This is pretty easy, though.

    Next I installed mod_cloudflare because I wanted to preserve the IP address without having to muck with plugins on everything. This particular site is my ‘Not all WordPress’ site after all. The catch is if I do it all manually, I have to redo it every time I upgrade via EasyApache(Don’t judge me). I already have to do that for PageSpeed. That said, cPanel suggested I read Installing mod_cloudflare on cPanel, so I did that and then ran EasyApache:

    Screen Shot of EasyApache

    So that was easy! By the way, TL Tech is one of my standard resources. They have a lot of tricks, and I’ve bookmarked ’em.

    Finally I checked out if there were issues with PageSpeed and CloudFlare. CloudFlare says no, but indicates the redundancy. That’s okay. I did an extra step of telling PageSpeed to not modify caching headers, as that’s something we did for DreamHost and Varnish (DreamPress!). Just add this to your .htaccess section for PageSpeed.

    ModPagespeedModifyCachingHeaders off
    

    On CloudFlare

    whohostsThis was straightforward. Follow their directions and it’s fine. I went for free, and fiddled with my Security Settings a lot. I hate captcha. And I know, I knooooow, the users for this site will cry if they get hit by one, so I turned my security to “Essentially Off” – This is the only way to get rid of Captcha. Sad panda. I also turned “Browser integrity check” on for now.

    In Performance Settings, I made Caching level “Simplified” and left the rest as default. Then I set up PageRules for WordPress and my other apps. You only get three rules with free (and 20 with the first level plan) so I made sure to free up the admin tools.

    On my webapps

    Last up, tackling purging caching. I’m far more familiar with this now, as I support a Varnish plugin that does much the same (and I did consider installing Varnish). The official CloudFlare plugin, for some reason, only serves the same purpose as mod_cloudflare, in that it restores IP addresses. But what I really want is a way to purge my cache with a new post. Pretend I’m saying this in that voice I used at WCSF… there’s a plugin for that: CloudFlare Cache Purge.

    Sadly there isn’t a similar plugin/extension for my other apps. And this is why I ended up at my current conclusion…

    Current Conclusion

    Sadly, even after letting it bake for a few days I determined it wasn’t quite right for me. Everything worked, and if my site was more static, it would be perfect. But this brought up the same problem I’ve had with all caches: my dynamic content gets hurt.

    cachingWhat is static that I can and should cache? JS, CSS, font files, images. What is not static? Blog posts, comments that are happening all the time, fast and furious. A gallery that needs to update. A wiki that has a deadline. Worst of all, it prevented two of my apps from being able to make their own ‘static’ cache in the background. Now really that means I shouldn’t have to make my static cache at all, but this brought up another issue. Coordinated pushes of content, where four separate apps update 1-3 pages each at the same time means I need to be able to purge those pages, right away. And right now, there aren’t extensions to do that.

    Of note: I noticed the exact same problem with Fastly and Varnish, so it’s not just CloudFlare, it’s a function of how these things are supposed to work.

    What would I need to make these desirable? Basically I need a way to purge my cache on the proxy efficiently, quickly, and selectively. Now that I work on the Varnish Cache at DreamHost, I’ve seen how deep the rabbit hole can go with this, however, and I know fully how hard this is. Proxy Caching is not for everyone. When you have dynamic content that changes for logged in users on the fly, it’s a pain. I mean, I use PageSpeed to compress and cache CSS and JS, and I have to flush it when I update my site design. Caching your caching is always going to be tricky, unless there’s a simple, one click, way to say “I’ve updated these pages, please purge them.”

    We’re not there yet.

    Recommendation

    CloudFlare is pretty awesome, actually. If you’re ‘just’ running a blog on shared hosting, I would seriously consider using it, especially in light of the various DDoS attacks out there. A cloud proxy will help you, if you don’t have server level access to tweak mod_security. The fact that CloudFlare gives you a ‘free’ option to test with, without having to give anyone your credit card info, makes it great for experimentation and puts it above the other proxies right now.

    But with all things, keep in mind your personal usage. It’s not just “Does this make my site run faster?” but it’s a lot of “Does this make my usage of my site better?” For me, they win on the first and fail on the second. Maybe one day I’ll change my workflow so cloud proxy, or Varnish, can be the answer, but that’s not today.

  • MySQL – my.cnf

    MySQL – my.cnf

    This is a fairly rare file, and one I never would have found had I not needed to run a standard SQL process via cron.

    Names have been changed to protect the innocent.

    As the story goes, no matter what I did, I could not get this one app to stop spewing out ‘smart’ quotes. You know the fancy apostrophes and quotes that curl? Well, that’s not normally a problem, like in WordPress I’d just filter it out, but in this locked down system, I didn’t have that option. I called the vendor, and they said “Make sure you don’t paste in smart quotes.”

    mysqlThat was all fine and dandy for me but I’m not the master of the universe like that. Well, not all the time. I had people to input data for me! They were going to have to manually take the forms (Word Docs), filled in by non-techs, and copy the data into the right places in the app. And you want me to tell them they have to fix this for the non-techs? I thought about how much time that would take, and decided the best fix was to change the forms! Right?

    If you’ve ever worked for a major company, you know why this was about as effective as aspirin for a root canal. No deal. So I decided to get inventive.

    The only time this was a problem, these ugly quotes, was when we ran our weekly reports. This was how I found out about it, a manager complained that there was garbage instead of quotes on the form titles. Ergo: All I need to do is script something to clean them out!

    Enter SQL!

    # REPLACE SMART QUOTES WITH STUPID ONES
    # FIRST, REPLACE UTF-8 characters.
    UPDATE `secretapp_table` SET `formtitle` = REPLACE(`formtitle`, 0xE2809C, '"');
    UPDATE `secretapp_table` SET `formtitle` = REPLACE(`formtitle`, 0xE2809D, '"');
    # NEXT, REPLACE their Windows-1252 equivalents.
    UPDATE `secretapp_table` SET `formtitle` = REPLACE(`formtitle`, CHAR(147), '"');
    UPDATE `secretapp_table` SET `formtitle` = REPLACE(`formtitle`, CHAR(148), '"');
    

    In my testing, if I ran that on formtitle, it cleaned it up for the report. This was a default report in the app, by the way, not something I had any control to change. And you wonder why I love open source? Anyhow, once I knew how this would work, I sent about scripting it. I couldn’t hook into any triggers on the app, though, because they don’t like to make it easy.

    Fine, I decided. A crontab time it is! I made this simple script to run at midnight, every night, and clean up the DB:

    #! /bin/bash
    
    mysql -h "dbname-secretapp" "secretapp_db" < "quotecleaner.sql"
    

    It worked when I ran it by hand, but it failed when cron’d. This took me some headbanging, but after reading up on how SQL works, I realized it worked when I ran it as me because I’m me! But cron is not me. I have permissions to run whatever I want in my database. Cron does not. Nor should it! So how do I script it? I don’t want the passwords sitting in that file, which would be accessible by anyone with the CMS to update it.

    I went around the corner to my buddy who was a DB expert, and after explaining my situation (and him agreeing that the cron/sql mashup was the best), he asked a simple question. “Who has access to log in as you?” The answer? Just me and the admins. The updating tool for our scripts was all stuff we ran on our PCs that pushed out to the servers, so no one but an admin (me) ever logged in directly.

    He grinned and wrote down this on a sticky “.my.cnf”

    Google and a Drupal site told me that it was a file that was used to give the mysql command line tools extra information. You shove it in the home directory of the account, and, well, here’s ours:

    # Secret App user and password
    user=secretapp_user
    password=secretapp_password
    

    The only reason I even remembered all this was because an ex-coworker said he ran into the documentation I left explaining all of this, and was thankful. He had to have it scan the body of the form now, because the managers wanted that in the report too!

  • Adding Per Site Multisite Options

    Adding Per Site Multisite Options

    johnc- said in IRC the other day, regarding the use of get_option API for WordPress “our standard practice is to use get_option to enable site specific features, if the feature needs to be unavailable for other sites then it gets broken into a separate plugin for clarity”

    diceSo to explain this for those who blinked a little we need some examples, and really this depends what you’re writing.

    We got to this point in the conversation while folks were watching my “Don’t Use WordPress Multisite” presentation from WordCamp SF. During the presentation, I mentioned that generally, when I want to write a function for a specific site on Multisite, I wrap it around a ‘If site 1, then …’ and put it in it’s own plugin file in mu-plugins. That leaves me with files like halfelf-functions.php so if I ever split the site out (see? I’m always thinking ahead) I know what file to copy.

    But that’s not the only way about it. Another way is to put all the functions in a file, and then wrap the actual filters and actions around a get_option call. Why would I want to do this instead of a separate function file? The question of portability comes up primarily. Exporting site options is not the easiest thing in the world on a Multisite, but there are cases, like my Capital H Dangit! function, where this would make sense. In general, I always want DreamHost to have a capital H, so since 99% of my sites have that on, I could, instead, use an option, since if I ever moved the one site that doesn’t use it, I just won’t bring the function over!

    Currently have wrapped that function around an ‘if site 2, then don’t run’ check, which works fine. But if I wanted to move that to options, it would go like this:

    
    // Add the default option of capital h to yes, and autoload
    add_option( 'helf_capital_H_dangit', 'yes', '', 'yes');
    
    if ( get_option( 'helf_capital_H_dangit' ) == 'yes' ) {
        foreach ( array( 'the_content', 'the_title', 'comment_text' ) as $filter )
            add_filter( $filter, 'capital_H_dangit', 11 );
    }
    
    function capital_H_dangit( $text ) { 
        [... code here ...]
    }
    

    This is pretty basic. It adds an option called helf_capital_H_dangit, auto-loads, and defaults to on for everyone. That was the easy part. The hard part is determining how to control it.

    One option is an interface where I can check a box on, say, General Settings > Writing > Formatting (right under the smilies check box would be perfect), but since I knew this was something I was going to want to control as the super-admin (that is, I don’t want the other people on my network to turn it off), I went in to the back end of my site at /wp-admin/network/site-info.php?id=2 (since this is site ) and searched for ‘Helf’

    Screen Shot 2013-08-21 at 2.21.41 PM

    I edited it to ‘no’ and saved. Boom. I can use DreamHost and Dreamhost here.

    Now this isn’t something I’d do for everything. In fact, my actual halfelf-functions.php file looks like this:

    global $blog_id;
    
    if ( $blog_id == 2 ) {
    
    	remove_filter( 'the_content', 'capital_P_dangit', 11 );
    	remove_filter( 'the_content', 'capital_H_dangit', 11 );
    
    	// I Make Plugins Filters
    }
    

    All the per-site filters are right there turned off as I want them. It’s not a lot of effort that way, and it’s still easy to pick up a site and drop it somewhere else.

    Businesswoman in Front of DoorsWhich is better? I don’t know. The real test would be to do some hardcore speed checks and see if checking for the blog ID is faster than checking for an option. I think the speed benefit gains would come from only calling this when needed, but for the limited world in which this is used, it should be fine. Also, keep in mind what both johnc- and I are saying, but in different ways: remember the 80/20 rule.

    In my opinion, if you’re making a feature that will be used by 80%+ of the sites on your Network, get_option is probably the easiest bet. If you’re making a feature that’s going to be used by 20%- of the sites, then a separate plugin (with a site_id check) is the way to go. Of course, you could do an option and default it to ‘no’ as well, but that brings up an interesting level of things to remember if you ever move a site.

    If you’ve got a more efficient way of doing the same thing, or even just a different way, speak up! More options are always better.

    Oh and no, we’re not going to sneakily install this on DreamPress, but if I did, it would also capitalize DreamPress, DreamCompute, and everything else out there. But I won’t.

  • WordPress Media Library: Show ID

    WordPress Media Library: Show ID

    random-rotation-galleryWhile this is considerably less of an issue with the new Media Uploader, and how it inserts your gallery code, this used to be a hassle. The old [gallery] code would just be that, a short tag, and if included all images attached to a post. So if you wanted it to exclude some images, you had to figure out their IDs, or remove them from the post.

    I used to have to show people how to do this all the time. Hover over the image, note the URL, bleh bleah bleaaaaaaaaah.

    So what if the images showed the IDs? Hey! You can do that with this function!

    function column_id($columns) {
        $columns['colID'] = __('ID');
        return $columns;
    }
    add_filter( 'manage_media_columns', 'column_id' );
    function column_id_row($columnName, $columnID){
        if($columnName == 'colID'){
           echo $columnID;
        }
    }
    add_filter( 'manage_media_custom_column', 'column_id_row', 10, 2 );
    

    And there you go. I don’t actually use this anymore, but it was sitting in my scrapbook of functions.

    If you’re wondering about the right way to handle galleries today, the gallery editor lets you configure what images are and aren’t in it through a GUI, so you don’t need to mess with this. Just click on the gallery to edit it, remove the images you don’t want, add the new ones, and off you go. About the only thing it doesn’t do is let me select how I want the images to like (URL, file, or none), and I still don’t have the option to link to an external URL. Ah well.

  • Code By Any Other Name

    Code By Any Other Name

    red_rose__lips-wideWhile this post is mostly geared to how to better name WordPress themes and plugins, the concepts should be easy to extrapolate for just about any bit of code. One of the hardest things to do, as a developer, is to come up with a name for your plugin or theme. Sometimes it’s really easy, like if you want to make a plugin that shows the phases of the moon as a widget, you’d probably call it ‘Phases of the Moon Widget.’ But is that the best name to give your plugin?

    One of the least obvious aspects of plugins is that the name you submit when you fill in the form on the WordPress Add a Plugin Page is the name you get for your plugin. So if you submitted ‘Phases of the Moon Widget’ then you get the url http://wordpress.org/plugins/phases-of-the-moon-widget, and that will also be the name of the folder on someone’s blog: /wp-content/plugins/phases-of-the-moon-widget/. That may not be what you wanted.

    When you’re coming up with the name of your plugin, few people give thought to the ‘slug’ you get with your plugin. They try to think of a name that is evocative and descriptive, but often not short and succinct. One might think, in this Twitter/SMS world, we’d be better coming up with short plugin names, but we often get plugins like ‘recently-used-categories-with-alphabetical-or-most-used-ordering’ and then the author gets annoyed with his URL.

    In fairness to everyone, this isn’t well understood. And even I have plugin names I regret in the long run. The process is a little mystical and magical to how someone should be submitting a plugin with name and description. After all, you have more than one name and description to consider. You have the name, the slug, the description and the readme. Ouch! How do you do it?

    Base BellesFor this example, I’m going to pretend I wrote a plugin that pulls in data from mlb.com and sends an email to people on my blog every time the Cleveland Indians win a game. I plan for this plugin to be used for a BuddyPress community (The Base-Belles), but after I wrote it, I realized I could make this work for any MLB team, and for wins and losses. Thus I now have a plugin that, on my site, is probably called “Indians Game Winner Emails” and has a slug like “indians-winner-emails” or something weird like that. When I write code just for myself, I rarely concern myself with anything fussy with names.

    I’ve also made a theme for this site that I want to share, and I’ve called it “Base-Belles” (after the site), but if I release this to the world, I’d want to make it something everyone can use for any team’s fan group, so I will genericize that up.

    When you submit a plugin, you’re asked for a name, a description and a zip. So let’s get started. When you submit a theme, you’re uploading the zip directly, and it’s in there you pick your name and slug. So for themes, this is less of a hassle, but the basic principle remains.

    The Name

    Even themes have two ‘names.’ You have your slug-name and your name-name. As I go to submit my plugin name, I might be tempted to type in “MLB Game Results Emailer by the Base-Belles” and in some ways, that is a great name for a plugin. It’s descriptive after all. But the first thing you need to do is drop any mention of ‘by…’ with your submissions. That’s just not needed, as a theme has a style.css to show who wrote it, and a plugin has the readme. We’ll know.

    That means your name is now “MLB Game Results Emailer” which looks great. Or does it. Do I really want the slug mlb-game-results-emailer? What about mlb-results-alerts instead? That’s not much shorter, but as a slug goes, it’s descriptive. Even mlb-results-mail would be better. They’re to the point, and when I read the list of plugins via SSH or SFTP, I’ll know right away which plugin it goes with. This means I will submit my plugin with the name “MLB Results Mail” and I’m happy.

    If this was a theme, I’d call it “Base-Belles” after the site, and use the slug base-belles. Boy that would be easy. Except … I generalized it, didn’t I? Now I have “MLB Fansite Theme for BuddyPress” which is a good name, but a bad slug. So for a slug, I’d use mlb-fansite instead. My child theme for my own site will become base-belles and now I’m happy here too! If I was really clever and totally made the theme generic, it would become “Sports Team Fansite” and sports-fansite.

    Descriptions

    When we ask for a description what we really want is your short description. “This plugin sends an email to your subscribers every time your chosen baseball team wins a game.” Or a theme “This BuddyPress optimized theme is perfect for running fan-sites for baseball teams.” This is all anyone wants to see for a short description. It should fit in a tweet. Short, simple, perfect.

    Why don’t we want all the details? Well for one you overwhelm us with too much information at once if you paste in the readme. And for another, themes and plugins gets hundreds of reviews to comb through a day. Keeping it simple and short saves us time, which makes it easier for us to work through high volume. Where we want to see details is in your readme.txt. These are absolutely required for a couple reasons. First (and most important) we want to know that you’re ready to go live. A plugin should only be submitted when it’s ready to be released to the wild, after all, and that means you have a fully finished wordpress.org repository page which is handled by (you guessed it) the readme. If I can’t read your readme and go “Aha, that’s how the plugin is installed and configured and that’s how I use it” then you have done something wrong. The readme.txt is your gateway drug. Love it. Make it sing.

    Something I often tell people who have had plugins rejected is that when they resubmit “Put ‘I talked to Ipstenu about XYZ’ in the description so we know you’ve already spoken to one of us. That makes it painless for me to look in our group email box, find the previous conversation, make sure we’re all on the same page, and approve. Also if I both handled the earlier conversation and I see your submission, it’ll trigger my memory and I’ll get through your ticket faster.

    ZIPs

    As of today, you cannot submit a plugin or theme to the WordPress.org repositories without a zip. not a RAR, not a gzip, but a zip.

    I love getting zip files, but many times people submit zips that don’t open on linux, or have another zip in them. What we want in that zip is your complete plugin that I could upload to a test site. A theme will be auto-rejected by their scanner if it doesn’t meet their standards, you’ll have to start over. Plugins we still review everything by hand, so we have to open your zip. Personally, I use TextWrangler, which actually lets me open a zip without having to unzip it, but sometimes people zip things weirdly and I have to open it and drag the folder up.

    If you’re using Github, there’s a built in link to a zip, which you can send us. BUT. Keep in mind, the zip will not bring in submodules. Yeah, ain’t that a damn dirty trick? You can use it to update your own code, but anyone who pulls down a zip to test with won’t get it. That really annoys me, and I’m not sure if it’s a bug or something Git did intentionally. Oh, submodules. You’re so complicated.

    Do we care what you name your plugin’s zip? No. Do we care that you’re calling that name explicitly in your code? Yes. Use functions to determine directories and save us all a hassle. Do we care about calling wp-config.php and other WordPress core files by name? We sure do, but that’s another topic altogether.

    Summary

    In summary? Short slugs, descriptive names, simple descriptions, detailed readmes.

    Of course, that’s high level stuff and doesn’t explain how to pick a plugin name. I’m highly fond of puns (hence Genericon’d) or I name things based on their original concept (rss2email was plugin’d as post2email). Sometimes the name is just obvious (Rickroll). Do you have tricks for coming up with a good name?

  • How To Duplicate Content

    How To Duplicate Content

    I’ve talked about this before. 100% duplication of content on multiple sites is bad. So why am I going to tell you how to do it? And better, why am I going to tell you how to do it without Multisite? Because as a proof-of-concept, it was interesting.

    The rest of this post tells you how to do something I don’t advocate, nor will I support. If you have a better way, or improvements, please leave comments. Otherwise, you’re on your own when you do this. I will not help you do it in any way, shape, or form.

    Honestly, I still think this is a pretty silly idea. Duplicating content is a terrible user experience, and I still flat-out decline to accept any work for doing this. Sharing content is one thing, but 100% duplication of sites makes no sense at all to me. Yoast also says it’s a bad idea. But, if you really are totally 100% dedicated to do this, and you absolutely are going to, damn the torpedos, then you should do this in the least computationally expensive way possible. And that would be a single install.

    Now all that said, this means you’ll need to do a lot of monkey-work, so why do I call this ‘easier’? In many ways, easy is relative and this will be hard, complicated, and may I stress, entirely unnecessary. You’re going the hard way around for something that good planning and a solid understanding of the Internet totally negates. Remember the absolute rule of the Internet: Use one URL per page and never change that URL. (With all rules, there are exceptions, of course.)

    The way to make all this work, without Multisite, is by tricking your domain a little. There’s a neat trick with parking (or mirroring, depends on your host) domains, that lets you keep the other domain URL in your browser’s address bar. That’s what I do with this site, actually, halfelf.org is parked on top ipstenu.org. And with a park, the URL always stays as halfelf.org. Hey look! Two URLs, one site! Multisite has secret sauce to know “Someone’s coming to HalfElf, send ’em to site .” But on a single site, all my links would still be ipstenu.org and not halfelf.org.

    Now how do you use this to duplicate content? You use relative URLs.

    So here’s a real example. I have twofer.elftest.net set up to mirror plugins.elftest.net (which will give you a coming soon page, it’s just where I like to blow things up for tests).

    In the beginning of this post, when I linked to my old post about Duplication Dilution, the URL was https://halfelf.org/2012/duplication-dillution/ and that is what we call an absolute URL. Because I’m mapping domains, I can leave those in without worry, but if I wasn’t, I’d change that URL to /2012/duplication-dillution/ instead. Right away this makes my URLs entirely relative, no domain name included, and I’m off to the races.

    This doesn’t solve everything, though. See, WordPress really wants to use absolute URLs. There are plugins like root relative URLs, and those will help a lot. None of them back-ports your existing posts, though, so for that it’s nothing for it but to search/replace the DB and change your post content.(ONLY change your post content. Do not change GUIDs!) I really like those plugins because now for a new post, when I add a link and chose to link to existing content, it happily works:

    addinglink

    And when I add an image, it too smartly handles as I want it to:

    addingimages

    That’s the easy part of all this, though. Now you have to disable canonical URLs, so that you don’t end up with even more of the dread duplicate content penalty in WordPress.

    remove_action('wp_head', 'rel_canonical');
    

    This also stops WP from redirecting things like http://plugins.elftest.net/?p=1 as well, however, so keep that in mind. Of course, that’s what you wanted. But they don’t address the problem of your source code. If I view source on twofer.elftest.net, it still showed plugins.elftest.net, and that would be a problem for images and themes. You’ll need to toss in this to your wp-config.php, which will dynamically change your URL to be whatever URL I’m visiting from, so that changes automatically. Awesome.

    define('WP_HOME', 'http://' . $_SERVER['HTTP_HOST']);
    define('WP_SITEURL', 'http://' . $_SERVER['HTTP_HOST']);
    define('DOMAIN_CURRENT_SITE', $_SERVER['HTTP_HOST']);
    

    Now I want to tell WordPress that wp-content is not in URL/wp-content/ so let’s just put this in and make it relative too!

    define('WP_CONTENT_URL', '/wp-content');
    

    I’m still going to have to search and replace my old post content (I used Velvet Blues for this):

    Velvet Blue Update

    But that didn’t address the problem of the source code. 90% of WP now thinks it’s all on twofer, which is what I wanted, but look at XMLRPC:

    sourcecode

    the_more_you_know2And even better, when I try to log in via twofer, it still says I’m going to plugins. Oh and it doesn’t pass through cookies, so really, I never log in to Twofer. Realistically? This isn’t a problem. I’m always going to use plugins.elftest for all this when I log in on the backend, and since the convenience of all this was meant for the front end, and it’s just pingbacks. And why is that? Honestly, I don’t know. I have a guess that since, at WordPress’ heart, the site is always plugins, the absolute URL there has to be what it is, but in so far as all that goes, I think it meets the needs of why most people want to do this.

    Conclusions? You can do this. If you wanted to, you can hardcode the theme so the domain you visit the site with will dynamically change the header image, or widgets, or anything else you want. PHP is pretty cool that way and WordPress is too. But I would never do it, except as an experiment to see what I could do it at all.