PageRenderTime 36ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/https-domain-alias.php

https://gitlab.com/Blueprint-Marketing/wp-https-domain-alias
PHP | 421 lines | 195 code | 52 blank | 174 comment | 45 complexity | 134895ab29f9ba39294476f121d8df61 MD5 | raw file
  1. <?php
  2. /**
  3. * Plugin Name: HTTPS domain alias
  4. * Plugin URI: https://github.com/Seravo/wp-https-domain-alias
  5. * Description: Enable your site to have a different domains for HTTP and HTTPS. Useful e.g. if you have a wildcard SSL/TLS certificate for server but not for each site.
  6. * Version: 1.3.3
  7. * Author: Seravo Oy
  8. * Author URI: http://seravo.fi
  9. * License: GPLv3
  10. */
  11. /** Copyright 2015 Seravo Oy
  12. This program is free software; you can redistribute it and/or modify
  13. it under the terms of the GNU General Public License, version 3, as
  14. published by the Free Software Foundation.
  15. This program is distributed in the hope that it will be useful,
  16. but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. GNU General Public License for more details.
  19. You should have received a copy of the GNU General Public License
  20. along with this program; if not, write to the Free Software
  21. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  22. */
  23. /**
  24. * @package HTTPS_Domain_Alias
  25. *
  26. * Make sure a https capable domain is used {@see HTTPS_DOMAIN_ALIAS} if the
  27. * protocol is HTTPS.
  28. *
  29. * Make sure the wp-config.php defines the needed constants, e.g.
  30. * define('FORCE_SSL_LOGIN', true);
  31. * define('FORCE_SSL_ADMIN', true);
  32. * define('HTTPS_DOMAIN_ALIAS', 'coss.seravo.fi');
  33. *
  34. * On a WordPress Network install HTTPS_DOMAIN_ALIAS can also be
  35. * defined with a wildcard, e.g. '*.seravo.fi'.
  36. * Compatible with WordPress MU Domain Mapping.
  37. *
  38. * Example:
  39. * Redirect never points to https://coss.fi/..
  40. * but instead always to https://coss.seravo.fi/...
  41. *
  42. * For more information see readme.txt
  43. *
  44. * @param string $url
  45. * @param string $status (optional, not used in this function)
  46. * @return string
  47. */
  48. function htsda_https_domain_rewrite( $url, $status = 0 ) {
  49. // Rewrite only if the request is https, or the user is logged in
  50. // to preserve cookie integrity
  51. if ( substr( $url, 0, 5 ) == 'https'
  52. || ( function_exists( 'is_user_logged_in' ) && is_user_logged_in()
  53. && ! ( defined( 'DISABLE_FRONTEND_SSL' ) && DISABLE_FRONTEND_SSL ) ) ) {
  54. // Assume domain is always same for all calls to this function
  55. // during same request and thus define some variables as static.
  56. static $domains;
  57. if ( ! isset( $domains ) ) {
  58. $domains = array();
  59. // $domain is current site URL without the www prefix
  60. // TODO: can we just strip www? convention says yes
  61. $domains[] = hstda_trim_url(parse_url( get_option( 'home' ), PHP_URL_HOST ), 'www.');
  62. // Also take the current request host so this works even when redirect_canonical is not in use
  63. $domains[] = hstda_trim_url($_SERVER['HTTP_HOST'], 'www.');
  64. }
  65. static $domainAlias;
  66. if ( ! isset( $domainAlias ) ) {
  67. $domainAlias = htsda_get_domain_alias($domain);
  68. }
  69. // If $location does not include simple https domain alias, rewrite it.
  70. $url = hstda_rewrite_url($url,$domains,$domainAlias);
  71. }
  72. return $url;
  73. }
  74. /**
  75. * Same as above, but handles all domains in a multisite
  76. */
  77. function htsda_mu_https_domain_rewrite( $url, $status = 0 ) {
  78. // Rewrite only if the request is https, or the user is logged in
  79. // to preserve cookie integrity
  80. if ( substr( $url, 0, 5 ) == 'https'
  81. || ( function_exists( 'is_user_logged_in' ) && is_user_logged_in()
  82. && ! ( defined( 'DISABLE_FRONTEND_SSL' ) && DISABLE_FRONTEND_SSL ) ) ) {
  83. // these won't change during the request
  84. static $domains;
  85. if ( !isset( $domains ) ) {
  86. $blogs = wp_get_sites(); // get info from wp_blogs table
  87. $domains = array(); // map the domains here
  88. $domains[] = hstda_trim_url(parse_url( get_site_url( 1 ), PHP_URL_HOST ), 'www.'); // main site home
  89. // special case for wpmu domain mapping plugin
  90. if( function_exists('domain_mapping_siteurl') ) {
  91. $domains[] = hstda_trim_url(parse_url( domain_mapping_siteurl( false ), PHP_URL_HOST ), 'www.');
  92. }
  93. foreach ( $blogs as $blog ) {
  94. $domains[] = hstda_trim_url($blog['domain'],'www.');
  95. }
  96. // dedupe domains
  97. $domains = array_unique( $domains );
  98. }
  99. // Rewrite the $url
  100. $url = hstda_rewrite_url($url,$domains);
  101. }
  102. return $url;
  103. }
  104. /**
  105. * Gets the domain alias for the given domain
  106. */
  107. function htsda_get_domain_alias( $domain ) {
  108. if ( substr( HTTPS_DOMAIN_ALIAS, -strlen( $domain ) ) == $domain ) {
  109. // Special case: $domainAlias ends with $domain,
  110. // which is possible in WP Network when requesting
  111. // the main site, don't rewrite urls as a https
  112. // certificate for sure exists for direct domain.
  113. // e.g. domain seravo.fi, domain alias *.seravo.fi
  114. return $domain;
  115. }
  116. else if ( substr( HTTPS_DOMAIN_ALIAS, 0, 1 ) == '*' ) {
  117. if(false !== strpos($domain, substr( HTTPS_DOMAIN_ALIAS, 1 )) ) {
  118. // never include the https domain alias part in the domain base
  119. $domainBase = substr( $domain, 0, strrpos( $domain, substr( HTTPS_DOMAIN_ALIAS, 1 ) ) );
  120. } else {
  121. // domain base is everything before the TLD part
  122. // TODO: what about dual TLD's like .co.uk ?
  123. $domainBase = substr( $domain, 0, strrpos( $domain, '.' ) );
  124. }
  125. // substitute dots with dashes so that we never end up in sub-sub domains
  126. $domainBase = str_replace('.', '-', $domainBase);
  127. $domainAliasBase = substr( HTTPS_DOMAIN_ALIAS, 1 );
  128. return $domainBase . $domainAliasBase;
  129. }
  130. else {
  131. return HTTPS_DOMAIN_ALIAS;
  132. }
  133. }
  134. /**
  135. * Debug wrapper
  136. *
  137. *
  138. * @param string $url
  139. * @param string $path
  140. * @param string $plugins
  141. * @return string $url
  142. */
  143. function htsda_debug_rewrite( $url, $path=false, $plugin = false, $extra = false ) {
  144. error_log( "in: $url" );
  145. $url = is_multisite() ? htsda_mu_https_domain_rewrite( $url ) : htsda_https_domain_rewrite( $url );
  146. error_log( "out: $url" );
  147. return $url;
  148. }
  149. /**
  150. * Includes a patch for Polylang Language plugin, which redefines home_url in the back-end
  151. */
  152. function htsda_home_url_rewrite( $url ) {
  153. // Store the original url in global constant so that we can use it later to fix things
  154. if (!defined('HTTPS_DOMAIN_ALIAS_FRONTEND_URL')) {
  155. $parsed_url = parse_url($url);
  156. define('HTTPS_DOMAIN_ALIAS_FRONTEND_URL', $parsed_url['scheme'].'://'.$parsed_url['host'].$parsed_url['path']);
  157. }
  158. // don't rewrite urls for polylang settings page
  159. if ( isset($_GET['page']) && $_GET['page'] == 'mlang' ) {
  160. return $url;
  161. }
  162. $url = is_multisite() ? htsda_mu_https_domain_rewrite( $url ) : htsda_https_domain_rewrite( $url );
  163. return $url;
  164. }
  165. /**
  166. * Additional functionality to make all links relative
  167. *
  168. * This helps keep the front end clean of any HTTPS domain alias links
  169. *
  170. * Thanks to @chernjie for the idea!
  171. */
  172. /**
  173. * This converts any link to slash-relative
  174. *
  175. * NOTE: this applies to external links as well, so be careful with this!
  176. */
  177. function htsda_root_relative_url( $url, $html ) {
  178. // If urls already start from root, just return it
  179. if ( $url[0] == "/" ) return $html;
  180. $p = parse_url( $url );
  181. $root = $p['scheme'] . "://" . $p['host'];
  182. $html = str_ireplace( $root, '', $html );
  183. return $html;
  184. }
  185. /*
  186. * Media gallery images should be handled with relative urls
  187. */
  188. function htsda_root_relative_image_urls( $html, $id, $caption, $title, $align, $url, $size, $alt ) {
  189. return htsda_root_relative_url( $url, $html );
  190. }
  191. function htsda_root_relative_media_urls( $html, $id, $att ) {
  192. return htsda_root_relative_url( $att['url'], $html );
  193. }
  194. /*
  195. * This adds a small javascript fix for the TinyMCE link adder dialog
  196. */
  197. function htsda_link_adder_fix( $Hook ) {
  198. if ( 'post.php' === $Hook || 'post-new.php' === $Hook ) {
  199. // we only need to use this fix in post.php
  200. wp_enqueue_script( 'link-relative', plugin_dir_url( __FILE__ ) . 'link-relative.js' );
  201. }
  202. }
  203. /*
  204. * Register filters only if HTTPS_DOMAIN_ALIAS defined
  205. */
  206. if ( defined( 'HTTPS_DOMAIN_ALIAS' ) ) {
  207. // A redirect or link to https may happen from pages served via http
  208. $domain_filter = is_multisite() ? 'htsda_mu_https_domain_rewrite' : 'htsda_https_domain_rewrite';
  209. add_filter( 'login_url', $domain_filter );
  210. add_filter( 'logout_url', $domain_filter );
  211. add_filter( 'admin_url', $domain_filter );
  212. add_filter( 'wp_redirect', $domain_filter );
  213. add_filter( 'plugins_url', $domain_filter );
  214. add_filter( 'content_url', $domain_filter );
  215. add_filter( 'theme_mod_header_image', $domain_filter );
  216. add_filter( 'wp_get_attachment_url', $domain_filter );
  217. add_filter( 'wp_get_attachment_thumb_url', $domain_filter );
  218. add_filter( 'site_url', $domain_filter );
  219. add_filter( 'home_url', 'htsda_home_url_rewrite' );
  220. // Force relative urls for links created in the wp-admin
  221. add_filter( 'media_send_to_editor', 'htsda_root_relative_media_urls', 10, 3 );
  222. add_filter( 'image_send_to_editor', 'htsda_root_relative_image_urls', 10, 9 );
  223. add_action( 'admin_enqueue_scripts', 'htsda_link_adder_fix' );
  224. } else {
  225. error_log( 'Constant HTTPS_DOMAIN_ALIAS is not defined' );
  226. }
  227. /*
  228. * Make sure this plugin loads as first so that the filters will be applied
  229. * to all plugins before they fetch or define any URLs.
  230. *
  231. * This function will only take effect at the time when some plugin is activated,
  232. * does not apply directly for old installs and in general is brittle to brake,
  233. * as something else might edit the plugin list in the database options table
  234. * and thus lower the priorty for this plugin.
  235. */
  236. add_action( 'activated_plugin', 'htsda_https_domain_alias_must_be_first_plugin' );
  237. function htsda_https_domain_alias_must_be_first_plugin() {
  238. // ensure path to this file is via main wp plugin path
  239. $wp_path_to_this_file = preg_replace( '/(.*)plugins\/(.*)$/', WP_PLUGIN_DIR."/$2", __FILE__ );
  240. $this_plugin = plugin_basename( trim( $wp_path_to_this_file ) );
  241. $active_plugins = get_option( 'active_plugins' );
  242. $this_plugin_key = array_search( $this_plugin, $active_plugins );
  243. if ( $this_plugin_key ) { // if it's 0 it's the first plugin already, no need to continue
  244. array_splice( $active_plugins, $this_plugin_key, 1 );
  245. array_unshift( $active_plugins, $this_plugin );
  246. update_option( 'active_plugins', $active_plugins );
  247. }
  248. }
  249. /*
  250. * A function for determining if we're currently on a login page
  251. */
  252. function is_login_page() {
  253. return in_array( $GLOBALS['pagenow'], array( 'wp-login.php', 'wp-register.php' ) );
  254. }
  255. /*
  256. * Redirects non logged in visitors away from the visible domain alias front
  257. * end. This also makes sure search engines don't index the domain alias but
  258. * rather the actual canonical site thus improving site SEO.
  259. */
  260. add_action( 'wp', 'htsda_https_domain_alias_redirect_visitors' );
  261. function htsda_https_domain_alias_redirect_visitors() {
  262. // check if visitor is currently in a domain alias location
  263. $is_on_domain_alias = strpos( get_option( 'HOME' ), $_SERVER['HTTP_HOST'] );
  264. if ( ! $is_on_domain_alias &&
  265. ! is_user_logged_in() &&
  266. ! is_login_page() ) {
  267. wp_redirect(get_option( 'HOME' ) . $_SERVER['REQUEST_URI'], 301 );
  268. }
  269. }
  270. /**
  271. * Create a readme page in the settings menu
  272. */
  273. add_action( 'admin_menu', 'htsda_https_domain_alias_readme' );
  274. function htsda_https_domain_alias_readme() {
  275. //Readme is only visible, when HTTPS_DOMAIN_ALIAS is not defined
  276. if ( ! defined( 'HTTPS_DOMAIN_ALIAS' ) ) {
  277. add_options_page( 'HTTPS Domain Alias', 'HTTPS Domain Alias', 'administrator', __FILE__, 'htsda_build_readme_page', plugins_url( '/images/icon.png', __FILE__ ) );
  278. }
  279. }
  280. /*
  281. * Helper: Rewrite url if it's pointing to this site
  282. *
  283. * @param string well formed url
  284. * @param array domains of the site
  285. * (optional)@param string ssl secured domain alias of the site
  286. */
  287. function hstda_rewrite_url($url,$domains,$domainAlias=NULL) {
  288. $parts = parse_url($url);
  289. // Strip www. from url
  290. $parts['host'] = hstda_trim_url($parts['host'], 'www.');
  291. // Only rewrite local urls
  292. if (isset($parts['host']) && !in_array($parts['host'],$domains)) {
  293. return $url; // If the host is eg. twitter.com leave it unchanged
  294. } else {
  295. $parts['scheme'] = "https";
  296. $parts['host'] = (isset($domainAlias)) ? $domainAlias : htsda_get_domain_alias($parts['host']);
  297. // TODO Is there cases where we should also replace $parts['query'] ?
  298. return hstda_build_url($parts);
  299. }
  300. }
  301. /*
  302. * Helper: Build an URL
  303. * Useful for building new url from @return value of parse_url()
  304. *
  305. * @param mixed (Part(s) of) an URL in form of a string or associative array like parse_url() returns
  306. * @param mixed Same as the first argument
  307. */
  308. function hstda_build_url($parts){
  309. return
  310. ((isset($parts['scheme'])) ? $parts['scheme'] . '://' : '')
  311. .((isset($parts['user'])) ? $parts['user'] . ((isset($parts['pass'])) ? ':' . $parts['pass'] : '') .'@' : '')
  312. .((isset($parts['host'])) ? $parts['host'] : '')
  313. .((isset($parts['port'])) ? ':' . $parts['port'] : '')
  314. .((isset($parts['path'])) ? $parts['path'] : '')
  315. .((isset($parts['query'])) ? '?' . $parts['query'] : '')
  316. .((isset($parts['fragment'])) ? '#' . $parts['fragment'] : '')
  317. ;
  318. }
  319. /*
  320. * Trims $prefix if it exists in the beginning of the string
  321. * This is alot faster than regex
  322. * See: http://stackoverflow.com/a/4517270/1337062
  323. */
  324. function hstda_trim_url($str,$prefix) {
  325. if (substr($str, 0, strlen($prefix)) == $prefix) {
  326. $str = substr($str, strlen($prefix));
  327. }
  328. return $str;
  329. }
  330. /*
  331. * Display the readme page
  332. */
  333. function htsda_build_readme_page() { ?>
  334. <div class="wrap">
  335. <h2>HTTPS Domain Alias</h2>
  336. <div id="message" class="error">
  337. <p><?php _e('This readme page is only visible when HTTPS_DOMAIN_ALIAS is not defined in wp-config.php. You will not see this once the constant is defined.', 'htsda' );?></p>
  338. </div>
  339. <?php include( 'admin-readme.html' ); ?>
  340. <p>&nbsp;</p>
  341. <p><small>HTTPS Domain Alias is made by <a href="http://seravo.fi/">Seravo Oy</a>, which specialize
  342. in open source support services and among others is the only company in Finland to provide
  343. [WordPress Premium Hosting](http://seravo.fi/wordpress-palvelu).</small></p>
  344. </div>
  345. <?php
  346. }
  347. /**
  348. * A helper sorter function by string length
  349. */
  350. function _by_length($a, $b){
  351. return strlen($b) - strlen($a);
  352. }
  353. /*
  354. * Change how the permalink is shown in backend editor view
  355. */
  356. add_filter('get_sample_permalink_html','htsda_sample_permalink_html',5,1);
  357. function htsda_sample_permalink_html($content){
  358. if (defined('HTTPS_DOMAIN_ALIAS_FRONTEND_URL')) {
  359. $domain_alias = htsda_home_url_rewrite(HTTPS_DOMAIN_ALIAS_FRONTEND_URL);
  360. // Replace url between <a> tags
  361. // If we just replace from everywhere it breaks preview links
  362. $content = str_replace('>'.$domain_alias,'>'.HTTPS_DOMAIN_ALIAS_FRONTEND_URL,$content);
  363. }
  364. return $content;
  365. }