Link to home
Start Free TrialLog in
Avatar of Julian Hansen
Julian HansenFlag for South Africa

asked on

WP_CONTENT_URL Constant changes its value mid-execution

I have been asked to look at a WordPress blog that is not displaying correctly after change over to HTTPS. I did a WP CLI search and replace on the URLS which amended some of the URLS but the links to styles and scripts is still on HTTP.

After doing some debugging in the core I discovered the following anomaly. The constant WP_CONTENT_URL which is set from the get_option('siteurl') is CHANGING its value mid execution.
I have put debug statements into

wp-includes\link-template.php
And
wp-includes\default-constants.php

To try and see what is going on.

I placed debug in the function plugins_url(); (the DEBUG statements dump out various variables, constants and returns from function calls)

Before the header.php of the template is loaded I get this

DEBUG path: searchwp-live-ajax-search  // (path passed to the function)
DEBUG siteurl: https://www.domain.com/blog // (result of get_option('siteurl');
DEBUG WP_CONTENT_URL: https://www.domain.com/blog/wp-content  // Dump of the WP_CONTENT_URL
DEBUG WPMU_PLUGIN_URL: https://www.domain.com/blog/wp-content/mu-plugins // Dump of the WPMU_PLUGIN_URL
DEBUG WP_PLUGIN_URL: https://www.domain.com/blog/wp-content/plugins  // Dump of the WP_PLUGIN_URL
DEBUG url: https://www.domain.com/blog/wp-content/plugins // Dump of the resulting URL

Open in new window


After the <!doctype ...>

DEBUG path: themes/blank/style.css
DEBUG siteurl: https://www.domain.com/blog {This does not change}
DEBUG WP_CONTENT_URL: http://www.domain.com/blog/wp-content 
DEBUG WPMU_PLUGIN_URL: http://www.domain.com/blog/wp-content/mu-plugins 
DEBUG WP_PLUGIN_URL: http://www.domain.com/blog/wp-content/plugins 
DEBUG url: http://www.domain.com/blog/wp-content/plugins

Open in new window


WP_CONTENT_URL is set in the function wp_plugin_directory_constants() in the following file
wp-includes\default-constants.php

if ( !defined('WP_CONTENT_URL') )
	{		
echo "Setting WP_CONTENT_URL to : " . get_option('siteurl') . " line 139 of " . __FILE__ . "\n";
		define( 'WP_CONTENT_URL', get_option('siteurl') . '/wp-content'); // full url - WP_CONTENT_DIR is defined further up
	}

Open in new window

The debug statement is mine and is output only ONCE for the page.

Anyone have any ideas how / why / where the WP_CONTENT_URL constant is suddenly getting changed from an https:// prefix to http://

I have searched the code base for WP_CONTENT_URL - no other lines manipulate the setting of its value - they only reference it.

This does not seem possible but it is obviously happening - any thoughts.
Avatar of Chris Stanyon
Chris Stanyon
Flag of United Kingdom of Great Britain and Northern Ireland image

Hey Julian,

Don't you just hate these kind of bugs.

Just had a quick look through my codebase for WP. If I were to try and track it down, I'd also take a look at the wp-includes/option.php code, as that's where the data is pulled from the options table. It looks like it's doing some stuff with caching, so some additional DEBUG info in there may lead you closer to a solution. You can at least dump out the retrieved options as soon as they're pulled from the DB (or cache) and see if that gives you any clues.

Othe than that ... ????
Avatar of Julian Hansen

ASKER

Thanks Chris,

What is confusing me is that the WP_CONTENT_URL is mutating. The code is running once as the debug where WP_CONTENT_URL is defiend is run only once - yet during execution the value of a define() is changing - which should not be possible.

The other weird thing is WP_CONTENT_URL is set with get_option('siteurl') however the returned value from get_option('siteurl')  remains constant with the correct URL after WP_CONTENT_URL changes.

Trying to figure out how a constant gets changed during code execution.
Hmmm .. I feel your pain. Like you say a constant is supposed to be just that!

Do you have any caching plugins enabled? Shouldn't really cause a problem, but in my book 'Clutching at Straws' is a valid debugging technique! Maybe disable all plugins while you're trying to figure it out - less moving parts. Switch themes, just as a sanity check.
1) Post your siteurl value.

