Display Rendering * The class uses a similar technique to Ruby On Rails views, whereby the display HTML is kept * in a separate directory and file from the main code. A display is 'rendered'(sent to the browser) * or 'captured'(returned to the calling function). * * Template files are separated into two areas: admin and user. Admin templates are only for display in * the WordPress admin interface, while user templates are typically for display on the site(although neither * of these are enforced). All templates are PHP code, but are referred to without .php extension. * * The reason for this separation is that one golden rule of plugin creation is that someone will always want to change * the formatting and style of your output. Rather than forcing them to modify the plugin(bad), or modify files within * the plugin(equally bad), the class allows user templates to be overridden with files contained within the theme. * * An additional benefit is that it leads to code re-use, especially with regards to Ajax(i.e. your display code can be called from * many locations) * * Template files are located within the 'view' subdirectory of the plugins base(specified when registering the plugin): * *
myplugin/view/admin
 * myplugin/view/myplugin
* * Admin templates are contained within 'admin', and user templates are contained within a directory of the same name as the plugin. * * User files can be overridden within the theme by creating a similar directory structure: * *
/themes/mytheme/view/myplugin
* * The class will first look in the theme and then defaults to the plugin. A plugin should always provide default templates. * *

Display Parameters

* Also similar to Ruby On Rails, when you display a template you must supply the parameters that the template has access to. This tries * to ensure a very clean separation between code and display. Parameters are supplied as an associative array mapping variable name to variable value. * * For example, * * array( 'message' => 'Your data was processed', 'items' => 103); * *

How it works in practice

* You create a template file to display how many items have been processed. You store this in 'view/admin/processed.php': * *
<p>You processed <?php echo $items ?> items</p>
* * When you want to display this in your plugin you use: * *
 $this->render_admin( 'processed', array( 'items' => 100));
