I'm using gulp & browserSync for server in WP development:

gulp.task('browser-sync', function () {
        proxy: projectURL

WordPress runs on localhost:3000/mysite

There is also a watch task that detects changes in php and reloads browser.

For some reason though WP customizer doesn't load site in iframe with the following error:

Refused to display 'http://localhost:3000/mysite/2012/01/07/template-sticky/?customize_changese…10a90359901&customize_theme=mysite&customize_messenger_channel=preview-0' in a frame because an ancestor violates the following Content Security Policy directive: "frame-ancestors http://localhost".

It works fine http://localhost/mysite without the port though, but won't reload automatically.

Is there a way to fix this somehow?

  • Did you set the port in WP config? If not, can you change it to 80? – kero Jul 20 '17 at 15:53
  • @kero do you mean MySQL host? – Runnick Jul 20 '17 at 18:06
  • Have you tried changing your site URL and home URL in WP Admin to be http://localhost:3000? It appears it is currently set to just http://localhost. – Weston Ruter Jul 20 '17 at 20:40
  • @WestonRuter yes, it's //localhost:3000 there – Runnick Jul 21 '17 at 7:11
  • 1
    You can see where that header gets set here: github.com/WordPress/wordpress-develop/blob/4.8.0/src/… I don't see how it would be stripping the port, but that's where I'd look when debugging. – Weston Ruter Jul 21 '17 at 15:01

Found a work around by adding ' localhost:3000' to the 'Content-Security-Policy' header:

function edit_customizer_headers () {
  function edit_csp_header ($headers) {
    $headers['Content-Security-Policy'] .= ' localhost:3000';
    return $headers;
  add_filter('wp_headers', 'edit_csp_header');
add_action('customize_preview_init', 'edit_customizer_headers');

Maybe it may be late, but I recently have found a solution with a filter:

function theme_set_url_scheme($url, $path, $blog_id){
      $parsed_url = parse_url($url);
      $parsed_url["port"] = intval($_GET['wp_port']);
      $scheme   = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
      $host     = isset($parsed_url['host']) ? $parsed_url['host'] : '';
      $port     = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
      $user     = isset($parsed_url['user']) ? $parsed_url['user'] : '';
      $pass     = isset($parsed_url['pass']) ? ':' . $parsed_url['pass']  : '';
      $pass     = ($user || $pass) ? "$pass@" : '';
      $path     = isset($parsed_url['path']) ? $parsed_url['path'] : '';
      $query    = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
      $fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
      $url = "$scheme$user$pass$host$port$path$query$fragment";
    return $url;
add_filter("admin_url", "theme_set_url_scheme', null, 3);

And then open up the customizer with adding this querystring variable to the end:


I tried to do this without adding the querystring parameter, but I guess browsersync redirects the calls back to server port 80, so the 3000 custom port is only visible through browser and browsersync.

Better option:

Add the querystring parameter to browsersync setup like this:

options: {
    proxy: 'wordpress.dev?wp_port=3000',

So you don't need to do anything manually. It works out of the box.


Might be better to alter your gulp script in some variation of the tip on this bug report https://github.com/BrowserSync/browser-sync/issues/1241

Hacking the source php files you are working on to get this working seems ... less good.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.