diff options
author | James Inman <james@jamesinman.co.uk> | 2012-09-07 14:35:45 +0100 |
---|---|---|
committer | James Inman <james@jamesinman.co.uk> | 2012-09-07 14:35:45 +0100 |
commit | 00a4ce5d12076348e1e56179cceb2411731ceb0d (patch) | |
tree | 193ce28fbaeca952b75a5d22adcd7986b11687f4 | |
parent | 770ec8df748b1c8237714d1e65bfb5a09795c22f (diff) | |
download | clockwork-php-00a4ce5d12076348e1e56179cceb2411731ceb0d.zip clockwork-php-00a4ce5d12076348e1e56179cceb2411731ceb0d.tar.gz clockwork-php-00a4ce5d12076348e1e56179cceb2411731ceb0d.tar.bz2 |
Updating for getBalance(), WordPress updates.
-rwxr-xr-x[-rw-r--r--] | class-Clockwork.php | 61 | ||||
-rwxr-xr-x[-rw-r--r--] | class-ClockworkException.php | 1 | ||||
-rwxr-xr-x | wordpress/class-WordPressClockwork.php | 448 | ||||
-rw-r--r-- | wordpress/class-WordPressClockworkHTTP.php | 168 | ||||
-rwxr-xr-x | wordpress/class-clockwork-plugin.php | 326 |
5 files changed, 824 insertions, 180 deletions
diff --git a/class-Clockwork.php b/class-Clockwork.php index 68aec9e..2824a08 100644..100755 --- a/class-Clockwork.php +++ b/class-Clockwork.php @@ -23,31 +23,37 @@ class Clockwork { /* * Version of this class + * @author Martin Steel */ const VERSION = '1.1.0'; /** * All Clockwork API calls start with BASE_URL + * @author Martin Steel */ const API_BASE_URL = 'api.clockworksms.com/xml/'; /** * string to append to API_BASE_URL to check authentication + * @author Martin Steel */ const API_AUTH_METHOD = 'authenticate'; /** * string to append to API_BASE_URL for sending SMS + * @author Martin Steel */ const API_SMS_METHOD = 'sms'; /** * string to append to API_BASE_URL for checking message credit + * @author Martin Steel */ const API_CREDIT_METHOD = 'credit'; /** * string to append to API_BASE_URL for checking account balance + * @author Martin Steel */ const API_BALANCE_METHOD = 'balance'; @@ -55,6 +61,7 @@ class Clockwork { * Clockwork API Key * * @var string + * @author Martin Steel */ public $key; @@ -64,6 +71,7 @@ class Clockwork { * If this is not set, SSL will be used where PHP supports it * * @var bool + * @author Martin Steel */ public $ssl; @@ -71,6 +79,7 @@ class Clockwork { * Proxy server hostname (Optional) * * @var string + * @author Martin Steel */ public $proxy_host; @@ -78,6 +87,7 @@ class Clockwork { * Proxy server port (Optional) * * @var integer + * @author Martin Steel */ public $proxy_port; @@ -85,6 +95,7 @@ class Clockwork { * From address used on text messages * * @var string (11 characters or 12 numbers) + * @author Martin Steel */ public $from; @@ -92,6 +103,7 @@ class Clockwork { * Allow long SMS messages (Cost up to 3 credits) * * @var bool + * @author Martin Steel */ public $long; @@ -99,6 +111,7 @@ class Clockwork { * Truncate message text if it is too long * * @var bool + * @author Martin Steel */ public $truncate; @@ -106,6 +119,7 @@ class Clockwork { * Enables various logging of messages when true. * * @var bool + * @author Martin Steel */ public $log; @@ -116,6 +130,7 @@ class Clockwork { * 'error' - Return an error (Messasge is not sent) * 'remove' - Remove the invalid character(s) * 'replace' - Replace invalid characters where possible, remove others + * @author Martin Steel */ public $invalid_char_action; @@ -124,6 +139,7 @@ class Clockwork { * * @param string key Your Clockwork API Key * @param array options Optional parameters for sending SMS + * @author Martin Steel */ public function __construct($key, array $options = array()) { if (empty($key)) { @@ -146,6 +162,7 @@ class Clockwork { * Send some text messages * * + * @author Martin Steel */ public function send(array $sms) { if (!is_array($sms)) { @@ -297,6 +314,7 @@ class Clockwork { * * @return integer SMS credits remaining * @deprecated Use checkBalance() instead + * @author Martin Steel */ public function checkCredit() { // Create XML doc for request @@ -344,6 +362,7 @@ class Clockwork { * Check your account balance * * @return array Array of account balance: + * @author Martin Steel */ public function checkBalance() { // Create XML doc for request @@ -352,14 +371,14 @@ class Clockwork { $req_doc->appendChild($root); $root->appendChild($req_doc->createElement('Key', $this->key)); $req_xml = $req_doc->saveXML(); - + // POST XML to Clockwork $resp_xml = $this->postToClockwork(self::API_BALANCE_METHOD, $req_xml); // Create XML doc for response $resp_doc = new DOMDocument(); $resp_doc->loadXML($resp_xml); - + // Parse the response to find balance value $balance = null; $err_no = null; @@ -368,7 +387,7 @@ class Clockwork { foreach ($resp_doc->documentElement->childNodes as $doc_child) { switch ($doc_child->nodeName) { case "Balance": - $balance = floatval($doc_child->nodeValue); + $balance = number_format(floatval($doc_child->nodeValue), 2); break; case "Currency": foreach ($doc_child->childNodes as $resp_node) { @@ -404,6 +423,7 @@ class Clockwork { * Check whether the API Key is valid * * @return bool True indicates a valid key + * @author Martin Steel */ public function checkKey() { // Create XML doc for request @@ -454,17 +474,21 @@ class Clockwork { * @param string data Content of HTTP POST * * @return string Response from Clockwork + * @author Martin Steel */ protected function postToClockwork($method, $data) { - if ($this->log) { $this->logXML("API $method Request XML", $data); } - - $ssl = isset($this->ssl) ? $this->ssl : $this->sslSupport(); + + if( isset( $this->ssl ) ) { + $ssl = $this->ssl; + } else { + $ssl = $this->sslSupport(); + } $url = $ssl ? 'https://' : 'http://'; - $url.= self::API_BASE_URL . $method; + $url .= self::API_BASE_URL . $method; $response = $this->xmlPost($url, $data); @@ -483,6 +507,7 @@ class Clockwork { * @param string url URL to send to * @param string data Data to POST * @return string Response returned by server + * @author Martin Steel */ protected function xmlPost($url, $data) { if(extension_loaded('curl')) { @@ -551,8 +576,9 @@ class Clockwork { * any requests. * * @return bool True if SSL is supported + * @author Martin Steel */ - private function sslSupport() { + protected function sslSupport() { $ssl = false; // See if PHP is compiled with cURL if (extension_loaded('curl')) { @@ -571,6 +597,7 @@ class Clockwork { * @param string xml An XML formatted string * * @return void + * @author Martin Steel */ protected function logXML($log_msg, $xml) { // Tidy if possible @@ -590,14 +617,26 @@ class Clockwork { error_log("Clockwork $log_msg: $xml"); } - /* + /** * Check if an array is associative * * @param array $array Array to check - * @return bool + * @return bool + * @author Martin Steel */ - function is_assoc($array) { + protected function is_assoc($array) { return (bool)count(array_filter(array_keys($array), 'is_string')); } + + /** + * Check if a number is a valid MSISDN + * + * @param string $val Value to check + * @return bool True if valid MSISDN + * @author James Inman + */ + public static function is_valid_msisdn($val) { + return preg_match( '/^[1-9][0-9]{10,14}$/', $val ); + } } diff --git a/class-ClockworkException.php b/class-ClockworkException.php index 0b1c8bf..bf8d63e 100644..100755 --- a/class-ClockworkException.php +++ b/class-ClockworkException.php @@ -25,4 +25,3 @@ class ClockworkException extends Exception { parent::__construct( $message, $code ); } } - diff --git a/wordpress/class-WordPressClockwork.php b/wordpress/class-WordPressClockwork.php new file mode 100755 index 0000000..764e42d --- /dev/null +++ b/wordpress/class-WordPressClockwork.php @@ -0,0 +1,448 @@ +<?php +/** +* WordPress Clockwork class +* +* Extends the Clockwor wrapper class to use the +* WordPress HTTP API for HTTP calls, attempts to work +* round the differences in PHP versions, such as SSL +* & curl support +* +* @package Clockwork +* @subpackage WordPressClockwork +* @since 1.0 +*/ + +class WordPressClockwork extends Clockwork { + + /** + * Options key for Clockwork plugins + */ + const OPTIONS_KEY = 'clockwork_options'; + + /** + * SSL options key for Clockwork plugins + */ + const SSL_OPTIONS_KEY = 'clockwork_ssl_options'; + + /** + * String to append to API_BASE_URL for getting a new key + */ + const API_GET_KEY_METHOD = 'get_key'; + + /** + * Mapping of country dialing codes to ISO codes + */ + public static $country_codes = array( + 'AC' => '247', + 'AD' => '376', + 'AE' => '971', + 'AF' => '93', + 'AG' => '1268', + 'AI' => '1264', + 'AL' => '355', + 'AM' => '374', + 'AO' => '244', + 'AQ' => '672', + 'AR' => '54', + 'AS' => '1684', + 'AT' => '43', + 'AU' => '61', + 'AW' => '297', + 'AX' => '358', + 'AZ' => '994', + 'BA' => '387', + 'BB' => '1246', + 'BD' => '880', + 'BE' => '32', + 'BF' => '226', + 'BG' => '359', + 'BH' => '973', + 'BI' => '257', + 'BJ' => '229', + 'BL' => '590', + 'BM' => '1441', + 'BN' => '673', + 'BO' => '591', + 'BQ' => '599', + 'BR' => '55', + 'BS' => '1242', + 'BT' => '975', + 'BW' => '267', + 'BY' => '375', + 'BZ' => '501', + 'CA' => '1', + 'CC' => '61', + 'CD' => '243', + 'CF' => '236', + 'CG' => '242', + 'CH' => '41', + 'CI' => '225', + 'CK' => '682', + 'CL' => '56', + 'CM' => '237', + 'CN' => '86', + 'CO' => '57', + 'CR' => '506', + 'CU' => '53', + 'CV' => '238', + 'CW' => '599', + 'CX' => '61', + 'CY' => '357', + 'CZ' => '420', + 'DE' => '49', + 'DJ' => '253', + 'DK' => '45', + 'DM' => '1767', + 'DO' => '1809', + 'DO' => '1829', + 'DO' => '1849', + 'DZ' => '213', + 'EC' => '593', + 'EE' => '372', + 'EG' => '20', + 'EH' => '212', + 'ER' => '291', + 'ES' => '34', + 'ET' => '251', + 'EU' => '388', + 'FI' => '358', + 'FJ' => '679', + 'FK' => '500', + 'FM' => '691', + 'FO' => '298', + 'FR' => '33', + 'GA' => '241', + 'GB' => '44', + 'GD' => '1473', + 'GE' => '995', + 'GF' => '594', + 'GG' => '44', + 'GH' => '233', + 'GI' => '350', + 'GL' => '299', + 'GM' => '220', + 'GN' => '224', + 'GP' => '590', + 'GQ' => '240', + 'GR' => '30', + 'GT' => '502', + 'GU' => '1671', + 'GW' => '245', + 'GY' => '592', + 'HK' => '852', + 'HN' => '504', + 'HR' => '385', + 'HT' => '509', + 'HU' => '36', + 'ID' => '62', + 'IE' => '353', + 'IL' => '972', + 'IM' => '44', + 'IN' => '91', + 'IO' => '246', + 'IQ' => '964', + 'IR' => '98', + 'IS' => '354', + 'IT' => '39', + 'JE' => '44', + 'JM' => '1876', + 'JO' => '962', + 'JP' => '81', + 'KE' => '254', + 'KG' => '996', + 'KH' => '855', + 'KI' => '686', + 'KM' => '269', + 'KN' => '1869', + 'KP' => '850', + 'KR' => '82', + 'KW' => '965', + 'KY' => '1345', + 'KZ' => '7', + 'LA' => '856', + 'LB' => '961', + 'LC' => '1758', + 'LI' => '423', + 'LK' => '94', + 'LR' => '231', + 'LS' => '266', + 'LT' => '370', + 'LU' => '352', + 'LV' => '371', + 'LY' => '218', + 'MA' => '212', + 'MC' => '377', + 'MD' => '373', + 'ME' => '382', + 'MF' => '590', + 'MG' => '261', + 'MH' => '692', + 'MK' => '389', + 'ML' => '223', + 'MM' => '95', + 'MN' => '976', + 'MO' => '853', + 'MP' => '1670', + 'MQ' => '596', + 'MR' => '222', + 'MS' => '1664', + 'MT' => '356', + 'MU' => '230', + 'MV' => '960', + 'MW' => '265', + 'MX' => '52', + 'MY' => '60', + 'MZ' => '258', + 'NA' => '264', + 'NC' => '687', + 'NE' => '227', + 'NF' => '672', + 'NG' => '234', + 'NI' => '505', + 'NL' => '31', + 'NO' => '47', + 'NP' => '977', + 'NR' => '674', + 'NU' => '683', + 'NZ' => '64', + 'OM' => '968', + 'PA' => '507', + 'PE' => '51', + 'PF' => '689', + 'PG' => '675', + 'PH' => '63', + 'PK' => '92', + 'PL' => '48', + 'PM' => '508', + 'PR' => '1787', + 'PR' => '1939', + 'PS' => '970', + 'PT' => '351', + 'PW' => '680', + 'PY' => '595', + 'QA' => '974', + 'QN' => '374', + 'QS' => '252', + 'QY' => '90', + 'RE' => '262', + 'RO' => '40', + 'RS' => '381', + 'RU' => '7', + 'RW' => '250', + 'SA' => '966', + 'SB' => '677', + 'SC' => '248', + 'SD' => '249', + 'SE' => '46', + 'SG' => '65', + 'SH' => '290', + 'SI' => '386', + 'SJ' => '47', + 'SK' => '421', + 'SL' => '232', + 'SM' => '378', + 'SN' => '221', + 'SO' => '252', + 'SR' => '597', + 'SS' => '211', + 'ST' => '239', + 'SV' => '503', + 'SX' => '1721', + 'SY' => '963', + 'SZ' => '268', + 'TA' => '290', + 'TC' => '1649', + 'TD' => '235', + 'TG' => '228', + 'TH' => '66', + 'TJ' => '992', + 'TK' => '690', + 'TL' => '670', + 'TM' => '993', + 'TN' => '216', + 'TO' => '676', + 'TR' => '90', + 'TT' => '1868', + 'TV' => '688', + 'TW' => '886', + 'TZ' => '255', + 'UA' => '380', + 'UG' => '256', + 'UK' => '44', + 'US' => '1', + 'UY' => '598', + 'UZ' => '998', + 'VA' => '379', + 'VA' => '39', + 'VC' => '1784', + 'VE' => '58', + 'VG' => '1284', + 'VI' => '1340', + 'VN' => '84', + 'VU' => '678', + 'WF' => '681', + 'WS' => '685', + 'XC' => '991', + 'XD' => '888', + 'XG' => '881', + 'XL' => '883', + 'XN' => '857', + 'XN' => '858', + 'XN' => '870', + 'XP' => '878', + 'XR' => '979', + 'XS' => '808', + 'XT' => '800', + 'XV' => '882', + 'YE' => '967', + 'YT' => '262', + 'ZA' => '27', + 'ZM' => '260', + 'ZW' => '263', + ); + + /** + * Legacy username + * + * @var string + */ + private $username; + + /** + * Legacy password + * + * @var string + */ + public $password; + + /** + * Create a new instance of the Clockwork wrapper + * + * Also supports passing a username and a password as first and second parameter, but ONLY when + * used in WordPressClockwork for the purposes of converting to an API key. + * + * @param string key Your Clockwork API Key + * @param array options Optional parameters for sending SMS + * @author James Inman + */ + public function __construct( $arg1, $arg2 = array() ) { + if( !isset( $arg2 ) || is_array( $arg2 ) ) { + parent::__construct( $arg1, $arg2 ); + } else { + $this->username = $arg1; + $this->password = $arg2; + } + } + + public function createAPIKey( $name = 'WordPress API Key' ) { + // Create XML doc for request + $req_doc = new DOMDocument( '1.0', 'UTF-8' ); + $root = $req_doc->createElement( 'GetKey' ); + $req_doc->appendChild( $root ); + $root->appendChild( $req_doc->createElement( 'Username', $this->username ) ); + $root->appendChild( $req_doc->createElement( 'Password', $this->password ) ); + $root->appendChild( $req_doc->createElement( 'Name', $name ) ); + $req_xml = $req_doc->saveXML(); + // POST XML to Clockwork + $resp_xml = $this->postToClockwork( self::API_GET_KEY_METHOD, $req_xml ); + + // Create XML doc for response + $resp_doc = new DOMDocument(); + $resp_doc->loadXML( $resp_xml ); + + // Parse the response to find credit value + $key = null; + $err_no = null; + $err_desc = null; + + foreach( $resp_doc->documentElement->childNodes as $doc_child ) { + switch( $doc_child->nodeName ) { + case "Key": + $key = $doc_child->nodeValue; + break; + case "ErrNo": + $err_no = $doc_child->nodeValue; + break; + case "ErrDesc": + $err_desc = $doc_child->nodeValue; + break; + default: + break; + } + } + + if( isset( $err_no ) ) { + throw new ClockworkException( $err_desc, $err_no ); + } + + $this->key = $key; + return $key; + } + + /** + * Check if the WordPress HTTP API can support SSL + * + * @returns bool True if SSL is supported + */ + public function sslSupport() { + return wp_http_supports( array( 'ssl' ) ); + } + + /** + * Make an HTTP POST using the WordPress HTTP API. + * + * @param string url URL to send to + * @param string data Data to POST + * @return string Response returned by server + */ + protected function xmlPost( $url, $data ) { + $args = array( + 'body' => $data, + 'headers' => array( 'Content-Type' => 'text/xml' ), + 'timeout' => 10, // Seconds + ); + + // Check whether WordPress should veryify the SSL certificate + if( stristr( $url, 'https://' ) ) { + $args['sslverify'] = $this->sslVerify( $url ); + } + + $result = wp_remote_post( $url, $args ); + if( is_wp_error( $result ) ) { + error_log( "POST failed: " . $result->get_error_message() ); + throw new ClockworkException( "HTTP Call failed - Error: " . $result->get_error_message() ); + } + return $result[ 'body' ]; + } + + /** + * Verify SSL conectivity to the remote host + * + * If the request fails store a flag so that we + * don't need to do the check again + */ + private function sslVerify($url) { + $opt = get_option( self::SSL_OPTIONS_KEY ); + if( !$opt ) { + $opt = array(); + } + + if( !array_key_exists( 'sslverify', $opt ) ) { + $args = array( + 'timeout' => 10 // Seconds + ); + + $result = wp_remote_post( $url, $args ); + + if( is_wp_error( $result ) ) { + $opt['sslverify'] = false; + } else { + $opt['sslverify'] = true; + } + + update_option( self::SSL_OPTIONS_KEY, $opt ); + } + return $opt['sslverify']; + } + +} diff --git a/wordpress/class-WordPressClockworkHTTP.php b/wordpress/class-WordPressClockworkHTTP.php deleted file mode 100644 index 06e039e..0000000 --- a/wordpress/class-WordPressClockworkHTTP.php +++ /dev/null @@ -1,168 +0,0 @@ -<?php -/** -* WordPress Clockwork class -* -* Extends the Clockwork wrapper class to use the -* WordPress HTTP API for HTTP calls, attempts to work -* round the differences in PHP versions, such as SSL -* and curl support. -* -* @package Clockwork -* @subpackage WordPressClockwork -* @since 1.0 -*/ - -class WordPressClockwork extends Clockwork { - - /** - * Options key for Clockwork plugins - */ - const OPTIONS_KEY = 'clockwork_options'; - - /** - * String to append to API_BASE_URL for getting a new key - */ - const API_GET_KEY_METHOD = 'get_key'; - - /** - * Legacy username - * - * @var string - */ - private $username; - - /** - * Legacy password - * - * @var string - */ - public $password; - - /** - * Create a new instance of the Clockwork wrapper - * - * Also supports passing a username and a password as first and second parameter, but ONLY when - * used in WordPressClockwork for the purposes of converting to an API key. - * - * @param string key Your Clockwork API Key - * @param array options Optional parameters for sending SMS - * @author James Inman - */ - public function __construct( $arg1, $arg2 = array() ) { - if( !isset( $arg2 ) || is_array( $arg2 ) ) { - parent::__construct( $arg1, $arg2 ); - } else { - $this->username = $arg1; - $this->password = $arg2; - } - } - - public function createAPIKey( $name = 'WordPress API Key' ) { - // Create XML doc for request - $req_doc = new DOMDocument( '1.0', 'UTF-8' ); - $root = $req_doc->createElement( 'GetKey' ); - $req_doc->appendChild( $root ); - $root->appendChild( $req_doc->createElement( 'Username', $this->username ) ); - $root->appendChild( $req_doc->createElement( 'Password', $this->password ) ); - $root->appendChild( $req_doc->createElement( 'Name', $name ) ); - $req_xml = $req_doc->saveXML(); - - // POST XML to Clockwork - $resp_xml = $this->postToClockwork( self::API_GET_KEY_METHOD, $req_xml ); - - // Create XML doc for response - $resp_doc = new DOMDocument(); - $resp_doc->loadXML( $resp_xml ); - - // Parse the response to find credit value - $key = null; - $err_no = null; - $err_desc = null; - - foreach( $resp_doc->documentElement->childNodes as $doc_child ) { - switch( $doc_child->nodeName ) { - case "Key": - $key = $doc_child->nodeValue; - break; - case "ErrNo": - $err_no = $doc_child->nodeValue; - break; - case "ErrDesc": - $err_desc = $doc_child->nodeValue; - break; - default: - break; - } - } - - if( isset( $err_no ) ) { - throw new ClockworkException( $err_desc, $err_no ); - } - - $this->key = $key; - return $key; - } - - /** - * Check if the WordPress HTTP API can support SSL - * - * @returns bool True if SSL is supported - */ - public function sslSupport() { - return wp_http_supports( array( 'ssl' ) ); - } - - /** - * Make an HTTP POST using the WordPress HTTP API. - * - * @param string url URL to send to - * @param string data Data to POST - * @return string Response returned by server - */ - protected function xmlPost( $url, $data ) { - $args = array( - 'body' => $data, - 'headers' => array( 'Content-Type' => 'text/xml' ), - 'timeout' => 10, // Seconds - ); - - // Check whether WordPress should veryify the SSL certificate - if( stristr( $url, 'https://' ) ) { - $args['sslverify'] = $this->sslVerify( $url ); - } - - $result = wp_remote_post( $url, $args ); - if( is_wp_error( $result ) ) { - error_log( "POST failed: " . $result->get_error_message() ); - throw new ClockworkException( "HTTP Call failed - Error: " . $result->get_error_message() ); - } - return $result[ 'body' ]; - } - - /** - * Verify SSL conectivity to the remote host - * - * If the request fails store a flag so that we - * don't need to do the check again - */ - private function sslVerify($url) { - $opt = get_option( self::OPTIONS_KEY ); - if( !$opt ) { - $opt = array(); - } - if( !array_key_exists( 'sslverify', $opt ) ) { - $args = array( - 'timeout' => 10, // Seconds - ); - $result = wp_remote_post( $url, $args ); - if( is_wp_error( $result ) ) { - $opt['sslverify'] = false; - } else { - $opt['sslverify'] = true; - } - update_option( self::OPTIONS_KEY, $opt ); - } - return $opt['sslverify']; - } - -}
\ No newline at end of file diff --git a/wordpress/class-clockwork-plugin.php b/wordpress/class-clockwork-plugin.php new file mode 100755 index 0000000..aa879b8 --- /dev/null +++ b/wordpress/class-clockwork-plugin.php @@ -0,0 +1,326 @@ +<?php +/* Copyright 2012, Mediaburst Limited. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// Require the Clockwork API +if( !class_exists('Clockwork') ) { + require_once( 'clockwork/class-Clockwork.php' ); +} +if( !class_exists('WordPressClockwork') ) { + require_once( 'clockwork/class-WordPressClockwork.php' ); +} + +/** + * Base class for Clockwork plugins + * + * @package Clockwork + * @author James Inman + */ +abstract class Clockwork_Plugin { + + /** + * Version of the Clockwork Wordpress wrapper + */ + const VERSION = '1.0.0'; + /** + * URL to signup for a new Clockwork account + */ + const SIGNUP_URL = 'http://www.clockworksms.com/platforms/wordpress/?utm_source=wpadmin&utm_medium=plugin&utm_campaign=wp-clockwork'; + /** + * URL to top up message credit + */ + const BUY_URL = 'https://app.clockworksms.com/purchase/?utm_source=wpadmin&utm_medium=plugin&utm_campaign=wp-clockwork'; + /** + * URL for support + */ + const SUPPORT_URL = 'http://www.clockworksms.com/support/?utm_source=wpadmin&utm_medium=plugin&utm_campaign=wp-clockwork'; + + /** + * @param $callback Callback function for the plugin's menu item + * + * @author James Inman + */ + public $plugin_callback = null; + + /** + * Instance of WordPressClockwork + * + * @var WordPressClockwork + * @author James Inman + */ + protected $clockwork = null; + + /** + * Setup admin panel menu, notices and settings + * + * @author James Inman + */ + public function __construct() { + // If Clockwork API key isn't set, convert existing username and password into API key + $this->convert_existing_username_and_password(); + + // Setup clockwork + try { + $options = get_option( 'clockwork_options' ); + if( is_array( $options ) && isset( $options['api_key'] ) ) { + $this->clockwork = new WordPressClockwork( $options['api_key'] ); + } + } catch( Exception $e ) { + } + + add_action( 'admin_head', array( $this, 'setup_admin_head' ) ); + add_action( 'admin_menu', array( $this, 'setup_admin_navigation' ) ); + add_action( 'admin_notices', array( $this, 'setup_admin_message' ) ); + add_action( 'admin_bar_menu', array( $this, 'setup_admin_bar' ), 999 ); + add_action( 'admin_init', array( $this, 'setup_admin_init' ) ); + + $this->plugin_callback = array( $this, 'main' ); + } + + /** + * Return the username and password from the plugin's existing options + * + * @return array Array of 'username' and 'password' + * @author James Inman + */ + abstract public function get_existing_username_and_password(); + + /** + * Setup HTML for the admin <head> + * + * @return void + * @author James Inman + */ + abstract public function setup_admin_head(); + + /** + * Convert existing username and password to a new API key + * + * @return void + * @author James Inman + */ + public function convert_existing_username_and_password() { + $options = get_option( 'clockwork_options' ); + if( !is_array( $options ) || !isset( $options['api_key'] ) ) { + $existing_details = $this->get_existing_username_and_password(); + + if( is_array( $existing_details ) && isset( $existing_details['username'] ) && isset( $existing_details['password'] ) ) { + try { + // We have a username and password, now go and convert them + $this->clockwork = new WordPressClockwork( $existing_details['username'], $existing_details['password'] ); + $key = $this->clockwork->createAPIKey( 'WordPress - ' . home_url() ); + // Set the Clockwork API key to be the newly created key + update_option( 'clockwork_options', array( 'api_key' => $key ) ); + } catch( ClockworkException $e ) { + return; + } + } + } + } + + /** + * Tell the user to update their Clockwork options on every admin panel page if they haven't already + * + * @return void + * @author James Inman + */ + public function setup_admin_message() { + // Don't bother showing the "You need to set your Clockwork options" message if it's that form we're viewing + if( !isset( $this->clockwork ) && ( get_current_screen()->base != 'toplevel_page_clockwork_options' ) ) { + $this->show_admin_message('You need to set your <a href="/wp-admin/admin.php?page=clockwork_options">Clockwork options</a> before you can use ' . $this->plugin_name . '.'); + } + } + + /** + * Add the Clockwork balance to the admin bar + * + * @return void + * @author James Inman + */ + public function setup_admin_bar() { + global $wp_admin_bar; + if ( !is_super_admin() || !is_admin_bar_showing() ) { + return; + } + // Display a low credit notification if there's no credit + try { + if( !isset( $this->clockwork ) ) { + $options = get_option( 'clockwork_options' ); + + $clockwork = new WordPressClockwork( $options['api_key'] ); + } + $balance = $this->clockwork->checkBalance(); + if( $balance <= 0 ) { + $balance_string = '£0. Top up now!'; + } else { + $balance_string = $balance['symbol'] . $balance['balance']; + } + // Add a node to the Admin bar + $wp_admin_bar->add_node( array( + 'id' => 'clockwork_balance', + 'title' => 'Clockwork: ' . $balance_string, + 'href' => self::BUY_URL ) + ); + } catch( Exception $e ) { + // Don't kill the entire admin panel because we can't get the balance + } + } + + /** + * Setup admin navigation: callback for 'admin_menu' + * + * @return void + * @author James Inman + */ + public function setup_admin_navigation() { + global $menu; + + $menu_exists = false; + foreach( $menu as $k => $item ) { + if( $item[0] == "Clockwork SMS" ) { + $menu_exists = true; + break; + } + } + + // Setup global Clockwork options + if( !$menu_exists ) { + add_menu_page( __( 'Clockwork SMS', $this->language_string ), __( 'Clockwork SMS', $this->language_string ), 'manage_options', 'clockwork_options', array( $this, 'clockwork_options' ), plugins_url( 'images/logo_16px_16px.png', dirname( __FILE__ ) ) ); + add_submenu_page( 'clockwork_options', __( 'Clockwork Options', $this->language_string ), __( 'Clockwork Options', $this->language_string ), 'manage_options', 'clockwork_options', array( $this, 'clockwork_options' ) ); + } + + // Setup options for this plugin + add_submenu_page( 'clockwork_options', __( $this->plugin_name, $this->language_string ), __( $this->plugin_name, $this->language_string ), 'manage_options', $this->plugin_callback[1], $this->plugin_callback ); + } + + /** + * Register global Clockwork settings for API keys + * + * @return void + * @author James Inman + */ + public function setup_admin_init() { + register_setting( 'clockwork_options', 'clockwork_options', array( $this, 'clockwork_options_validate' ) ); + add_settings_section( 'clockwork_options', 'API Key', array( $this, 'settings_api_key_text' ), 'clockwork_options' ); + add_settings_field( 'clockwork_api_key', 'Your API Key', array( $this, 'settings_api_key_input' ), 'clockwork_options', 'clockwork_options' ); + } + + /** + * Introductory text for the API keys part of the form + * + * @return void + * @author James Inman + */ + public function settings_api_key_text() { + echo '<p>You need an API key to use the Clockwork plugins.</p>'; + } + + /** + * Input box for the API key + * + * @return void + * @author James Inman + */ + public function settings_api_key_input() { + try { + if( !isset( $this->clockwork ) ) { + $options = get_option( 'clockwork_options' ); + $this->clockwork = new WordPressClockwork( $options['api_key'] ); + } + + echo "<input id='clockwork_api_key' name='clockwork_options[api_key]' size='40' type='text' value='{$this->clockwork->key}' />"; + + // Show balance + $balance = $this->clockwork->checkBalance(); + if( $balance ) { + echo '<p><strong>Balance:</strong> ' . $balance['symbol'] . $balance['balance'] . ' <a href="' . self::BUY_URL . '" class="button">Buy More</a></p>'; + } else { // We can't get the credits for some reason + echo '<p><a href="' . self::BUY_URL . '" class="button">Buy More Credit</a></p>'; + } + + } catch( ClockworkException $e ) { + echo "<input id='clockwork_api_key' name='clockwork_options[api_key]' size='40' type='text' value='' />"; + echo '<p><a href="' . self::SIGNUP_URL . '" class="button">Get An API Key</a></p>'; + } + } + + /** + * Validation for the API key + * + * @return void + * @author James Inman + */ + public function clockwork_options_validate( $val ) { + try { + $key = trim( $val['api_key'] ); + if( $key ) { + $clockwork = new WordPressClockwork( $key ); + $clockwork->checkKey(); + $this->clockwork = $clockwork; + add_settings_error( 'clockwork_options', 'clockwork_options', 'Your settings were saved! You can now start using Clockwork SMS.', 'updated' ); + } else { + $key = ''; + add_settings_error( 'clockwork_options', 'clockwork_options', 'You cannot enter a blank API key.', 'error' ); + } + } catch( ClockworkException $ex ) { + add_settings_error( 'clockwork_options', 'clockwork_options', 'Your API key was incorrect. Please enter it again.', 'error' ); + } + return $val; + } + + /** + * Render the main Clockwork options page + * + * @return void + * @author James Inman + */ + public function clockwork_options() { + $this->render_template( 'clockwork-options' ); + } + + /** + * Show a message at the top of the administration panel + * + * @param string $message Error message to show (can include HTML) + * @param bool $errormsg True to display as a red 'error message' + * @return void + * @author James Inman + */ + protected function show_admin_message( $message, $errormsg = false ) { + if( $errormsg ) { + echo '<div id="message" class="error">'; + } else { + echo '<div id="message" class="updated fade">'; + } + + echo "<p><strong>$message</strong></p></div>"; + } + + /** + * Render a template file from the templates directory + * + * @param string $name Path to template file, excluding .php extension + * @param array $data Array of data to include in template + * @return void + * @author James Inman + */ + protected function render_template( $name, $data = array() ) { + extract( $data ); + include( WP_PLUGIN_DIR . '/' . rtrim( basename( dirname( dirname( __FILE__ ) ) ), '/' ) . '/templates/' . $name . '.php' ); + } + +} |