Stephane Daury, Doug Stewart, and Viper007Bond
**************************************************************************/
class WPhone {
var $version;
var $folder;
var $whitelist = array();
var $browsers = array();
var $showui = FALSE;
var $ismobile = FALSE;
var $iscompat = FALSE;
var $context;
var $current_basename;
var $site_url;
var $blog_url;
var $interface_url;
var $interface_path;
var $admin_url;
var $compatregex;
var $falsepositiveregex;
var $forcetakeover = FALSE;
var $obstartstatus = FALSE;
var $menu = array();
var $submenu = array();
/**
* Ensures plugin is installed correctly and registers actions and filters
*
* @since 1.0.0
* @return NULL
*/
function WPhone() {
$this->version = '1.5.1';
if ( !defined('PLUGINDIR') ) {
add_action( 'admin_notices', array(&$this, 'WordPressTooOld') );
return;
}
$this->folder = PLUGINDIR . '/wphone';
// Make sure people install this plugin correctly by doing a couple simple checks
if ( 'wphone' !== basename( dirname( __FILE__ ) ) || !file_exists( ABSPATH . $this->folder . '/includes/header.php' ) ) {
add_action( 'admin_notices', array(&$this, 'IncorrectlyInstalled') );
return;
}
// Load up the localization file if we're using WordPress in a different language
// Just drop it in this plugin's "localization" folder and name it "wphone-[value in wp-config].mo"
load_plugin_textdomain( 'wphone', $this->folder . '/localization' );
// Set the cookie names as constants
define( 'WPHONE_USEUI_COOKIE', 'wordpress_wphone_useui_' . COOKIEHASH );
define( 'WPHONE_CHKBOX_COOKIE', 'wordpress_wphone_chkbox_' . COOKIEHASH );
// Set some variables after running their values through filters
$this->current_basename = apply_filters( 'wphone_currentbasename', basename( $_SERVER['PHP_SELF'] ) );
$this->compatregex = apply_filters( 'wphone_compatregex', '/iphone|ipod|safari/i' );
$this->falsepositiveregex = apply_filters( 'wphone_falsepositiveregex', '/symbian|nokia/i' );
$this->site_url = get_bloginfo( 'wpurl' );
$this->blog_url = get_option('home');
$this->interface_url = apply_filters( 'wphone_interfaceurl', $this->site_url . '/' . $this->folder . '/includes' );
$this->admin_url = apply_filters( 'wphone_adminurl', $this->site_url . '/wp-admin' );
# Create the user agents lists. These are filterable as well.
# Most of these browser names are thanks to Alex King via his GPL'ed "WordPress Mobile Edition" plugin
// Set and sort some browsers that are never mobile browsers
$this->whitelist = apply_filters( 'wphone_whitelistbrowsers', array(
'Stand Alone/QNws',
) );
natcasesort( $this->whitelist );
// Set and sort some browsers that we should consider mobile browsers
$this->browsers = apply_filters( 'wphone_mobilebrowsers', array(
'2.0 MMP',
'240x320',
'AvantGo',
'BlackBerry',
'Blazer',
'Cellphone',
'Danger',
'DoCoMo',
'Elaine/3.0',
'EudoraWeb',
'hiptop',
'iPhone',
'iPod',
'MMEF20',
'MOT-V',
'NetFront',
'Newt',
'Nokia',
'Opera Mini',
'Palm',
'portalmmm',
'Proxinet',
'ProxiNet',
'SHARP-TQ-GX10',
'Small',
'SonyEricsson',
'Symbian OS',
'SymbianOS',
'TS21i-10',
'UP.Browser',
'UP.Link',
'Windows CE',
'WinWAP',
) );
natcasesort( $this->browsers );
// Detect browsers. See function definition for details.
$this->LookForMobileBrowser();
# Register our hooks
// Login form stuff
add_action( 'login_head', array(&$this, 'LoginFormHead') );
add_action( 'login_form', array(&$this, 'LoginFormCheckbox'), 7 );
add_action( 'wp_login', array(&$this, 'LoginFormPOST') );
add_action( 'wp_logout', array(&$this, 'ClearCookie') );
# The rest are admin only, so don't bog down the main site
if ( !is_admin() ) return;
add_filter( 'wp_redirect', array(&$this, 'MaybeChangeRedirect'), 1 );
add_action( 'init', array(&$this, 'MaybeStartOutputBuffering'), 1 );
add_action( 'admin_notices', array(&$this, 'MaybeDisplayBufferError') );
add_action( 'admin_footer', array(&$this, 'MaybeOverride'), 77 );
// Welcome message
add_action( 'activate_wphone/wphone.php', array(&$this, 'PluginActivated') );
add_action( 'admin_notices', array(&$this, 'WelcomeMessage'), 7 );
add_action( 'plugins_loaded', array(&$this, 'QuickSwitchInterface'), 17 );
}
/**
* Displays an error saying this version of WordPress is too old.
*
* Designed for the "admin_notices" action.
*
* @since 1.0.0
* @return NULL
*/
function WordPressTooOld() { ?>
WordPress Version Too Old: WPhone is only compatible with WordPress 2.1+ and is designed for use with the latest version of WordPress. Please upgrade to the latest version.', 'wphone'), 'http://wordpress.org/download/' ); ?>
WPhone Incorrectly Installed: WPhone must be installed to %s and it's directory structure intact. You will not be able to use the plugin until this is fixed.", 'wphone'), '/' . PLUGINDIR . '/wphone/' ); ?>
WPhone! We hope your enjoy it. You can start using the admin interface by checking the new checkbox on the login form when you login on your phone.', 'wphone'), './?wphone=on' ); ?>
right now or later
}
/**
* Sets or deletes the USEUI cookie based on a URL variable.
*
* If $_GET['wphone'] is set to "on", sets the WPhone USEUI cookie.
* If $_GET['wphone'] is set to "off", deletes the WPhone USEUI cookie.
* Then redirects to the dashboard.
*
* Designed for the "plugins_loaded" action.
*
* @since 1.0.0
* @return NULL
*/
function QuickSwitchInterface() {
if ( 'on' != $_GET['wphone'] && 'off' != $_GET['wphone'] ) return;
if ( 'on' == $_GET['wphone'] ) $expire = time() + 31536000; // on
else $expire = time() - 31536000; // off
setcookie( WPHONE_USEUI_COOKIE, 1, $expire, COOKIEPATH, COOKIE_DOMAIN );
wp_redirect( get_bloginfo('wpurl') . '/wp-admin/' );
exit();
}
/**
* Sets the internal $showui, $ismobile, and $iscompat variables to either TRUE or FALSE based on a number of tests.
*
* @since 1.0.0
* @return NULL
*/
function LookForMobileBrowser() {
// Reset the vars
$this->ismobile = FALSE;
$this->iscompat = FALSE;
$this->showui = FALSE;
// If the user has manually selected the mobile interface, assume they're on a mobile device
if ( !empty($_COOKIE[WPHONE_USEUI_COOKIE]) ) {
$this->showui = TRUE;
$this->ismobile = TRUE;
// If the browser supports Javascript AND has "webkit" in the user agent, assume it's an iPhone or similiar
// This ensures it's not a partial JS-support browser and that it's not a no JS browser with a "webkit" user agent
if ( 'rich' == $_COOKIE[WPHONE_USEUI_COOKIE] && preg_match( $this->compatregex, $_SERVER['HTTP_USER_AGENT'] ) && FALSE == preg_match( $this->falsepositiveregex, $_SERVER['HTTP_USER_AGENT'] ) )
$this->iscompat = TRUE;
}
// Okay, so they don't want the mobile interface, but let's guess about their browser anyway for other uses
else {
// Check to see if the user's browser is on the browser whitelist
foreach ( (array) $this->whitelist as $browser ) {
if ( strstr( $_SERVER['HTTP_USER_AGENT'], $browser ) ) {
return;
}
}
// Check for known mobile browsers
foreach ( (array) $this->browsers as $browser ) {
if ( strstr( $_SERVER['HTTP_USER_AGENT'], $browser ) ) {
$this->ismobile = TRUE;
return;
}
}
}
}
/**
* If the mobile UI is wanted, this function attempts to turn on output
* buffering and records the result to the internal variable, $obstartstatus.
*
* Designed for the "init" action.
*
* @since 1.0.0
* @return NULL
*/
function MaybeStartOutputBuffering() {
if ( TRUE != $this->showui ) return;
$this->obstartstatus = ob_start();
}
/**
* If the mobile UI is wanted but output buffering failed, then display an error message.
*
* Designed for the "admin_notices" action.
*
* @since 1.0.0
* @return NULL
*/
function MaybeDisplayBufferError() {
if ( TRUE != $this->showui || FALSE != $this->obstartstatus ) return;
echo '' . __('WPhone was unable to display the mobile interface as ob_start() failed to initialize.', 'wphone') . "
\n\n";
}
/**
* If the mobile UI is wanted and output buffering didn't fail, check for
* certain cases where we want to modify the redirect URL to something else of our choosing.
*
* Designed for the "wp_redirect" filter.
*
* @since 1.0.0
* @param string $location A full or relative URL to redirect to.
* @return string $location The possibly modified full or relative URL to redirect to.
*/
function MaybeChangeRedirect( $location ) {
if ( TRUE != $this->showui || FALSE == $this->obstartstatus ) return $location;
global $user_ID;
// After deleting a comment
if ( 'comment.php' == $this->current_basename && 'deletecomment' == $_GET['action'] && get_option('siteurl') . '/wp-admin/edit-comments.php' == $location ) {
$location = 'edit-comments.php?type=approved&parent=edit-comments';
}
// After managing a post and it's not published
elseif ( 'post.php' == $this->current_basename ) {
$post_ID = (int) $_POST['post_ID'];
$post = get_post($post_ID);
// If a draft, redirect to your or others' drafts
if ( 'post' == $post->post_type && 'draft' == $post->post_status ) {
$location = ( $user_ID == $post->post_author ) ? 'edit.php?post_status=draft&author=' . $user_ID : 'edit.php?post_status=draft&author=-' . $user_ID;
}
// if it's pending, redirect to the pending list
elseif ( 'post' == $post->post_type && 'pending' == $post->post_status ) {
$location = 'edit.php?post_status=pending';
}
}
return $location;
}
/**
* Display the mobile admin interface if it's wanted.
*
* If the mobile UI is wanted and output buffering didn't fail, empty the
* output buffer, determine what page is to be displayed, enable GZip, require_once() the
* file containing the page we wish to display, and then exit() to avoid any further HTML.
*
* Designed for the "admin_footer" filter.
*
* @since 1.0.0
* @return NULL
*/
function MaybeOverride() {
if ( TRUE != $this->showui || FALSE == $this->obstartstatus ) return;
auth_redirect(); // Make sure the user is logged in with credentials
ob_clean(); // Dump any HTML that's already been created
$current_basename = $this->current_basename; // Incase the old var is referenced anywhere
// Figure out which one of files contains the stuff we need as a base
switch ( $this->current_basename ) {
// Write or edit posts and pages
case 'post.php' :
case 'page.php' :
case 'post-new.php' :
case 'page-new.php' :
$this->context = ( strstr($this->current_basename, 'page') ) ? 'page' : 'post';
$include_file = 'write.php';
break;
// List posts or pages
case 'edit.php' :
case 'edit-pages.php' :
$this->context = ( strstr($this->current_basename, 'page') ) ? 'page' : 'post';
$include_file = 'list.php';
break;
// List or edit comments
case 'edit-comments.php' :
case 'comment.php' :
$this->context = ( strstr($this->current_basename, 's.php') ) ? 'list' : 'edit';
$include_file = 'comment.php';
break;
// List users or edit user (including self)
case 'profile.php' :
case 'users.php' :
case 'user-edit.php' :
$this->context = ( strstr($this->current_basename, 'users') ) ? 'list' : 'edit';
$include_file = 'user.php';
break;
// List, add or edit categories
case 'categories.php' :
$this->context = ( $_GET['action'] ) ? 'edit' : 'list';
$include_file = 'category.php';
break;
// List or edit categories
case 'plugins.php' :
$this->context = 'list';
$include_file = 'plugins.php';
break;
// Index or unknown page
default :
$this->context = 'dashboard';
$include_file = 'dashboard.php';
}
// Special case for successful submit of the "Your Profile" form
if ( 'profile.php' == $this->current_basename && !empty($_GET['updated']) ) {
$this->context = 'dashboard';
$include_file = 'dashboard.php';
$profileupdated = TRUE;
}
global $wpdb, $userdata, $wp_version;
if ( empty($userdata->ID) ) get_currentuserinfo(); // Just incase
// Instantiate the navigantional menus and submenus
$this->set_nav_menus();
// Attempt to gzip page to make faster load times
ob_start( 'ob_gzhandler' );
// Load up the admin functions and such
require_once( ABSPATH . 'wp-admin/admin.php');
// Filters!
$this->context = apply_filters( 'wphone_context', $this->context );
$include_file = apply_filters( 'wphone_includefile', ABSPATH . $this->folder . '/includes/' . $include_file );
// Load the file to display
if ( !file_exists( $include_file ) ) {
wp_die( sprintf( __('The file WPhone needed to display this page could not be found. Click here to disable the mobile interface.', 'wphone'), './?wphone=off' ) );
}
require_once( $include_file );
// Stop from displaying the rest of the stuff below the "admin_footer" hook
exit();
}
/**
* Use current_user_can() to check if the user is allowed to do a capability
* and if not, display an error message and then stop the script.
*
* @since 1.0.0
* @param string $args[0] The capability name to check for
* @param string $args[1] An ID or other identifier to use in combination with the capability.
* @param string $args[2] Unknown use, if any use at all.
* @return NULL
*/
function check_user_permissions() {
$args = func_get_args();
if ( ! current_user_can( $args[0], $args[1], $args[2] ) ) {
exit (
''
. '\n