Top Quark’s Self Hosted Plugins plugin is in full swing and getting used by WordPress developers across the internets to host their own plugins. It’s what drives the plugins deployment services here on topquark.com.
Because I’m charging (a reasonable fee) for my plugins, I needed to add in an authentication protocol. As of version 1.0.8 of Self Hosted Plugins, there are hooks that should allow you to have some authentication for your plugins.
Here on TopQuark.com, I’m using Digital Access Pass (DAP) to manage my memberships. It allows me to control who gets access to which plugins so if someone buys one, they don’t automatically get access to the others. You will likely have a different setup on your site, so for this example, I’m only going to show how to authenticate against a user in the WordPress database.
After reading this post…
…you will have written a plugin that gets hosted on your own site that uses WordPress filters to authenticate an email address against your WordPress User Database.
What to add to your Self Hosted Plugin
You’ll need to add a Settings page to your self-hosted plugin. You may already have one. Creating a settings page is way beyond the scope of this post, but I’ll include a modified version the source code for what I’ve been using in my own plugins as a reference. The file is called formidable-plus.settings.php:
<?php
/*********************************************************
* To Customize, replace the following
* - fplus_ -> a unique function prefix
* - Formidable Plus -> the name of the plugin
* - formidable-plus -> the plugin slug at the mothership
* - $mothership -> the actual mothership
*********************************************************/
// add the admin options page
add_action('admin_menu', 'fplus_plugin_admin_add_page');
function fplus_plugin_admin_add_page() {
add_options_page('Formidable Plus', 'Formidable Plus', 'manage_options', 'formidable-plus', 'fplus_plugin_options_page');
}
// display the admin options page
function fplus_plugin_options_page() {
?>
<div>
<h2>Formidable Plus</h2>
<form action="options.php" method="post">
<?php settings_fields('fplus_plugin_options'); ?>
<?php do_settings_sections('formidable-plus'); ?>
<p class="submit">
<input id="submit" class="button-primary" type="submit" value="Save Changes" name="submit">
</p>
</form></div>
<?php
}
// add the admin settings and such
add_action('admin_init', 'fplus_plugin_admin_init');
function fplus_plugin_admin_init(){
register_setting( 'fplus_plugin_options', 'fplus_plugin_options', 'fplus_plugin_options_validate' );
add_settings_section('fplus_plugin_main', 'Top Quark Credentials', 'fplus_plugin_section_text', 'formidable-plus');
add_settings_field('topquark_email', 'Email:', 'fplus_plugin_setting_string', 'formidable-plus', 'fplus_plugin_main','topquark_email');
}
function fplus_plugin_options_validate($input){
$valid = array('topquark_email' => '');
$input = wp_parse_args($input,$valid);
return $input;
}
function fplus_plugin_section_text() {
echo '<p>To receive updates to this plugin, you must have purchased Formidable Plus from TopQuark.com. Please enter your Top Quark email below, or visit <a href="http://topquark.com">TopQuark.com</a> to purchase.</p>';
$options = get_option('fplus_plugin_options');
if (is_array($options) and isset($options['topquark_email'])){
// Verify against the mothership
$mothership = 'http://topquark.com';
$options['topquark_request'] = 'verify';
$options['topquark_plugin'] = 'formidable-plus';
$url = $mothership.'/?'.http_build_query($options);
$result = wp_remote_get($url);
if (!is_array($result) or !is_array($result['response']) or $result['response']['code'] != 200){
$note = "Unable to communicate with TopQuark.com to verify your settings.";
echo sprintf('<div class="error fade"><p>%s</p></div>', $note);
}
elseif ($result['body'] != 'verified'){
$note = "Your credentials could not be verified.<br/>";
$note.= $result['body'];
echo sprintf('<div class="error fade"><p>%s</p></div>', $note);
}
else{
$note = "Awesome! You're good to go!";
echo sprintf('<div class="updated fade"><p>%s</p></div>', $note);
}
}
}
function fplus_plugin_setting_string($what) {
$options = get_option('fplus_plugin_options');
$option = $options[$what];
$name = $id = $what;
switch($what){
default:
$type = 'text';
break;
}
echo "<input id=\"$id\" name=\"fplus_plugin_options[$name]\" type=\"$type\" value=\"".esc_attr($option)."\" />";
}
add_filter('puc_request_info_query_args-formidable-plus','fplus_request_info_query_args');
function fplus_request_info_query_args($queryArgs){
$options = get_option('fplus_plugin_options');
$queryArgs+=$options;
return $queryArgs;
}
?>
At the bottom of my main plugin file (formidable-plus.php in this example), I simply include the settings file:
include_once('formidable-plus.settings.php');
The functions that are of interest are `fplus_plugin_section_text`, which does a verification of the credentials on the actual settings page, and `fplus_request_info_query_args` (and the corresponding `add_filter()` call), which adds the necessary arguments to the call the plugin makes when checking for updates.
What to add to your Server to handle the authentication
Your self-hosted plugin is now ready to get updates from the server, but you need to add some stuff to your server itself to be able to handle the authentication request. This gets done by creating and activating a new plugin on your server that hooks into the Self Hosted Plugins code using WordPress filters.
(I assume that since you’re hosting your own plugins, you know what I’m talking about here and know how to create and activate a new plugin)
There are a few different filters that you’ll want to hit.
Change the Download Button
Off the top, you’ll likely want to change the Download button within your extend/plugins pages to a link to register or purchase your plugin.
Here’s what you can do (remember, in this example, we’re allowing access to logged-in users, so I’ll just redirect to the login page)
add_filter('shp_details_action_button','topquark_shp_details_action_button',10,2);
function topquark_shp_details_action_button($markup,$args){
$Plugin = $args[0];
if (is_user_logged_in()){
return $markup; // allow download
}
else{
$top = '<p class="action-button">';
$tail = '</p>';
$bloginfo = get_bloginfo('url');
$middle = "Login/Register to Download";
return $top.$middle.$tail;
}
}
What happens here is simply that a message to Login/Register appears if the user is not currently logged in. I’m redirecting to the generic login page, but you might have your own registration/login page. If you’re offering your plugin for purchase, here’s a great place to put the price.
Handle the Settings Page Verification
Back in my settings page, recall I added a call to the mothership to verify credentials. This doesn’t check for updates, it just verifies the user has entered their credentials properly. Within my self-hosted-plugins-mod plugin file, I added the following:
add_action('parse_request','topquark_parse_request');
function topquark_parse_request($args,$request = null,$die = true){
if (!isset($request)){
$request = & $_REQUEST;
}
if(isset($request['topquark_request']) and $request['topquark_request'] == 'verify'){
if (!isset($request['topquark_email']) or !isset($request['topquark_plugin'])){
$message = "Must pass in topquark_email and topquark_plugin args";
}
else{
// Let's verify if the user is valid
$user = get_user_by_email($request['topquark_email']);
if (!$user){
$message = 'The email address was not found. Verify your settings or visit TopQuark.com to become a member.';
}
else{
$message = 'verified';
}
}
if ($die){
die($message);
}
else{
return $message;
}
}
}
Handle Authentication on the Update Request
Now that I know how to parse a request, I can add in a function to handle an update request from a WordPress installation of someone who has downloaded your plugin. To accomplish this, you’ll access the `shp_get_plugin_details` filter. Here’s what you can add to the new plugin you’re writing:
add_filter('shp_get_plugin_details','topquark_get_plugin_details',10,2);
function topquark_get_plugin_details($payload,$ref){
$Plugin = $ref[0];
$request['topquark_email'] = isset($_REQUEST['topquark_email']) ? $_REQUEST['topquark_email'] : '';
$request['topquark_request'] = 'verify';
$request['topquark_plugin'] = $Plugin->getParameter('SelfHostedPluginSlug');
if (topquark_parse_request(null,$request,false) != 'verified'){
$payload->upgrade_notice = 'Your subscription to receive updates for this product has expired. Come back and join us at <a href="http://topquark.com/" target="_blank">TopQuark.com</a>';
}
elseif(isset($_REQUEST['topquark_email'])){
unset($request['topquark_request']);
unset($request['topquark_plugin']);
$payload->download_url.= '?'.http_build_query($request); // adds the email to the download url
}
return $payload;
}
Note that if the authentication fails, we return a message. This message gets displayed on the Plugins page of the end-user’s WordPress admin area.
Adding Authentication to the download link
There’s one last step. That’s to add the authentication check to the download link so that only authorized people can actually download the plugin. Again, in the new plugin you’re writing for your server, add the following:
add_filter('redirect_self_hosted_plugin_download','topquark_mods_redirect_shp_download',10,3);
function topquark_mods_redirect_shp_download($redirect,$Plugin,$version){
if (is_user_logged_in()){
// If someone is logged in, allow the download
return $redirect;
}
$request['topquark_email'] = isset($_REQUEST['topquark_email']) ? $_REQUEST['topquark_email'] : '';
$request['topquark_request'] = 'verify';
$request['topquark_plugin'] = $Plugin->getParameter('SelfHostedPluginSlug');
if (topquark_parse_request(null,$request,false) == 'verified' and preg_match('/^WordPress/',$_SERVER['HTTP_USER_AGENT'])){
// This is for request from a WordPress installation (see the UserAgent regular expression) to download an update
return $redirect;
}
else{
// Not authorized, just go to the plugin page
return BASE_URL.SHP_REDIRECT_DIR.$Plugin->getParameter('SelfHostedPluginSlug');
}
}
That’s It
You’re now ready to start testing your authentication solution. Assuming you have a test end-user WordPress installation set up, you’ll likely want to make use of the `forceCheck` feature to force WordPress to check for updates (only works for Self Hosted Plugins, not for WordPress plugins unfortunately). To do this, navigate to your end-user’s plugin page and add `?forceCheck=foo` as a query argument (i.e http://localhost/my_site/wp-admin/plugins.php?forceCheck=foo). This is very handy as otherwise you have to wait 12 hours for the WordPress cron to check for updates. That would make testing so horrible.
Further Reading
You are likely interested in selling your plugin, or maybe only giving authorization for certain plugins to certain users. Your setup is entirely your own. Whichever path you choose, you’ll likely want to add custom fields, such as a price field, or a reference to a product in a Membership plugin, to your Self Hosted Plugins installation. This can be achieved without touching the main self-hosted-plugins plugin. It can all be achieved using filters within the Top Quark architecture (on which self-hosted-plugins is built). Consider taking a read through a post giving a detailed example on adding a price field to self-hosted-plugins.
JUL


About the Author
Top Quark is Trevor Mills is Top Quark. He is they as you are me and we are all together. He holds an Engineering degree, specializing in high energy physics, he plays bass in the Juno award winning band Digging Roots and he lovely loves his family. Top Quark’s suite of WordPress plugins are just what you’re looking for.