WordPress y Woocommerce bajo SSL desactiva el Cron de WP

El Cron de WordPress ha dejado de funcionar, ¿cómo puede ser esto?

Hace unos días me encontraba con un problema al configurar SSL en algunas de las tiendas que gestiono.

Lo primero que hice nada más contratar los certificados SSL fue irme de cabeza a mi archivo .htaccess a redirigir todo el tráfico a https de esta manera:

#BEGIN https redirects
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
#END https redirects

Hasta aquí bien, me redirige todo el tráfico a zona segura sin ningún problema, pero cual fue mi sorpresa cuando me di cuenta que el Cron de wordpress dejó de funcionar.

Buscando por la web encontré pocas entradas de gente que se hubiera dado cuenta y aún menos soluciones, así que me dije, manos a la obra!

Vale, solución rápida, le digo al servidor que todas menos la url que manda WP cuando pone en marcha el Cron:

# BEGIN https redirects
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteCond %{REQUEST_URI} !^/wp-cron\.php$ [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# END https redirects

Con esto debería bastar…pero no, aun no funcionaba, resulta que WP al poner las direcciones a https://www.midominio.com/ , convierte todas las url a https: incluido el Cron.

Vale, entonces solo hay que obligar a WP que genere esa url sin https para que esto funcione, probé con esto:

#BEGIN https redirects
RewriteEngine On

#Si entran urls sin https: las convierto todas menos Cron de WP
RewriteCond %{HTTPS} off
RewriteCond %{REQUEST_URI} !^/wp-cron\.php$ [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

#Si entra la url de Cron de WP con https: la paso a http:
RewriteCond %{HTTPS} on
RewriteCond %{REQUEST_URI} ^/wp-cron\.php$ [NC]
RewriteRule ^(.*)$ http://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

#END https redirects

¡Pero tampoco me funcionó!.

Ok, pues si no se puede desde fuera, habrá que abrir la caja de funciones y currarse un poco WP. Buscando encontre la solucion en un filtro de WP que venía al dedillo:

apply_filters( 'site_url', string $url, string $path, string|null $scheme, int|null $blog_id );

El código que creé fue este, con modificar .htaccess e incluir esto:

# BEGIN https redirects
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteCond %{REQUEST_URI} !^/wp-cron\.php$ [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# END https redirects

Y en el archivo functions.php de su tema pegando este código PHP:

//Si es un sitio SSL añado fix para cron de WP
if ( ( !empty( $_SERVER['HTTPS'])? true : false) == true ) {
   add_filter('site_url', array($this, 'FIX_https_WP_Cron'));
}

function FIX_https_WP_Cron($url) {
   $part_url= parse_url($url);
   if ( $part_url !==false && isset($part_url['host']) && 
        isset($part_url['scheme']) && 
        isset($part_url['path']) && 
        $part_url['scheme'] == 'https' && 
        strpos($part_url['path'] ,'wp-cron.php') !== false 
      )
   {
      $fix_url = str_replace($part_url['host'], $part_url['host'] . ':443' , str_replace( $part_url['scheme'].'://', 'http://', $url ) );
      return $fix_url;
   }
   return $url;
}

¡A funcionar! Mano de santo por ahora. 😉

¿Has tenido alguna situación similar?

¿Ves forma de mejorar este código?

¡No te cortes y comparte!