| 1 |
<?php |
| 2 |
|
| 3 |
// ====================================================================================== |
| 4 |
// This library is free software; you can redistribute it and/or |
| 5 |
// modify it under the terms of the GNU Lesser General Public |
| 6 |
// License as published by the Free Software Foundation; either |
| 7 |
// version 2.1 of the License, or(at your option) any later version. |
| 8 |
// |
| 9 |
// This library is distributed in the hope that it will be useful, |
| 10 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 12 |
// Lesser General Public License for more details. |
| 13 |
// ====================================================================================== |
| 14 |
// @author John Godley(http://urbangiraffe.com) |
| 15 |
// @version 0.2.7 |
| 16 |
// @copyright Copyright © 2009 John Godley, All Rights Reserved |
| 17 |
// ====================================================================================== |
| 18 |
// 0.1.6 - Corrected WP locale functions |
| 19 |
// 0.1.7 - Add phpdoc comments |
| 20 |
// 0.1.8 - Support for Admin SSL |
| 21 |
// 0.1.9 - URL encoding, defer localization until init |
| 22 |
// 0.1.10 - Better URL encoding |
| 23 |
// 0.1.11 - Make work in WP 2.0, fix HTTPS issue on IIS |
| 24 |
// 0.1.12 - Activation/deactivation actions that take into account the directory |
| 25 |
// 0.1.13 - Add realpath function |
| 26 |
// 0.1.14 - Add select/checked functions, fix locale loader |
| 27 |
// 0.1.15 - Remove dependency on prototype |
| 28 |
// 0.1.16 - Add support for homedir in realpath |
| 29 |
// 0.1.17 - Added widget class |
| 30 |
// 0.1.18 - Expand checked function |
| 31 |
// 0.1.19 - Make url() cope with sites with no trailing slash |
| 32 |
// 0.1.20 - Change init function to prevent overloading |
| 33 |
// 0.1.21 - Make widget work for WP 2.1 |
| 34 |
// 0.1.22 - Make select work with option groups, RSS compatability fix |
| 35 |
// 0.1.23 - Make widget count work better, fix widgets in K2 |
| 36 |
// 0.1.24 - Make realpath better |
| 37 |
// 0.1.25 - Support for new WP2.6 config location |
| 38 |
// 0.1.26 - Add description to widget class |
| 39 |
// 0.1.27 - Realpath on windows again |
| 40 |
// 0.1.28 - Plugin version information |
| 41 |
// 0.1.29 - Plugin version for older WP |
| 42 |
// 0.1.30 - Add htmlspecialchars for non-support charsets |
| 43 |
// 0.2 - WP Coding style |
| 44 |
// 0.2.1 - Better HTTPS detection |
| 45 |
// 0.2.2 - Plugin settings, base function |
| 46 |
// 0.2.3 - More HTTPS |
| 47 |
// 0.2.4 - Ajax helper, more compatability functions |
| 48 |
// 0.2.5 - _n helper |
| 49 |
// 0.2.6 - Compatability functions js_esc |
| 50 |
// 0.2.7 - Allow multiple hooks in add_action/add_filter |
| 51 |
// ====================================================================================== |
| 52 |
|
| 53 |
|
| 54 |
/** |
| 55 |
* Wraps up several useful functions for WordPress plugins and provides a method to separate |
| 56 |
* display HTML from PHP code. |
| 57 |
* |
| 58 |
* <h4>Display Rendering</h4> |
| 59 |
* The class uses a similar technique to Ruby On Rails views, whereby the display HTML is kept |
| 60 |
* in a separate directory and file from the main code. A display is 'rendered'(sent to the browser) |
| 61 |
* or 'captured'(returned to the calling function). |
| 62 |
* |
| 63 |
* Template files are separated into two areas: admin and user. Admin templates are only for display in |
| 64 |
* the WordPress admin interface, while user templates are typically for display on the site(although neither |
| 65 |
* of these are enforced). All templates are PHP code, but are referred to without .php extension. |
| 66 |
* |
| 67 |
* The reason for this separation is that one golden rule of plugin creation is that someone will always want to change |
| 68 |
* the formatting and style of your output. Rather than forcing them to modify the plugin(bad), or modify files within |
| 69 |
* the plugin(equally bad), the class allows user templates to be overridden with files contained within the theme. |
| 70 |
* |
| 71 |
* 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 |
| 72 |
* many locations) |
| 73 |
* |
| 74 |
* Template files are located within the 'view' subdirectory of the plugins base(specified when registering the plugin): |
| 75 |
* |
| 76 |
* <pre>myplugin/view/admin |
| 77 |
* myplugin/view/myplugin</pre> |
| 78 |
* |
| 79 |
* Admin templates are contained within 'admin', and user templates are contained within a directory of the same name as the plugin. |
| 80 |
* |
| 81 |
* User files can be overridden within the theme by creating a similar directory structure: |
| 82 |
* |
| 83 |
* <pre>/themes/mytheme/view/myplugin</pre> |
| 84 |
* |
| 85 |
* The class will first look in the theme and then defaults to the plugin. A plugin should always provide default templates. |
| 86 |
* |
| 87 |
* <h4>Display Parameters</h4> |
| 88 |
* Also similar to Ruby On Rails, when you display a template you must supply the parameters that the template has access to. This tries |
| 89 |
* to ensure a very clean separation between code and display. Parameters are supplied as an associative array mapping variable name to variable value. |
| 90 |
* |
| 91 |
* For example, |
| 92 |
* |
| 93 |
* array( 'message' => 'Your data was processed', 'items' => 103); |
| 94 |
* |
| 95 |
* <h4>How it works in practice</h4> |
| 96 |
* You create a template file to display how many items have been processed. You store this in 'view/admin/processed.php': |
| 97 |
* |
| 98 |
* <pre><p>You processed <?php echo $items ?> items</p></pre> |
| 99 |
* |
| 100 |
* When you want to display this in your plugin you use: |
| 101 |
* |
| 102 |
* <pre> $this->render_admin( 'processed', array( 'items' => 100));</pre> |
| 103 |
* |
| 104 |
* @package WordPress base library |
| 105 |
* @author John Godley |
| 106 |
* @copyright Copyright(C) John Godley |
| 107 |
**/ |
| 108 |
|
| 109 |
class Redirection_Plugin { |
| 110 |
/** |
| 111 |
* Plugin name |
| 112 |
* @var string |
| 113 |
**/ |
| 114 |
var $plugin_name; |
| 115 |
|
| 116 |
/** |
| 117 |
* Plugin 'view' directory |
| 118 |
* @var string Directory |
| 119 |
**/ |
| 120 |
var $plugin_base; |
| 121 |
|
| 122 |
/** |
| 123 |
* Version URL(if enabled) |
| 124 |
* @var string URL |
| 125 |
**/ |
| 126 |
var $version_url; |
| 127 |
|
| 128 |
/** |
| 129 |
* Register your plugin with a name and base directory. This <strong>must</strong> be called once. |
| 130 |
* |
| 131 |
* @param string $name Name of your plugin. Is used to determine the plugin locale domain |
| 132 |
* @param string $base Directory containing the plugin's 'view' files. |
| 133 |
* @return void |
| 134 |
**/ |
| 135 |
function register_plugin( $name, $base ) { |
| 136 |
$this->plugin_base = rtrim( dirname( $base ), '/' ); |
| 137 |
$this->plugin_name = $name; |
| 138 |
|
| 139 |
$this->add_action( 'init', 'load_locale' ); |
| 140 |
} |
| 141 |
|
| 142 |
/** |
| 143 |
* Hook called to change the locale directory |
| 144 |
* @return void |
| 145 |
**/ |
| 146 |
function load_locale() { |
| 147 |
// Here we manually fudge the plugin locale as WP doesnt allow many options |
| 148 |
$locale = get_locale(); |
| 149 |
if( empty( $locale ) ) |
| 150 |
$locale = 'en_US'; |
| 151 |
|
| 152 |
$mofile = dirname( __FILE__ )."/locale/$locale.mo"; |
| 153 |
load_textdomain( $this->plugin_name, $mofile ); |
| 154 |
} |
| 155 |
|
| 156 |
|
| 157 |
/** |
| 158 |
* Register a WordPress action and map it back to the calling object |
| 159 |
* |
| 160 |
* @param mixed $action Name of the action (single string or array of strings) |
| 161 |
* @param string $function Function name (optional, if an array is given for $action then first $action is used as function name) |
| 162 |
* @param int $priority WordPress priority(optional) |
| 163 |
* @param int $accepted_args Number of arguments the function accepts(optional) |
| 164 |
* @return void |
| 165 |
**/ |
| 166 |
function add_action( $actions, $function = '', $priority = 10, $accepted_args = 1 ) { |
| 167 |
if ( !is_array( $actions ) ) |
| 168 |
$actions = array( $actions ); |
| 169 |
|
| 170 |
foreach ( $actions AS $action ) { |
| 171 |
add_action( $action, array( &$this, $function == '' ? $actions[0] : $function ), $priority, $accepted_args ); |
| 172 |
} |
| 173 |
} |
| 174 |
|
| 175 |
|
| 176 |
/** |
| 177 |
* Register a WordPress filter and map it back to the calling object |
| 178 |
* |
| 179 |
* @param mixed $action Name of the action (single string or array of strings) |
| 180 |
* @param string $function Function name (optional, if an array is given for $action then first $action is used as function name) |
| 181 |
* @param int $priority WordPress priority(optional) |
| 182 |
* @param int $accepted_args Number of arguments the function accepts(optional) |
| 183 |
* @return void |
| 184 |
**/ |
| 185 |
function add_filter( $filters, $function = '', $priority = 10, $accepted_args = 1 ) { |
| 186 |
if ( !is_array( $filters ) ) |
| 187 |
$filters = array( $filters ); |
| 188 |
|
| 189 |
foreach ( $filters AS $filter ) { |
| 190 |
add_filter( $filter, array( &$this, $function == '' ? $filters[0] : $function ), $priority, $accepted_args ); |
| 191 |
} |
| 192 |
} |
| 193 |
|
| 194 |
|
| 195 |
/** |
| 196 |
* Special activation function that takes into account the plugin directory |
| 197 |
* |
| 198 |
* @param string $pluginfile The plugin file location(i.e. __FILE__) |
| 199 |
* @param string $function Optional function name, or default to 'activate' |
| 200 |
* @return void |
| 201 |
**/ |
| 202 |
function register_activation( $pluginfile, $function = '' ) { |
| 203 |
add_action( 'activate_'.basename( dirname( $pluginfile ) ).'/'.basename( $pluginfile ), array( &$this, $function == '' ? 'activate' : $function ) ); |
| 204 |
} |
| 205 |
|
| 206 |
function register_ajax( $action, $function = '', $priority = 10 ) { |
| 207 |
add_action( 'wp_ajax_'.$action, array( &$this, $function == '' ? $action : $function ), $priority ); |
| 208 |
} |
| 209 |
|
| 210 |
/** |
| 211 |
* Special deactivation function that takes into account the plugin directory |
| 212 |
* |
| 213 |
* @param string $pluginfile The plugin file location(i.e. __FILE__) |
| 214 |
* @param string $function Optional function name, or default to 'deactivate' |
| 215 |
* @return void |
| 216 |
**/ |
| 217 |
function register_deactivation( $pluginfile, $function = '' ) { |
| 218 |
add_action( 'deactivate_'.basename( dirname( $pluginfile ) ).'/'.basename( $pluginfile ), array( &$this, $function == '' ? 'deactivate' : $function ) ); |
| 219 |
} |
| 220 |
|
| 221 |
function register_plugin_settings( $pluginfile, $function = '' ) { |
| 222 |
add_action( 'plugin_action_links_'.basename( dirname( $pluginfile ) ).'/'.basename( $pluginfile ), array( &$this, $function == '' ? 'plugin_settings' : $function ), 10, 4 ); |
| 223 |
} |
| 224 |
|
| 225 |
/** |
| 226 |
* Renders an admin section of display code |
| 227 |
* |
| 228 |
* @param string $ug_name Name of the admin file(without extension) |
| 229 |
* @param string $array Array of variable name=>value that is available to the display code(optional) |
| 230 |
* @return void |
| 231 |
**/ |
| 232 |
function render_admin( $ug_name, $ug_vars = array() ) { |
| 233 |
global $plugin_base; |
| 234 |
|
| 235 |
foreach ( $ug_vars AS $key => $val ) { |
| 236 |
$$key = $val; |
| 237 |
} |
| 238 |
|
| 239 |
if ( file_exists( "{$this->plugin_base}/view/admin/$ug_name.php" ) ) |
| 240 |
include "{$this->plugin_base}/view/admin/$ug_name.php"; |
| 241 |
else |
| 242 |
echo "<p>Rendering of admin template {$this->plugin_base}/view/admin/$ug_name.php failed</p>"; |
| 243 |
} |
| 244 |
|
| 245 |
/** |
| 246 |
* Renders a section of user display code. The code is first checked for in the current theme display directory |
| 247 |
* before defaulting to the plugin |
| 248 |
* |
| 249 |
* @param string $ug_name Name of the admin file(without extension) |
| 250 |
* @param string $array Array of variable name=>value that is available to the display code(optional) |
| 251 |
* @return void |
| 252 |
**/ |
| 253 |
function render( $ug_name, $ug_vars = array() ) { |
| 254 |
foreach ( $ug_vars AS $key => $val ) { |
| 255 |
$$key = $val; |
| 256 |
} |
| 257 |
|
| 258 |
if ( file_exists( TEMPLATEPATH."/view/{$this->plugin_name}/$ug_name.php" ) ) |
| 259 |
include TEMPLATEPATH."/view/{$this->plugin_name}/$ug_name.php"; |
| 260 |
elseif ( file_exists( "{$this->plugin_base}/view/{$this->plugin_name}/$ug_name.php" ) ) |
| 261 |
include "{$this->plugin_base}/view/{$this->plugin_name}/$ug_name.php"; |
| 262 |
else |
| 263 |
echo "<p>Rendering of template $ug_name.php failed</p>"; |
| 264 |
} |
| 265 |
|
| 266 |
/** |
| 267 |
* Renders a section of user display code. The code is first checked for in the current theme display directory |
| 268 |
* before defaulting to the plugin |
| 269 |
* |
| 270 |
* @param string $ug_name Name of the admin file(without extension) |
| 271 |
* @param string $array Array of variable name=>value that is available to the display code(optional) |
| 272 |
* @return void |
| 273 |
**/ |
| 274 |
function capture( $ug_name, $ug_vars = array() ) { |
| 275 |
ob_start(); |
| 276 |
|
| 277 |
$this->render( $ug_name, $ug_vars ); |
| 278 |
$output = ob_get_contents(); |
| 279 |
|
| 280 |
ob_end_clean(); |
| 281 |
return $output; |
| 282 |
} |
| 283 |
|
| 284 |
/** |
| 285 |
* Captures an admin section of display code |
| 286 |
* |
| 287 |
* @param string $ug_name Name of the admin file(without extension) |
| 288 |
* @param string $array Array of variable name=>value that is available to the display code(optional) |
| 289 |
* @return string Captured code |
| 290 |
**/ |
| 291 |
function capture_admin( $ug_name, $ug_vars = array() ) { |
| 292 |
ob_start(); |
| 293 |
|
| 294 |
$this->render_admin( $ug_name, $ug_vars ); |
| 295 |
$output = ob_get_contents(); |
| 296 |
|
| 297 |
ob_end_clean(); |
| 298 |
return $output; |
| 299 |
} |
| 300 |
|
| 301 |
/** |
| 302 |
* Display a standard error message(using CSS ID 'message' and classes 'fade' and 'error) |
| 303 |
* |
| 304 |
* @param string $message Message to display |
| 305 |
* @return void |
| 306 |
**/ |
| 307 |
function render_error( $message ) { |
| 308 |
?> |
| 309 |
<div class="fade error" id="message"> |
| 310 |
<p><?php echo $message ?></p> |
| 311 |
</div> |
| 312 |
<?php |
| 313 |
} |
| 314 |
|
| 315 |
/** |
| 316 |
* Display a standard notice(using CSS ID 'message' and class 'updated' ). |
| 317 |
* Note that the notice can be made to automatically disappear, and can be removed |
| 318 |
* by clicking on it. |
| 319 |
* |
| 320 |
* @param string $message Message to display |
| 321 |
* @param int $timeout Number of seconds to automatically remove the message(optional) |
| 322 |
* @return void |
| 323 |
**/ |
| 324 |
function render_message( $message, $timeout = 0 ) { |
| 325 |
?> |
| 326 |
<div class="updated" id="message" onclick="this.parentNode.removeChild(this)"> |
| 327 |
<p><?php echo $message ?></p> |
| 328 |
</div> |
| 329 |
<?php |
| 330 |
} |
| 331 |
|
| 332 |
/** |
| 333 |
* Get the plugin's base directory |
| 334 |
* |
| 335 |
* @return string Base directory |
| 336 |
**/ |
| 337 |
function dir() { |
| 338 |
return $this->plugin_base; |
| 339 |
} |
| 340 |
|
| 341 |
function base () { |
| 342 |
return admin_url( $this->plugin_name ); |
| 343 |
} |
| 344 |
|
| 345 |
/** |
| 346 |
* Get a URL to the plugin. Useful for specifying JS and CSS files |
| 347 |
* |
| 348 |
* For example, <img src="<?php echo $this->url() ?>/myimage.png"/> |
| 349 |
* |
| 350 |
* @return string URL |
| 351 |
**/ |
| 352 |
function url( $url = '' ) { |
| 353 |
if ( $url ) |
| 354 |
return str_replace( '\\', urlencode( '\\' ), str_replace( '&amp', '&', str_replace( '&', '&', $url ) ) ); |
| 355 |
|
| 356 |
$root = ABSPATH; |
| 357 |
if ( defined( 'WP_PLUGIN_DIR' ) ) |
| 358 |
$root = WP_PLUGIN_DIR; |
| 359 |
|
| 360 |
$url = substr( $this->plugin_base, strlen( $this->realpath( $root ) ) ); |
| 361 |
if ( DIRECTORY_SEPARATOR != '/' ) |
| 362 |
$url = str_replace( DIRECTORY_SEPARATOR, '/', $url ); |
| 363 |
|
| 364 |
if ( defined( 'WP_PLUGIN_URL' ) ) |
| 365 |
$url = WP_PLUGIN_URL.'/'.ltrim( $url, '/' ); |
| 366 |
else |
| 367 |
$url = get_bloginfo( 'wpurl' ).'/'.ltrim( $url, '/' ); |
| 368 |
|
| 369 |
// Do an SSL check - only works on Apache |
| 370 |
global $is_IIS; |
| 371 |
if ( isset( $_SERVER['HTTPS'] ) && strtolower( $_SERVER['HTTPS'] ) == 'on' && $is_IIS === false ) |
| 372 |
$url = str_replace( 'http://', 'https://', $url ); |
| 373 |
|
| 374 |
return $url; |
| 375 |
} |
| 376 |
|
| 377 |
/** |
| 378 |
* Version of realpath that will work on systems without realpath |
| 379 |
* |
| 380 |
* @param string $path The path to canonicalize |
| 381 |
* @return string Canonicalized path |
| 382 |
**/ |
| 383 |
function realpath( $path ) { |
| 384 |
if ( function_exists( 'realpath' ) && DIRECTORY_SEPARATOR == '/' ) |
| 385 |
return realpath( $path ); |
| 386 |
elseif ( DIRECTORY_SEPARATOR == '/' ) |
| 387 |
{ |
| 388 |
$path = preg_replace( '/^~/', $_SERVER['DOCUMENT_ROOT'], $path ); |
| 389 |
|
| 390 |
// canonicalize |
| 391 |
$path = explode( DIRECTORY_SEPARATOR, $path ); |
| 392 |
$newpath = array(); |
| 393 |
|
| 394 |
for ( $i = 0; $i < count( $path ); $i++ ) { |
| 395 |
if ( $path[$i] === '' || $path[$i] === '.' ) |
| 396 |
continue; |
| 397 |
|
| 398 |
if ( $path[$i] === '..' ) { |
| 399 |
array_pop( $newpath ); |
| 400 |
continue; |
| 401 |
} |
| 402 |
|
| 403 |
array_push( $newpath, $path[$i] ); |
| 404 |
} |
| 405 |
|
| 406 |
return DIRECTORY_SEPARATOR.implode( DIRECTORY_SEPARATOR, $newpath ); |
| 407 |
} |
| 408 |
|
| 409 |
return $path; |
| 410 |
} |
| 411 |
|
| 412 |
/** |
| 413 |
* Helper function to check a checkbox if the item has been checked |
| 414 |
* |
| 415 |
* @param mixed $item Checkbox value, or array of checkbox values: field => value |
| 416 |
* @param string $field Fieldname, if array is given for $item |
| 417 |
* @return void |
| 418 |
**/ |
| 419 |
function checked( $item, $field = '' ) { |
| 420 |
if ( $field && is_array( $item ) ) { |
| 421 |
if ( isset( $item[$field] ) && $item[$field] ) |
| 422 |
echo ' checked="checked"'; |
| 423 |
} |
| 424 |
elseif ( !empty( $item ) ) |
| 425 |
echo ' checked="checked"'; |
| 426 |
} |
| 427 |
|
| 428 |
/** |
| 429 |
* Helper function to display a dropdown select box |
| 430 |
* |
| 431 |
* @param array $items Associative array of: fieldname => label |
| 432 |
* @param string $default Default fieldname to select |
| 433 |
* @return void |
| 434 |
**/ |
| 435 |
function select( $items, $default = '' ) { |
| 436 |
if ( count( $items ) > 0 ) { |
| 437 |
foreach ( $items AS $key => $value ) { |
| 438 |
if ( is_array( $value ) ) { |
| 439 |
echo '<optgroup label="'.esc_attr( $key ).'">'; |
| 440 |
|
| 441 |
foreach ( $value AS $sub => $subvalue ) { |
| 442 |
echo '<option value="'.esc_attr( $sub ).'"'.( $sub == $default ? ' selected="selected"' : '' ).'>'.esc_html( $subvalue ).'</option>'; |
| 443 |
} |
| 444 |
|
| 445 |
echo '</optgroup>'; |
| 446 |
} |
| 447 |
else |
| 448 |
echo '<option value="'.esc_attr( $key ).'"'.( $key == $default ? ' selected="selected"' : '' ).'>'.esc_html( $value ).'</option>'; |
| 449 |
} |
| 450 |
} |
| 451 |
} |
| 452 |
|
| 453 |
/** |
| 454 |
* Expanded version of htmlspecialchars which detects the blog encoding and runs iconv on any encoding that is not supported by htmlspecialchars |
| 455 |
* |
| 456 |
* @param string $text Text to run htmlspecialchars on |
| 457 |
* @return void |
| 458 |
**/ |
| 459 |
function specialchars( $text ) { |
| 460 |
$charset = get_option( 'blog_charset' ); |
| 461 |
|
| 462 |
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' ) ) ) |
| 463 |
return iconv( 'UTF-8//IGNORE', $charset, htmlspecialchars( iconv( $charset, 'UTF-8//IGNORE', $text ) ) ); |
| 464 |
return htmlspecialchars( $text, ENT_COMPAT, $charset ); |
| 465 |
} |
| 466 |
|
| 467 |
/** |
| 468 |
* Special version of strlen that runs mb_strlen if blog encoding is not UTF-8 |
| 469 |
* |
| 470 |
* @param string $name Name of your plugin. Is used to determine the plugin locale domain |
| 471 |
* @param string $base Directory containing the plugin's 'view' files. |
| 472 |
* @return void |
| 473 |
**/ |
| 474 |
function strlen( $text ) { |
| 475 |
$charset = get_option( 'blog_charset' ); |
| 476 |
|
| 477 |
if ( $charset != 'UTF-8' && function_exists( 'mb_strlen' ) ) |
| 478 |
return mb_strlen( $text ); |
| 479 |
return strlen( $text ); |
| 480 |
} |
| 481 |
|
| 482 |
/** |
| 483 |
* Returns version of plugin |
| 484 |
* |
| 485 |
* @return string Version |
| 486 |
**/ |
| 487 |
function version() { |
| 488 |
$plugin_data = implode( '', file( $this->plugin_base ) ); |
| 489 |
|
| 490 |
if ( preg_match( '|Version:(.*)|i', $plugin_data, $version ) ) |
| 491 |
return trim( $version[1] ); |
| 492 |
return ''; |
| 493 |
} |
| 494 |
} |
| 495 |
|
| 496 |
/** |
| 497 |
* Debug helper, borrowed from CakePHP, that displays a print_r inside <pre></pre> tags |
| 498 |
* |
| 499 |
* @param string $name Name of your plugin. Is used to determine the plugin locale domain |
| 500 |
* @param string $base Directory containing the plugin's 'view' files. |
| 501 |
* @return void |
| 502 |
**/ |
| 503 |
if ( !function_exists( 'pr' ) ) { |
| 504 |
function pr( $thing ) { |
| 505 |
echo '<pre>'; |
| 506 |
print_r( $thing ); |
| 507 |
echo '</pre>'; |
| 508 |
} |
| 509 |
} |
| 510 |
|
| 511 |
if ( !function_exists( '_n' ) ) { |
| 512 |
function _n($single, $plural, $number, $domain = 'default') { |
| 513 |
return __ngettext($single, $plural, $number, $domain = 'default'); |
| 514 |
} |
| 515 |
} |
| 516 |
|