This can be used by external tools (or you can run curl -I -L URL yourself) to determine if this is an Apache level problem or actually WordPress.

2) Enable WP_DEBUG (likely you already have) + review your debug.log file looking for oddities which might relate.

3) Remove any wp-config.php SSL related hardcoded constants.

4) Remove any plugins which attempt to muck about with forcing SSL (most of these plugins are badly broken + other conflict with Apache SSL configs).

Post a list of your plugins (wp-cli.php --allow-root plugin list) + your debug.log file.
@Chris,

I suspect there is caching on the actual site however I am debugging on a local version. They would not give me server access so instead they dumped the DB and tarballed /gzipped the files and I rehydrated this end and I am not using any caching on my setup.

@Dave,

I have tried removing the plugins - first thing I tried - it made no difference.
The siteurl is in the debug data I posted above. I dumped it with all the other data to check that it was a) correct, b) static - which it was in both cases.

This is a bit more low level than plugins though and the like - at the PHP level a constant is changing value during execution which is supposed to be impossible.

I know if I can find out why / how this constant value is changing it will unlock the rest of the puzzle. Probably something obvious - @Chris - clutching at straws is often the last resort and usually yields something so clutch away.

Here is a summary of the problem.

I am putting my debug code in the plugins_url() function. I am dumping all the paths sent to this function along with the variables and constants used in the function. This function is called 14 times with the $path variable empty - in all cases the WP_CONTENT_URL is set to the correct https value.

I also put debug code in the default-constants.php where the WP_CONTENT_URL define is set. This debug line is shown only ONCE during the entire page load - indicating it is called once to set the define - and never again.

After the 14th debug dump we get the first 6 lines (only 4 shown) of the header.php file in the template folder
<!DOCTYPE html>
<html lang="en-GB" prefix="og: http://ogp.me/ns#">
<head>
<meta charset="UTF-8">
...

Open in new window


After this all the DEBUG dumps show the WP_CONTENT_URL has having an http:// prefix - the siteurl still shows as before with the https and there are no debug lines to indicate that the code to set  the WP_CONTENT_URL was re-defined (which is theoretically not possible)

I have also searched the code base for all instances of WP_CONTENT_URL which has turned up only the use cases and the one define.

So, it appears that this code is able to do something in PHP that should not be possible - that is really the question I am trying to answer.
One thing I've found to be important when switching to https is to go into the theme options, make a small change, save it, undo it, and save again.

If you're relying on a search and replace on URLs you may find some get missed because they have (or don't have) www. at the start, or some other variation that caused them to be missed.
Well now... You've actually given the useful key of information.

You said the magic word local...

This introduces a can of worms.

1) You will not be able to reliably test your site if you use HTTPS at all, because HTTPS works with IPs which resolve.

2) If you've ever visited the real site (setting of home + siteurl) + that real site has HSTS set, then you're in a world of hurt because HSTS says to deny all HTTP requests till the HSTS time expires, which I set to 2 years for my sites.

All bets are off running local... unless you do this...

1) Clone working SSL certs to your local environment.

2) Completely hijack DNS, so your local IP is returned for all DNS lookups.

Now before you go off in a dark corner + whimper yourself to sleep, doing the above two steps is super easy. I do this with sites all the time.

Just copy over your real site's SSL certs + plumb them into your local Apache config.

To completely hijack DNS is easy too. Just run dnsmasq + add a single entry to your dnsmasq config to map *.yourdomain.com to any IP.
If you're relying on a search and replace on URLs you may find some get missed because they have (or don't have) www. at the start, or some other variation that caused them to be missed.
I searched the code base and a dump of the database - no URL's found that were not changed. This is happening in code. The call to plugin_url() is returning the wrong URL (at least that is what it appears

@Dave
I have a process I have been using for a while which includes updating the hosts file. The HTTPS side of things is not the issue - if you do a view source on the loaded page most of the .css and .js files are rendered as HTTP instead of HTTPS. These links are generated dynamically through a call to the wp_enqueueXXXX functions.

Thanks for the input guys - not quite there yet but the discussion has given me ideas - please keep throwing suggestions (no matter if way off base) - there is a logical explanation for this - just need to narrow down where it is.
Unfortunately, simply changing /etc/hosts may or may not be sufficient.

Much better to run a local copy of dnsmasq, so you can know 100% you've hijacked all DNS requests.