* * @package WordPress base library * @author John Godley * @copyright Copyright(C) John Godley **/ class AT_Plugin { /** * Plugin name * @var string **/ var $plugin_name; /** * Plugin 'view' directory * @var string Directory **/ var $plugin_base; /** * Version URL(if enabled) * @var string URL **/ var $version_url; /** * Register your plugin with a name and base directory. This must be called once. * * @param string $name Name of your plugin. Is used to determine the plugin locale domain * @param string $base Directory containing the plugin's 'view' files. * @return void **/ function register_plugin( $name, $base ) { $this->plugin_base = rtrim( dirname( $base ), '/' ); $this->plugin_name = $name; $this->add_action( 'init', 'load_locale' ); global $wp_version; if ( version_compare( $wp_version, '2.7', '<' ) ) $this->add_action( 'admin_menu', 'compatibility_27' ); if ( version_compare( $wp_version, '2.6', '<' ) ) $this->add_action( 'admin_menu', 'compatibility_26' ); if ( version_compare( $wp_version, '2.5', '<' ) ) { $this->add_action( 'admin_menu', 'compatibility_25' ); if ( !function_exists( 'is_front_page' ) ) { function is_front_page ( ) { return is_home (); } } } } function compatibility_25() { if ( !function_exists( 'check_ajax_referer' ) ) { function check_ajax_referer( $action = -1, $query_arg = false, $die = true ) { if ( $query_arg ) $nonce = $_REQUEST[$query_arg]; else $nonce = $_REQUEST['_ajax_nonce'] ? $_REQUEST['_ajax_nonce'] : $_REQUEST['_wpnonce']; $result = wp_verify_nonce( $nonce, $action ); if ( $die && false == $result ) die('-1'); do_action('check_ajax_referer', $action, $result); return $result; } } } function compatibility_26() { if ( !function_exists( 'admin_url' ) ) { function admin_url() { $url = site_url('wp-admin/', 'admin'); if ( !empty($path) && is_string($path) && strpos($path, '..') === false ) $url .= ltrim($path, '/'); return $url; } } if ( !function_exists( 'is_ssl' ) ) { function is_ssl() { if ( isset($_SERVER['HTTPS']) ) { if ( 'on' == strtolower($_SERVER['HTTPS']) ) return true; if ( '1' == $_SERVER['HTTPS'] ) return true; } elseif ( isset($_SERVER['SERVER_PORT']) && ( '443' == $_SERVER['SERVER_PORT'] ) ) { return true; } return false; } } if ( !function_exists( 'site_url' ) ) { function site_url($path = '', $scheme = null) { $scheme = ( is_ssl() ? 'https' : 'http' ); $url = str_replace( 'http://', "{$scheme}://", get_option('siteurl') ); if ( !empty($path) && is_string($path) && strpos($path, '..') === false ) $url .= '/' . ltrim($path, '/'); return apply_filters('site_url', $url, $path, $orig_scheme); } } } /** * Backwards compatible admin functions * @return void **/ function compatibility_27() { if ( !function_exists( 'screen_icon' ) ) { function screen_icon() { } } if ( !function_exists( 'add_meta_box' ) ) { function add_meta_box ( $id, $title, $callback, $page, $context = 'advanced', $priority = 'default', $callback_args=null ) { add_action( 'dbx_post_advanced', $callback ); } } } /** * Hook called to change the locale directory * @return void **/ function load_locale() { // Here we manually fudge the plugin locale as WP doesnt allow many options $locale = get_locale(); if( empty( $locale ) ) $locale = 'en_US'; $mofile = dirname( __FILE__ )."/locale/$locale.mo"; load_textdomain( $this->plugin_name, $mofile ); } /** * Register a WordPress action and map it back to the calling object * * @param string $action Name of the action * @param string $function Function name(optional) * @param int $priority WordPress priority(optional) * @param int $accepted_args Number of arguments the function accepts(optional) * @return void **/ function add_action( $action, $function = '', $priority = 10, $accepted_args = 1 ) { add_action( $action, array( &$this, $function == '' ? $action : $function ), $priority, $accepted_args ); } /** * Register a WordPress filter and map it back to the calling object * * @param string $action Name of the action * @param string $function Function name(optional) * @param int $priority WordPress priority(optional) * @param int $accepted_args Number of arguments the function accepts(optional) * @return void **/ function add_filter( $filter, $function = '', $priority = 10, $accepted_args = 1 ) { add_filter( $filter, array( &$this, $function == '' ? $filter : $function ), $priority, $accepted_args ); } /** * Special activation function that takes into account the plugin directory * * @param string $pluginfile The plugin file location(i.e. __FILE__) * @param string $function Optional function name, or default to 'activate' * @return void **/ function register_activation( $pluginfile, $function = '' ) { add_action( 'activate_'.basename( dirname( $pluginfile ) ).'/'.basename( $pluginfile ), array( &$this, $function == '' ? 'activate' : $function ) ); } function register_ajax( $action, $function = '', $priority = 10 ) { add_action( 'wp_ajax_'.$action, array( &$this, $function == '' ? $action : $function ), $priority ); } /** * Special deactivation function that takes into account the plugin directory * * @param string $pluginfile The plugin file location(i.e. __FILE__) * @param string $function Optional function name, or default to 'deactivate' * @return void **/ function register_deactivation( $pluginfile, $function = '' ) { add_action( 'deactivate_'.basename( dirname( $pluginfile ) ).'/'.basename( $pluginfile ), array( &$this, $function == '' ? 'deactivate' : $function ) ); } function register_plugin_settings( $pluginfile, $function = '' ) { add_action( 'plugin_action_links_'.basename( dirname( $pluginfile ) ).'/'.basename( $pluginfile ), array( &$this, $function == '' ? 'plugin_settings' : $function ), 10, 4 ); } /** * Renders an admin section of display code * * @param string $ug_name Name of the admin file(without extension) * @param string $array Array of variable name=>value that is available to the display code(optional) * @return void **/ function render_admin( $ug_name, $ug_vars = array() ) { global $plugin_base; foreach ( $ug_vars AS $key => $val ) { $$key = $val; } if ( file_exists( "{$this->plugin_base}/view/admin/$ug_name.php" ) ) include "{$this->plugin_base}/view/admin/$ug_name.php"; else echo "

Rendering of admin template {$this->plugin_base}/view/admin/$ug_name.php failed

"; } /** * Renders a section of user display code. The code is first checked for in the current theme display directory * before defaulting to the plugin * * @param string $ug_name Name of the admin file(without extension) * @param string $array Array of variable name=>value that is available to the display code(optional) * @return void **/ function render( $ug_name, $ug_vars = array() ) { foreach ( $ug_vars AS $key => $val ) { $$key = $val; } if ( file_exists( TEMPLATEPATH."/view/{$this->plugin_name}/$ug_name.php" ) ) include TEMPLATEPATH."/view/{$this->plugin_name}/$ug_name.php"; elseif ( file_exists( "{$this->plugin_base}/view/{$this->plugin_name}/$ug_name.php" ) ) include "{$this->plugin_base}/view/{$this->plugin_name}/$ug_name.php"; else echo "

Rendering of template $ug_name.php failed

"; } /** * Renders a section of user display code. The code is first checked for in the current theme display directory * before defaulting to the plugin * * @param string $ug_name Name of the admin file(without extension) * @param string $array Array of variable name=>value that is available to the display code(optional) * @return void **/ function capture( $ug_name, $ug_vars = array() ) { ob_start(); $this->render( $ug_name, $ug_vars ); $output = ob_get_contents(); ob_end_clean(); return $output; } /** * Captures an admin section of display code * * @param string $ug_name Name of the admin file(without extension) * @param string $array Array of variable name=>value that is available to the display code(optional) * @return string Captured code **/ function capture_admin( $ug_name, $ug_vars = array() ) { ob_start(); $this->render_admin( $ug_name, $ug_vars ); $output = ob_get_contents(); ob_end_clean(); return $output; } /** * Display a standard error message(using CSS ID 'message' and classes 'fade' and 'error) * * @param string $message Message to display * @return void **/ function render_error( $message ) { ?>

plugin_base; } function base () { $parts = explode( '?', basename( $_SERVER['REQUEST_URI'] ) ); return $parts[0]; } /** * Get a URL to the plugin. Useful for specifying JS and CSS files * * For example, * * @return string URL **/ function url( $url = '' ) { if ( $url ) return str_replace( '\\', urlencode( '\\' ), str_replace( '&amp', '&', str_replace( '&', '&', $url ) ) ); $root = ABSPATH; if ( defined( 'WP_PLUGIN_DIR' ) ) $root = WP_PLUGIN_DIR; $url = substr( $this->plugin_base, strlen( $this->realpath( $root ) ) ); if ( DIRECTORY_SEPARATOR != '/' ) $url = str_replace( DIRECTORY_SEPARATOR, '/', $url ); if ( defined( 'WP_PLUGIN_URL' ) ) $url = WP_PLUGIN_URL.'/'.ltrim( $url, '/' ); else $url = get_bloginfo( 'wpurl' ).'/'.ltrim( $url, '/' ); // Do an SSL check - only works on Apache global $is_IIS; if ( isset( $_SERVER['HTTPS'] ) && strtolower( $_SERVER['HTTPS'] ) == 'on' && $is_IIS === false ) $url = str_replace( 'http://', 'https://', $url ); return $url; } /** * Version of realpath that will work on systems without realpath * * @param string $path The path to canonicalize * @return string Canonicalized path **/ function realpath( $path ) { if ( function_exists( 'realpath' ) && DIRECTORY_SEPARATOR == '/' ) return realpath( $path ); elseif ( DIRECTORY_SEPARATOR == '/' ) { $path = preg_replace( '/^~/', $_SERVER['DOCUMENT_ROOT'], $path ); // canonicalize $path = explode( DIRECTORY_SEPARATOR, $path ); $newpath = array(); for ( $i = 0; $i < count( $path ); $i++ ) { if ( $path[$i] === '' || $path[$i] === '.' ) continue; if ( $path[$i] === '..' ) { array_pop( $newpath ); continue; } array_push( $newpath, $path[$i] ); } return DIRECTORY_SEPARATOR.implode( DIRECTORY_SEPARATOR, $newpath ); } return $path; } /** * Helper function to check a checkbox if the item has been checked * * @param mixed $item Checkbox value, or array of checkbox values: field => value * @param string $field Fieldname, if array is given for $item * @return void **/ function checked( $item, $field = '' ) { if ( $field && is_array( $item ) ) { if ( isset( $item[$field] ) && $item[$field] ) echo ' checked="checked"'; } elseif ( !empty( $item ) ) echo ' checked="checked"'; } /** * Helper function to display a dropdown select box * * @param array $items Associative array of: fieldname => label * @param string $default Default fieldname to select * @return void **/ function select( $items, $default = '' ) { if ( count( $items ) > 0 ) { foreach ( $items AS $key => $value ) { if ( is_array( $value ) ) { echo ''; foreach ( $value AS $sub => $subvalue ) { echo ''; } echo ''; } else echo ''; } } } /** * Expanded version of htmlspecialchars which detects the blog encoding and runs iconv on any encoding that is not supported by htmlspecialchars * * @param string $text Text to run htmlspecialchars on * @return void **/ function specialchars( $text ) { $charset = get_option( 'blog_charset' ); if ( $charset != 'UTF-8' && function_exists( 'iconv' ) && !in_array( $charset, array( 'ISO-8859-1', 'ISO-8859-15', 'cp1251', 'cp1252', 'KOI8-R', 'BIG5', 'GB2312', 'Shift_JIS', 'EUC-JP' ) ) ) return iconv( 'UTF-8//IGNORE', $charset, htmlspecialchars( iconv( $charset, 'UTF-8//IGNORE', $text ) ) ); return htmlspecialchars( $text, ENT_COMPAT, $charset ); } /** * Special version of strlen that runs mb_strlen if blog encoding is not UTF-8 * * @param string $name Name of your plugin. Is used to determine the plugin locale domain * @param string $base Directory containing the plugin's 'view' files. * @return void **/ function strlen( $text ) { $charset = get_option( 'blog_charset' ); if ( $charset != 'UTF-8' && function_exists( 'mb_strlen' ) ) return mb_strlen( $text ); return strlen( $text ); } } /** * Debug helper, borrowed from CakePHP, that displays a print_r inside
 tags
 *
 * @param string $name Name of your plugin.  Is used to determine the plugin locale domain
 * @param string $base Directory containing the plugin's 'view' files.
 * @return void
 **/
if ( !function_exists( 'pr' ) ) {
	function pr( $thing ) {
		echo '
';
		print_r( $thing );
		echo '
'; } } if ( !function_exists( '_n' ) ) { function _n($single, $plural, $number, $domain = 'default') { return __ngettext($single, $plural, $number, $domain = 'default'); } }