Wordpress

Update your personal or commercial wordpress theme from your own repository

If you wish to upgrade your own wordpress framework or theme from your own remote repository then this is a quiet simple operation to do using wordpress API.

Of course this is a trivial example, you’ll need to add yourself the logic for restricting the download of your updates to only those people that have purchased from you a valid license or subscription plan.

In my case i’ve assumed the updates are public.

Anyway.

The magic behind all of this is the just the wordpress filter  “pre_set_site_transient_update_themes. Just have it to point to your update function like this:

add_filter( 'pre_set_site_transient_update_themes', array(&$this, 'check_for_update') );

This filter gets called when wordpress check for themes updates. The result is always cached by wordpress using a transient. You can force the remote checking using the admin UI or programmatically by removing the transient “update_themes” in this way:

set_site_transient('update_themes', null);

The prototype for the filter callback is:

function check_for_update( $transient )

The $transient object will contain also a property called checked that is an hash of all the installed themes and their actual version, like this:

'my-child-theme'=>'1.0.1',
'genesis' => '2.0.0',

What you need to do now is to send a POST request to your remote server script using wp_remote_post() and sending it all the data you need to validate and process the update request: the themes to be checked, their version, statistical and marketing infoes (you can ninja the admin email!), anything else you need.

From your remote script you’ll need to return infoes, maybe in JSON, to populate back the $transient->response array with infoes about every theme you wish to be updated. For each item you need to provide 3 parameters:

  • new_version – will contain your up-to-date version numer;
  • package – full URL to the ZIP file that contains the latest version;
  • url – full URL to a page that will be opened as IFRAME with detailed info about the theme changes;

This is how it will be look if you find updates for one of your themes:

$transient->response = array( 
    'my-child-theme' => array ( 
        'new_version'=>'1.0.0',  
        'package' => 'http://....zip', 
        'url'=>'http://..../info.html' 
    )
);

Instead, if there are no updates or if there is some error then just return $transient without changing it.

This is an abstract example from my update class method:

function check_for_update( $transient ) {

    // Skip if checked is not here
    if (empty($transient->checked)) return $transient;

    // prepare $args
    $args = array(...);

    // send POST
    $response = wp_remote_post( $this->api_url, $args );

    // skip on errors
    if( is_wp_error($response) || ($response['response']['code'] != 200) ) {
        return $transient;
    }
    if( empty($response['body']) ) {
        return $transient;
    }

    // decode response and save it
    $transient_response = unserialize($response['body']);
    if (!is_array($transient_response)) {
        return $transient;
    }
    $transient->response = $transient_response;

    return $transient; 
}

My repote script is something like this (remember to add input sanitization and filtering):

    $count = 0;
    $update_data = array();    
    
    foreach ($_POST['themes'] as $theme=>$old_version) {
        $new_version = search_package($theme);
        
        if ($new_version===FALSE) $new_version='0.0.0';

        if ( version_compare( $old_version, $new_version, '>=' ) ) {
            continue;
        }
        
        $count++;
        $update_data[$theme] = array(
            'new_version'=>$new_version,
            'url'=>'http://'.$server_name.'/',
            'package'=>'http://'.$server_name.'/my-updates/'.$theme.'-'.$new_version.'.zip',
        );
    }
    
    if ($count>0) {
        print serialize( $update_data );
        exit;
    }
    // ELSE .. no update availbles
}

function search_package($fn) {
    $flist = glob($fn.'-*.zip');
    if (count($flist)<1) return FALSE;
    $flast = end($flist);
    $flast = preg_replace('/.*-/', '', $flast);
    $flast = preg_replace('/\.zip.*/', '', $flast);
    return $flast;
}

That’s all. I used an enhanched version of this code to provide updates to my own wordpress framework and child themes.