Also, if you have hijacked all DNS requests, then you can change over to using 100% HTTPS links with no HTTP, which will likely also fix hard to debug problems.
Just out of interest Julian, have you tried defining the WP_CONTENT_URL in the wp_config.php file just to see if it get's changed when set there.

See what happens if you define it there (just use some arbitrary value - https://www.example.com - I know it'll break your site, but then see if the https is converted to http (add it before the call to require wp-settings).

Curious as to whether it would make a difference.
That was interesting.

WP_CONTENT_URL stays constant now with the defined value - but the URL's still enqueuing as http.

So a new avenue to explore... will report back shortly.
Follow up:
I have opened another question to split out the HTTPS issue from this question (https://www.experts-exchange.com/questions/29115569/Migrating-Wordpress-to-HTTPS-does-not-update-path-for-enqueued-resources.html#questionAdd) as this question was more about the issue of a defined "constant" changing value.

On the original issue I added further debug code to the WP files.
Following Chris' suggestion, I also added the following to the wp_config.php file
define('WP_PLUGIN_URL','https://www.domain.com'); 

Open in new window

Here is what confuses me. This value is being reported in the debug up to where the theme starts loading (before the <!doctype )
As soon as the page starts rendering the value changes back to http.
(The debug is the the plugin_url() function)

If I set the value in wp_config.php to httpZ:// then it stays httpZ:// throughout. So it is sensitive to the original scheme value.

I have put code in to see if code to set the WP_PLUGIN is firing more than once - only one debug statement is displayed.

So as things stand, unless I am missing something really obvious, something in WP is able to change the value of a define() (constant) value - which is not possible?
Could it be that the site is being loaded twice? Or does the log make it clear it's a single load of the site?
Hmmm .. I'm as stumped as you are. Like you say, a constant should be completely immutable!

Have you been able to eliminate this as a particular plugin or theme issue (disable plugins / change themes).

Here's another slightly random thought - filters! I can't think how a filter could change a constant, but it's possible I guess that any call to retrieve the constant could pass the returned value through a filter ?? This looks like quite an interesting plugin for logging all filters and actions - may shed some light on the inner workings - https://pantheon.io/blog/tracing-wordpress-actions-and-filters
eg your browser requests https://example.com and a resource in the page requests say http://example.com/file.ext and triggers a second load of the site. Normally resources like images don't require WordPress to be loaded, but there may be exceptions (eg when the image isn't found)
Could it be that the site is being loaded twice? Or does the log make it clear it's a single load of the site?
Definitely loaded once - that is one of the things I looked for.
Having said that, loading twice would imply some sort of refresh - so you get whatever the last request is - they would not render in the same page..

My debug dump is continuous see below
Before page rendering starts.
(The dumps are non-intuitive as I was adding as I went along) The important bits are where you see the dump of WP_PLUGIN_URL
The --- X LOADED ---- lines are in files where the constants are defined - checking that they are actually called once.
 -------------------- 1:LOADED -------------------
 -------------------- 2:LOADED -------------------
-----------E:\Projects\domain\debug\wp-includes\link-template.php -------------------- 3. LOADED ----------------
wp_plugin_directory_constantsE:\Projects\domain\debug\wp-includes\default-constants.php
WP_PLUGIN_URL already defined *******************************************************
------------------- WPMU_PLUGIN_DIR -----------------------
E:\Projects\domain\debug\wp-includes\plugin.php: WP_CONTENT_URL:https://www.domain.co.uk/blog[E:\Projects\domain\debug\wp-content\plugins\ajaxy-search-form\sf.php]
DEBUG path: 
DEBUG siteurl: http://www.domain.co.uk/blog
DEBUG path after normalize: 
DEBUG WP_CONTENT_URL: https://www.domain.co.uk/blog 
DEBUG plugin: E:/Projects/domain/debug/wp-content/plugins/ajaxy-search-form/sf.php
DEBUG mu_plugin_dir: E:/Projects/domain/debug/wp-content/mu-plugins
DEBUG WPMU_PLUGIN_DIR: E:\Projects\domain\debug/wp-content/mu-plugins 
DEBUG WPMU_PLUGIN_URL: https://www.domain.co.uk/blog/mu-plugins 

DEBUG AJAXY_SF_PLUGIN_URL: AJAXY_SF_PLUGIN_URL 
DEBUG WP_PLUGIN_URL [xx]: https://www.domain.co.uk/blog/plugins/ 
DEBUG WP_PLUGIN_URL [yy]: https://www.domain.co.uk/blog/plugins/ 
DEBUG: orig_scheme: 
DEBUG: scheme: https
DEBUG: url [before]: (https://www.domain.co.uk/blog/plugins/)
DEBUG: url [after]: (https://www.domain.co.uk/blog/plugins/)
DEBUG url: https://www.domain.co.uk/blog/plugins/

E:\Projects\domain\debug\wp-includes\plugin.php: WP_CONTENT_URL:https://www.domain.co.uk/blog[E:\Projects\domain\debug\wp-content\plugins\ajaxy-search-form\sf.php]
DEBUG path: 
DEBUG siteurl: http://www.domain.co.uk/blog
DEBUG path after normalize: 
DEBUG WP_CONTENT_URL: https://www.domain.co.uk/blog 
DEBUG plugin: E:/Projects/domain/debug/wp-content/plugins/ajaxy-search-form/sf.php
DEBUG mu_plugin_dir: E:/Projects/domain/debug/wp-content/mu-plugins
DEBUG WPMU_PLUGIN_DIR: E:\Projects\domain\debug/wp-content/mu-plugins 
DEBUG WPMU_PLUGIN_URL: https://www.domain.co.uk/blog/mu-plugins 
DEBUG AJAXY_SF_PLUGIN_URL: https://www.domain.co.uk/blog/plugins//ajaxy-search-form/ 
DEBUG WP_PLUGIN_URL [xx]: https://www.domain.co.uk/blog/plugins/ 
DEBUG WP_PLUGIN_URL [yy]: https://www.domain.co.uk/blog/plugins/ 
DEBUG: orig_scheme: 
DEBUG: scheme: https
DEBUG: url [before]: (https://www.domain.co.uk/blog/plugins/)
DEBUG: url [after]: (https://www.domain.co.uk/blog/plugins/)
DEBUG url: https://www.domain.co.uk/blog/plugins/

Open in new window

This goes on for a bit then we get the index.php in the theme running followed by the header.php
INDEX.php: --------------------------->https://www.domain.co.uk/blog
header.php: ---------------------------> https://www.domain.co.uk/blog
<!DOCTYPE html>
<html lang="en-GB" prefix="og: http://ogp.me/ns#">
<head>
<meta charset="UTF-8">

Open in new window

Theeeeeen we get this - note how the dump of the define('WP_PLUGIN_URL') is now set to a different value.
DEBUG: orig_scheme: https
DEBUG: scheme: https
DEBUG: url [before]: (http://www.domain.co.uk/blog)
DEBUG: url [after]: (https://www.domain.co.uk/blog)
DEBUG: wp_enqueue_script: src ---> []
DEBUG: WP_CONTENT_URL: https://www.domain.co.uk/blog
Enqueing ajaxy-sf [http://www.domain.co.uk/blog/plugins//ajaxy-search-form/]
DEBUG: wp_enqueue_script: src ---> [http://www.domain.co.uk/blog/plugins//ajaxy-search-form/js/sf.js]
DEBUG: WP_CONTENT_URL: https://www.domain.co.uk/blog
DEBUG: wp_enqueue_script: src ---> [http://www.domain.co.uk/blog/plugins//ajaxy-search-form/js/sf_selective.js]
DEBUG: WP_CONTENT_URL: https://www.domain.co.uk/blog
DEBUG path: themes/blank/style.css
DEBUG siteurl: http://www.domain.co.uk/blog
DEBUG path after normalize: themes/blank/style.css
DEBUG WP_CONTENT_URL: https://www.domain.co.uk/blog 
DEBUG plugin: E:/Projects/domain/debug/wp-content/plugins/ajaxy-search-form/sf.php
DEBUG mu_plugin_dir: E:/Projects/domain/debug/wp-content/mu-plugins
DEBUG WPMU_PLUGIN_DIR: E:\Projects\domain\debug/wp-content/mu-plugins 
DEBUG WPMU_PLUGIN_URL: http://www.domain.co.uk/blog/mu-plugins 
DEBUG AJAXY_SF_PLUGIN_URL: http://www.domain.co.uk/blog/plugins//ajaxy-search-form/ 
DEBUG WP_PLUGIN_URL [xx]: http://www.domain.co.uk/blog/plugins/ 
DEBUG WP_PLUGIN_URL [yy]: http://www.domain.co.uk/blog/plugins/ 
DEBUG: orig_scheme: 
DEBUG: scheme: https
DEBUG: url [before]: (http://www.domain.co.uk/blog/plugins/)
DEBUG: url [after]: (http://www.domain.co.uk/blog/plugins/)
DEBUG url: http://www.domain.co.uk/blog/plugins/
DEBUG path: themes/blank
DEBUG siteurl: http://www.domain.co.uk/blog
DEBUG path after normalize: themes/blank
DEBUG WP_CONTENT_URL: https://www.domain.co.uk/blog 
DEBUG plugin: E:/Projects/domain/debug/wp-content/plugins/ajaxy-search-form/sf.php
DEBUG mu_plugin_dir: E:/Projects/domain/debug/wp-content/mu-plugins
DEBUG WPMU_PLUGIN_DIR: E:\Projects\domain\debug/wp-content/mu-plugins 
DEBUG WPMU_PLUGIN_URL: http://www.domain.co.uk/blog/mu-plugins 
DEBUG AJAXY_SF_PLUGIN_URL: http://www.domain.co.uk/blog/plugins//ajaxy-search-form/ 
DEBUG WP_PLUGIN_URL [xx]: http://www.domain.co.uk/blog/plugins/ 
DEBUG WP_PLUGIN_URL [yy]: http://www.domain.co.uk/blog/plugins/ 
DEBUG: orig_scheme: 
DEBUG: scheme: https

Open in new window


This does not make sense so it means I am missing something - probably something obvious so looking for some rubber ducks to see what I have missed.
Hey Julian,

How come your siteurl is now http:// 

That comes from the DB and sets up the WP_CONTENT_URL const, which in turn sets up WP_PLUGIN_URL const. Have you changed this since you opened the question.
https://wordpress.org/plugins/ssl-insecure-content-fixer/ might help.

Looking over DNS discussion.

If you attempt to change /etc/hosts this is usually insufficient, because once you reference your site + your site references itself, the self reference will likely be handled server side.

This is why I only do what you're attempting by using LXD containers with dnsmasq running inside the container, doing a similar /etc/hosts spoof, which guarantees 100% of all site references loop back to the LXD container IP.

Then only make changes in the LXD container + never locally.

If you do this + point your /etc/hosts to the LXD container IP, you will achieve a 100% sandboxed site working as you expect 100% of the time.
How come your siteurl is now http:// 
It doesn't make a difference - that log was from another test I was doing - the issue is not the https - that I have moved to another thread it is the fact that a constant changes its value.

Here are the same logs with the site url set to https just demonstrate that is not a factor
Before render
DEBUG path: 
DEBUG siteurl: https://www.domain.co.uk/blog
DEBUG path after normalize: 
DEBUG WP_CONTENT_URL: https://www.domain.co.uk/blog 
DEBUG plugin: E:/Projects/domain/debug/wp-content/plugins/daves-wordpress-live-search/class-daves-wordpress-live-search.php
DEBUG mu_plugin_dir: E:/Projects/domain/debug/wp-content/mu-plugins
DEBUG WPMU_PLUGIN_DIR: E:\Projects\domain\debug/wp-content/mu-plugins 
DEBUG WPMU_PLUGIN_URL: https://www.domain.co.uk/blog/mu-plugins 
DEBUG AJAXY_SF_PLUGIN_URL: https://www.domain.co.uk/blog/plugins//ajaxy-search-form/ 
DEBUG WP_PLUGIN_URL [xx]: https://www.domain.co.uk/blog/plugins/ 
DEBUG WP_PLUGIN_URL [yy]: https://www.domain.co.uk/blog/plugins/ 
DEBUG: orig_scheme: 
DEBUG: scheme: https
DEBUG: url [before]: (https://www.domain.co.uk/blog/plugins/)
DEBUG: url [after]: (https://www.domain.co.uk/blog/plugins/)
DEBUG url: https://www.domain.co.uk/blog/plugins/

Open in new window

After page render starts
DEBUG path: themes/blank
DEBUG siteurl: https://www.domain.co.uk/blog
DEBUG path after normalize: themes/blank
DEBUG WP_CONTENT_URL: https://www.domain.co.uk/blog 
DEBUG plugin: E:/Projects/domain/debug/wp-content/plugins/ajaxy-search-form/sf.php
DEBUG mu_plugin_dir: E:/Projects/domain/debug/wp-content/mu-plugins
DEBUG WPMU_PLUGIN_DIR: E:\Projects\domain\debug/wp-content/mu-plugins 
DEBUG WPMU_PLUGIN_URL: http://www.domain.co.uk/blog/mu-plugins 
DEBUG AJAXY_SF_PLUGIN_URL: http://www.domain.co.uk/blog/plugins//ajaxy-search-form/ 
DEBUG WP_PLUGIN_URL [xx]: http://www.domain.co.uk/blog/plugins/ 
DEBUG WP_PLUGIN_URL [yy]: http://www.domain.co.uk/blog/plugins/ 
DEBUG: orig_scheme: 
DEBUG: scheme: https
DEBUG: url [before]: (http://www.domain.co.uk/blog/plugins/)
DEBUG: url [after]: (http://www.domain.co.uk/blog/plugins/)
DEBUG url: http://www.domain.co.uk/blog/plugins/

Open in new window

Site URL is now https but WP_PLUGIN_URL still switches.
@Dave,

Thanks but this is not about DNS or about how to get the site working - I have moved that to a separate question. This is a PHP issue. In PHP a defined constant should be immutable - you should not be able to change its value - yet in this situation it appears that it is changing its value.

The debug dumps are just echo statements dumping the value of defined constants before and after the start of the render process - what we are seeing should not be happening.

With respect to what my ultimate goal is - I would like to hear your comments. If you could post in the other thread any input you provide there would be much appreciated.
In case it is useful - I have had clearance from the client to post the URL.

http://www.trudiamonds.co.uk/blog
Here is some more interesting information. I added more debug statements to do a debug_backtrace when an http:// prefix is detected on the WP_PLUGIN_URL - and .... no backtrace. The test was to use substr(WP_PLUGIN_URL, 0, 5) and check for it not equal to https - so I added some debug statements to dump the substr() here is what I got
DEBUG link_template.PHP  AJAXY_SF_PLUGIN_URL: https://www.trudiamonds.co.uk/blog/plugins//ajaxy-search-form/ 
DEBUG link_template.PHP WP_PLUGIN_URL [xx]: https://www.trudiamonds.co.uk/blog/plugins/ 
DEBUG link_template.PHP BACKTRACE TEST: [https://www.trudiamonds.c] 
DEBUG: orig_scheme: 
DEBUG: scheme: https
DEBUG: url [before]: (https://www.trudiamonds.co.uk/blog/plugins/)
DEBUG: url [after]: (https://www.trudiamonds.co.uk/blog/plugins/)
DEBUG url: https://www.trudiamonds.co.uk/blog/plugins/
DEBUG link_template.PHP  AJAXY_SF_PLUGIN_URL: http://www.trudiamonds.co.uk/blog/plugins//ajaxy-search-form/ 
DEBUG link_template.PHP WP_PLUGIN_URL [xx]: http://www.trudiamonds.co.uk/blog/plugins/ 
DEBUG link_template.PHP BACKTRACE TEST: [https://www.trudiamonds.c] 

Open in new window

Line 2 - WP_PLUGIN_URL is still correct
Line 10 - WP_PLUGIN_URL reverts to http://
BUT
Line 11 which is the dump of the substr shows that the protocols is in fact https
But there is more.
If I do a substr(WP_PLUGIN_URL, 25) I get the output on line 11 - however if I do substr(WP_PLUGIN_URL, 35) I get the http:// output
As soon as it seems to access the /plugins section of the link it suddenly sees it as a http

I then updated the backtrace test to search for the full URL "http://www.trudiamonds.co.uk/blog/plugins/" - that code never fires even though the line immediately before it is dumping the URL as exactly that.

Still feel as if I am missing something obvious here.
Update to the above running strtoupper(WP_PLUGIN_URL) produces HTTPS://WWW.TRUDIAMONDS.CO.UK/BLOG/PLUGINS/
This question needs an answer!
Become an EE member today
7 DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform.
View membership options
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.