Enable Complete support for SSL on Wordpress

By 'complete' I mean: required SSL on the login and register pages as well as the entire admin section, and optional SSL for the entire blog for private reading. And when there is SSL, everything is transfered over SSL.

The first step is to enable SSL for administration. This is well documented within Wordpress, just add the following statement to your wp-config.php:

define('FORCE_SSL_ADMIN', true);

This will also force the links to the login, register, and forgot password pages to show up as 'https'. Wordpress will also force SSL if you navigate to the pages directory.

The second step is to set the relative options, settings, and constants to enable optional support for private browsing. Unfortunately Wordpress has no 'if https, only https' switch. Such that if you try to use 'https://yourblogurl.tld" the page may include images and plugin content over http causing a 'partial' SSL session (this is no good). We CANNOT enable private browsing if images are still transfered in clear-text.

This is a bit of a hack, and it looks a bit annoying. If you have a better engineered solution please let me know. Open your wp-config again and towards the top add:

define('WP_SITE_URI', ($_SERVER["HTTPS"]?"https://":"http://").$_SERVER["SERVER_NAME"]);
define('WP_SITEURI', ($_SERVER["HTTPS"]?"https://":"http://").$_SERVER["SERVER_NAME"]);

You could abstract out your domain if you'd like. This example assumes your blog is located in the top directory. Add a sub-directory at the end if you require. Then somewhere BEFORE the include for 'wp-settings' insert:

define("WP_CONTENT_URL", WP_SITE_URI . "/wp-content");

Then after the include of 'wp-settings' add:

wp_cache_set("siteurl_secure", "https://" . $_SERVER["SERVER_NAME"], "options");
wp_cache_set("home", WP_SITE_URI, "options");
wp_cache_set("siteurl", WP_SITE_URI, "options");

Yes, I know SERVER_NAME is repeated. I too feel dirty for having to add so much to Wordpress's configuration. The lead to rewrite the cache values was from noctis' blog (interesting that he does not support optional SSL).

Explanation: The optional part is the killer, since you want the ability to serve Wordpress in clear-text you need to make sure your 'siteurl' setting is set to use 'http://'. This setting is pulled from the database and used to set a constant called 'WP_CONTENT_URL'. Other constants will also inherit the 'http://' from WP_CONTENT_URL. Since constants are as they sound, you need to set it correctly before 'wp-settings' queries the database for the wrong value. However you must wait until 'wp-settings' includes the necessary functions to manipulate the cache. This is why we must wrap the include for 'wp-settings' to change all possible setting variables to support either HTTP or HTTPS.

Not done yet? Of course not! The last change is implemented as a plugin. (You could add it anywhere really.) We need to add a filter to replace all uploaded content to run over either HTTP or HTTPS. Whenever you insert an image into a post a corresponding <img src="http://" will be hard-coded into the post (if your saved 'siteurl' uses 'http://'). Create a plugin folder, name it something like 'content over ssl'. Inside create a like-named php file and inside include:

/* Plugin Name: Content over SSL
 * Description: Re-write content URIs to use the appropriate protocol
 * Author: Me
 * Version: .1

add_filter('the_content', 'my_ssl');

function my_ssl($content) {
  if (isset($_SERVER["HTTPS"]))
    $content = ereg_replace("http://" . $_SERVER["SERVER_NAME"], "https://" . $_SERVER["SERVER_NAME"], $content);
  return $content;

This will rewrite any hard-coded links in your post's content, to your domain name, to use HTTPS if the page is called using HTTPS. Remember to enable the plugin you just created in the Wordpress administration menus.

This was tested on Wordpress 3.0 running on Apache. Note: you'll need to setup SSL support yourself. :)