Viewing 4 replies - 1 through 4 (of 4 total)
  • I have an ajax call problem related to insecure urls included in SSL connections too, but not with Buddypress. It might be related:

    a) I use admin_url( ‘admin-ajax.php’ ) to assign the admin-ajax.php file url to my jQuery code. Let’s suppose that I want this url to have HTTPS because the present page/post requires it.

    b) This function uses WordPress’ get_admin_url:

    function get_admin_url( $blog_id = null, $path = '', $scheme = 'admin' ) {
    	$url = get_site_url($blog_id, 'wp-admin/', $scheme); //<<<---- No $path == 'admin-ajax.php'
    
    	if ( $path && is_string( $path ) )
    		$url .= ltrim( $path, '/' );
    
    	return apply_filters( 'admin_url', $url, $path, $blog_id ); <<<----- Here's $path == 'admin-ajax.php'
    }

    Please note that the get_site_url filter doesn’t get ‘admin-ajax.php’ ($path variable) as a parameter. Hooking to ‘admin_url’ provides you with the $path variable.

    c) If we follow the execution inside the get_site_url filter, we see at the bottom where WordPress HTTPS hooks too (the ‘site_url’ hook).

    function get_site_url( $blog_id = null, $path = '', $scheme = null ) {
    	if ( empty( $blog_id ) || !is_multisite() ) {
    		$url = get_option( 'siteurl' );
    	} else {
    		switch_to_blog( $blog_id );
    		$url = get_option( 'siteurl' );
    		restore_current_blog();
    	}
    
    	$url = set_url_scheme( $url, $scheme );
    
    	if ( $path && is_string( $path ) )
    		$url .= '/' . ltrim( $path, '/' );
    
    	return apply_filters( 'site_url', $url, $path, $scheme, $blog_id );
    }

    There’s a $path variable, but its value is ‘wp-admin/’ != ‘admin-ajax.php’.

    d) Here’s where WordPress HTTPS switches HTTPS to HTTP:

    public function site_url( $url, $path, $scheme, $blog_id ) {
    	$force_ssl = apply_filters('force_ssl', null, 0, $url); //<<- $force_ssl is returned false
    
    	if ( $scheme != 'http' && $force_ssl ) {
    		$url = $this->getPlugin()->makeUrlHttps($url);
    	} else if ( !is_null($force_ssl) && !$force_ssl ) {
    		$url = $this->getPlugin()->makeUrlHttp($url); <<-- So, HTTPS is now HTTP.
    	}
    	return $url;
    }

    Why $force_ssl is returned as false? This ‘force_ssl’ hooked filter doesn’t find ‘admin-ajax.php’ inside the $url variable, because of what was explained in b):

    public function secure_admin( $force_ssl, $post_id = 0, $url = '' ) {
    	if ( $url != '' && $this->getPlugin()->isUrlLocal($url) && ( strpos($url, 'wp-admin') !== false || strpos($url, 'wp-login') !== false ) ) {
    		if ( $this->getPlugin()->getSetting('exclusive_https') && !( ( defined('FORCE_SSL_ADMIN') && constant('FORCE_SSL_ADMIN') ) || $this->getPlugin()->getSetting('ssl_admin') ) ) {
    			$force_ssl = false;
    		//TODO When logged in to HTTP and visiting an HTTPS page, admin links will always be forced to HTTPS, even if the user is not logged in via HTTPS. I need to find a way to detect this.
    		} else if ( ( $this->getPlugin()->isSsl() && !$this->getPlugin()->getSetting('exclusive_https') ) || ( ( defined('FORCE_SSL_ADMIN') && constant('FORCE_SSL_ADMIN') ) || $this->getPlugin()->getSetting('ssl_admin') ) ) {
    			$force_ssl = true;
    		}
    		if ( strpos($url, 'admin-ajax.php') !== false ) { //<<--- The check fails here
    			if ( $this->getPlugin()->isSsl() ) {
    				$force_ssl = true;
    			} else {
    				$force_ssl = false; //<<-- So, $force_ssl is set to false
    			}
    		}
    	}
    
    	return $force_ssl;
    }

    And there’s another filter hooked to ‘force_ssl’ that looks for a file, when the url doesn’t include one, as seen on b):

    public function secure_element( $force_ssl, $post_id = 0, $url = '' ) {
    	if ( $url != '' && $this->getPlugin()->isUrlLocal($url) ) {
    		$filename = basename($url); <<---- filename check here
    		foreach( $this->getPlugin()->getFileExtensions() as $extension ) {
    			if ( preg_match('/\.' . $extension . '(\?|$)/', $filename) ) {
    				if ( $this->getPlugin()->isSsl() ) {
    					$force_ssl = true;
    				} else {
    					$force_ssl = false;
    				}
    			}
    		}
    	}
    	return $force_ssl;
    }

    e) After all ‘force_ssl’ hooked filters are applied, we’re returned to d), where $this->getPlugin()->makeUrlHttp($url) is evaluated, switching HTTPS to HTTP.

    In conclusion, ajax requests looking for ‘admin-ajax.php’ should be handled in the ‘admin_url’ hook ( see b) ), instead of ‘site_url’.

    If any additional information is needed to clarify this situation, please don’t hesitate to ask.

    This problem –which as pointed out by ReactorShop is not specific to buddypress– was driving me crazy, since it shows different behavior depending on whether you are logged in or not, the browser, and, in my experience, even on whether you are developing locally or in the production server. (E.g. it worked fine when logged in as admin in various browsers, but when not logged in you would get an insecure ajax url; but Chrome would let it pass, with an easy to miss console warning, while Firefox would block it).

    But in the end the solution was simple.

    Somewhere in my theme I have:

    wp_enqueue_script('my-script', get_stylesheet_directory_uri().'/js/my-script.js',array('jquery'),false,true);
    wp_localize_script('my-script','ajax',array('ajaxurl' => secure_ajax_url()));

    where:

    function secure_ajax_url() {
    	$ajax_url = admin_url('admin-ajax.php','https');
    	return str_replace('https://', 'https://', $ajax_url);
    }

    This outputs in the footer of the page:

    <script type='text/javascript'>
    /* <![CDATA[ */
    var ajax = {"ajaxurl":"https:\/\/www.example.com\/wp-admin\/admin-ajax.php"};
    /* ]]> */
    </script>

    Then in my-script.js I simply use ajax.ajaxurl as the url for ajax calls.

    Thread Starter itrichter

    (@itrichter)

    But is there a way to fix this in the https plugin? Because even if I could patch a plugin to fix this, there would always be some plugin that doesn’t work.
    And any https page with user content will eventualy contain http content, so this is a very essential problem.

    I am having the same problem with WordPress HTTPS and ajaxurl. Did you ever find a fix?

Viewing 4 replies - 1 through 4 (of 4 total)
  • The topic ‘not working foo Buddypress ajax calls’ is closed to new replies.