name
filename
filename_from_plugin_directory
path_from_plugin_directory
path_from_base_directory
url
@since 20130416
@var $paths
**/
public $paths = array();
/**
@brief The version of the plugin.
@since 20130811
@var $plugin_version
**/
public $plugin_version = 20000101;
/**
@brief Links to Wordpress' database object.
@since 20130416
@var $wpdb
**/
protected $wpdb;
/**
@brief Construct the class.
@param string $filename The __FILE__ special variable of the parent.
@since 20130416
**/
public function __construct( $__FILE__ = null )
{
// If no filename was specified, try to get the parent's filename.
if ( $__FILE__ === null )
{
$stacktrace = @debug_backtrace( false );
$__FILE__ = $stacktrace[ 0 ][ 'file' ];
}
if ( ! defined( 'ABSPATH' ) )
{
// Was this run from the command line?
if ( isset( $_SERVER[ 'argc'] ) )
{
$this->paths = array(
'__FILE__' => $__FILE__,
'name' => get_class( $this ),
'filename' => basename( $__FILE__ ),
);
$this->do_cli();
}
else
wp_die( 'ABSPATH is not defined!' );
}
parent::__construct();
global $wpdb;
$this->wpdb = $wpdb;
$this->is_network = MULTISITE;
$this->is_multisite = MULTISITE;
$this->submenu_pages = new \plainview\sdk_eightb_sold_alerts\collections\collection;
// Completely different path handling for Windows and then everything else. *sigh*
if ( PHP_OS == 'WINNT' )
{
$wp_plugin_dir = str_replace( '/', DIRECTORY_SEPARATOR, WP_PLUGIN_DIR );
$base_dir = dirname( dirname( WP_PLUGIN_DIR ) );
$path_from_plugin_directory = dirname( str_replace( $wp_plugin_dir, '', $__FILE__ ) );
$__FILE___from_plugin_directory = $path_from_plugin_directory . DIRECTORY_SEPARATOR . basename( $__FILE__ );
$this->paths = array(
'__FILE__' => $__FILE__,
'name' => get_class( $this ),
'filename' => basename( $__FILE__ ),
'filename_from_plugin_directory' => $__FILE___from_plugin_directory,
'path_from_plugin_directory' => $path_from_plugin_directory,
'path_from_base_directory' => str_replace( $base_dir, '', $wp_plugin_dir ) . $path_from_plugin_directory,
'url' => plugins_url() . str_replace( DIRECTORY_SEPARATOR, '/', $path_from_plugin_directory ),
);
}
else
{
// Everything else except Windows.
$this->paths = array(
'__FILE__' => $__FILE__,
'name' => get_class( $this ),
'filename' => basename( $__FILE__ ),
'filename_from_plugin_directory' => str_replace( WP_PLUGIN_DIR, '', $__FILE__ ),
'path_from_plugin_directory' => str_replace( WP_PLUGIN_DIR, '', dirname( $__FILE__ ) ),
'path_from_base_directory' => dirname( str_replace( ABSPATH, '', $__FILE__ ) ),
'url' => plugins_url() . str_replace( WP_PLUGIN_DIR, '', dirname( $__FILE__ ) ),
);
}
register_activation_hook( $this->paths( 'filename_from_plugin_directory' ), array( $this, 'activate_internal' ) );
register_deactivation_hook( $this->paths( 'filename_from_plugin_directory' ), array( $this, 'deactivate_internal' ) );
$this->_construct();
}
/**
@brief Overloadable method called after __construct.
@details
A convenience method that is called after the base is constructed.
This method has the advantage of not requiring neither parameters nor parent::.
@since 20130722
**/
public function _construct()
{
}
/**
@brief Overridable activation function.
@see activate_internal()
@since 20130416
**/
public function activate()
{
}
/**
@brief Internal activation function.
Child plugins should override activate().
@since 20130416
**/
public function activate_internal()
{
$this->register_options();
$this->activate();
}
/**
@brief Queues a submenu page for adding later.
@details 20151226 Switched to use menu_page object.
@see menu_page()
@since 20130416
**/
public function add_submenu_page()
{
// 0 1 2 3 4 5
// ( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $function = '' )
$args = func_get_args();
$this->menu_page()
->submenu( $args[ 4 ] )
->callback( $args[ 5 ] )
->capability( $args[ 3 ] )
->menu_title( $args[ 2 ] )
->page_title( $args[ 1 ] );
}
/**
@brief Flush the add_submenu_page cache.
@details Will first sort by key and then add the subpages.
@since 20130416
**/
public function add_submenu_pages()
{
$this->menu_page()->add_all();
}
/**
@brief Shows the uninstall form.
@since 20130416
**/
public function admin_uninstall()
{
$r = '';
$form = $this->form2();
$form->prefix( get_class( $this ) );
$form->markup( 'uninstall_info' )
->p_( 'This page will remove all the plugin tables and settings from the database and then deactivate the plugin.' );
$form->checkbox( 'sure' )
->label_( "Yes, I'm sure I want to remove all the plugin tables and settings." )
->required();
$form->primary_button( 'uninstall' )
->value_( "Uninstall plugin" );
if ( $form->is_posting() )
{
$form->post();
if ( $form->input( 'uninstall' )->pressed() )
{
if ( $form->input( 'sure' )->get_post_value() != 'on' )
$this->error_( 'You have to check the checkbox in order to uninstall the plugin.' );
else
{
$this->uninstall_internal();
$this->deactivate_me();
if( is_network_admin() )
$url ='ms-admin.php';
else
$url ='index.php';
$this->message_( 'The plugin and all associated settings and database tables have been removed. Please %sfollow this link to complete the uninstallation procedure%s.',
sprintf( '', $url, $this->_( 'This link will take you to the index page' ) ),
'' );
return;
}
}
}
$r .= $form->open_tag();
$r .= $form->display_form_table();
$r .= $form->close_tag();
echo $r;
}
/**
@brief Overridable deactivation function.
@see deactivate_internal()
@since 20130416
**/
public function deactivate()
{
}
/**
@brief Internal function that runs when deactivating the plugin.
@since 20130416
**/
public function deactivate_internal()
{
$this->deactivate();
}
/**
@brief Deactivates the plugin.
@since 20130416
**/
public function deactivate_me()
{
deactivate_plugins( [
$this->paths( 'filename_from_plugin_directory' )
] );
}
/**
@brief Display a warning about the function being deprecated.
@since 2015-12-25 13:29:48
**/
public function deprecated_function( $message )
{
if ( ! defined( 'WP_DEBUG' ) )
return;
if ( ! WP_DEBUG )
return;
$args = func_get_args();
$s = @ call_user_func_array( 'sprintf', $args );
if ( $s == '' )
$s = $message;
$backtrace = debug_backtrace();
array_shift( $backtrace );
$caller = reset( $backtrace );
echo sprintf( 'Deprecated in %s, function %s, line %s: %s', $caller[ 'class' ], $caller[ 'function' ], $caller[ 'line' ], $s );
}
/**
@brief Loads this plugin's language files.
Reads the language data from the class's name domain as default.
@param $domain
Optional domain.
@since 20130416
**/
public function load_language( $domain = '' )
{
if ( $domain != '' )
$this->language_domain = $domain;
if ( $this->language_domain == '' )
$this->language_domain = str_replace( '.php', '', $this->paths( 'filename' ) );
// This will allow other plugins to load a custom language file.
// The filter name will be similar to: ThreeWP_Broadcast_language_directory
$filter_name = $this->language_domain . '_language_directory';
$language_directory = $this->paths ( 'path_from_plugin_directory' ) . '/lang';
$language_directory = $this->filters( $filter_name, $language_directory );
load_plugin_textdomain( $this->language_domain, false, $language_directory );
}
/**
@brief Translate a string, if possible.
Like Wordpress' internal _() method except this one automatically uses the plugin's domain.
Can function like sprintf, if any %s are specified.
@param string $string String to translate. %s will require extra arguments to the method.
@since 20130416
@return string Translated string, or the untranslated string.
**/
public function _( $string )
{
$translated = __( $string, $this->language_domain );
$args = func_get_args();
// Remove the original string from the args.
array_shift( $args );
// Replace the original with the translated.
array_unshift( $args, $translated );
// Run it through sprintf.
$string = @ call_user_func_array( 'sprintf', $args );
// Did sprintf fail? Then return the translated.
if ( $string == '' )
$string = $translated;
else
$translated = $string;
return $translated;
}
/**
@brief Internal function to handle uninstallation (database removal) of module.
@since 20130416
**/
public function uninstall_internal()
{
$this->deregister_options();
$this->uninstall();
}
/**
@brief Overridable uninstall method.
@since 20130416
**/
public function uninstall()
{
}
// -------------------------------------------------------------------------------------------------
// ----------------------------------------- USER
// -------------------------------------------------------------------------------------------------
/**
@brief Return the user's capabilities on this blog as an array.
@since 2015-03-17 18:56:30
**/
public static function get_user_capabilities()
{
global $wpdb;
$key = sprintf( '%scapabilities', $wpdb->prefix );
$r = get_user_meta( get_current_user_id(), $key, true );
if ( ! is_array( $r ) )
$r = [];
if ( is_super_admin() )
$r[ 'super_admin' ] = true;
return $r;
}
/**
@brief Returns the user's role as a string.
@return User's role as a string.
@since 20130416
**/
public function get_user_role()
{
if ( function_exists( 'is_super_admin' ) && is_super_admin() )
return 'super_admin';
global $current_user;
wp_get_current_user();
if ( ! $current_user )
return false;
// We want the roles
$roles = $this->roles_as_values();
// Get the user's most powerful role.
$max = 0;
foreach( $current_user->roles as $role )
if ( isset( $roles[ $role ] ) )
$max = max( $max, $roles[ $role ] );
$roles = array_flip( $roles );
return $roles[ $max ];
}
/**
@brief Return an array containing role => value.
@since 2014-04-13 13:08:29
**/
public function roles_as_values()
{
$roles = $this->roles_as_options();
// And we want them numbered with the weakest at the top.
$roles = array_reverse( $roles );
$roles = array_keys( $roles );
// And the key should be the name of the role
$roles = array_flip( $roles );
return $roles;
}
/**
@brief Returns the user roles as a select options array.
@return The user roles as a select options array.
@since 20130416
**/
public function roles_as_options()
{
global $wp_roles;
$roles = $wp_roles->get_names();
if ( function_exists( 'is_super_admin' ) )
$roles = array_merge( [ 'super_admin' => $this->_( 'Super admin' ) ], $roles );
return $roles;
}
/**
@brief Checks whether the user's role is at least $role.
@param $role Role as string.
@return True if role is at least $role.
@since 20130416
**/
public function role_at_least( $role )
{
$user_role = $this->get_user_role();
if ( ! $user_role )
return false;
// No role? Then assume the user is capable of whatever that is.
if ( $role == '' )
return true;
if ( function_exists( 'is_super_admin' ) && is_super_admin() )
return true;
if ( $role == 'super_admin' )
return false;
$roles = $this->roles_as_values();
$role_value = $roles[ $role ];
// User role is
$user_role = $this->get_user_role();
$user_role_value = $roles[ $user_role ];
return $user_role_value >= $role_value;
}
/**
@brief Does the user have any of these roles?
@since 2015-03-17 18:57:33
**/
public static function user_has_roles( $roles )
{
if ( is_super_admin() )
return true;
if ( ! is_array( $roles ) )
$roles = [ $roles ];
$user_roles = static::get_user_capabilities();
$user_roles = array_keys ( $user_roles );
$intersect = array_intersect( $user_roles, $roles );
return count( $intersect ) > 0;
}
/**
@brief Return the user_id of the current user.
@return int The user's ID.
@since 20130416
**/
public function user_id()
{
return get_current_user_id();
}
// -------------------------------------------------------------------------------------------------
// ----------------------------------------- MESSAGES
// -------------------------------------------------------------------------------------------------
/**
@brief Displays a message.
Autodetects HTML / text.
@param $type
Type of message: error, warning, whatever. Free content.
@param $string
The message to display.
@since 20130416
**/
public function display_message( $type, $string )
{
// If this string has html codes, then output it as it.
$stripped = strip_tags( $string );
if ( strlen( $stripped ) == strlen( $string ) )
{
$string = explode("\n", $string);
$string = implode( '
', $string);
}
echo '
'.$this->now().'
'.$string.'
';
}
/**
@brief Return a message box of type 'info'.
@since 2015-12-21 20:26:14
**/
public function error_message_box()
{
return new message_boxes\Error( $this );
}
/**
@brief Return a message box of type 'info'.
@since 2015-12-21 20:26:14
**/
public function info_message_box()
{
return new message_boxes\Info( $this );
}
/**
@brief Displays an informational message.
@param string $string String to create into a message.
@since 20130416
**/
public function message( $string )
{
$this->display_message( 'updated pv_message', $string );
}
/**
@brief Convenience function to translate and then create a message from a string and optional sprintf arguments.
@param string $string String to translate and create into a message.
@param string $args One or more arguments.
@return A translated message.
@since 20130416
**/
public function message_( $string, $args = '' )
{
$args = func_get_args();
$string = call_user_func_array( array( &$this, '_' ), $args );
return $this->message( $string );
}
/**
@brief Displays an error message.
@details The only thing that makes it an error message is that the div has the class "error".
@param string $string String to create into a message.
@since 20130416
**/
public function error( $string )
{
$this->display_message( 'error', $string );
}
/**
@brief Convenience function to translate and then create an error message from a string and optional sprintf arguments.
@param string $string String to translate and create into a message.
@param string $args One or more arguments.
@return A translated error message.
@since 20130416
**/
public function error_( $string, $args = null )
{
$args = func_get_args();
$string = call_user_func_array( array( &$this, '_' ), $args );
return $this->error( $string );
}
// -------------------------------------------------------------------------------------------------
// ----------------------------------------- OPTIONS
// -------------------------------------------------------------------------------------------------
/**
Deletes a site option.
If this is a network, the site option is preferred.
@param $option Name of option to delete.
@since 20130416
**/
public function delete_option( $option )
{
if ( $this->is_network )
$this->delete_site_option( $option );
else
$this->delete_local_option( $option );
}
/**
Deletes a local option.
@param $option Name of option to delete.
@since 20130416
**/
public function delete_local_option( $option )
{
$option = $this->fix_local_option_name( $option );
delete_option( $option );
}
/**
Deletes a site option.
@param $option Name of option to delete.
@since 20130416
**/
public function delete_site_option( $option )
{
$option = $this->fix_site_option_name( $option );
delete_site_option( $option );
}
/**
@brief Removes all the options this plugin uses.
@since 20130416
**/
public function deregister_options()
{
if ( isset( $this->options ) )
foreach( $this->options as $option=>$value )
$this->delete_option( $option );
foreach( $this->local_options() as $option=>$value )
{
$option = $this->fix_local_option_name( $option );
delete_option( $option );
}
if ( $this->is_network )
foreach( $this->site_options() as $option=>$value )
{
$option = $this->fix_site_option_name( $option );
delete_site_option( $option );
}
else
{
foreach( $this->site_options() as $option=>$value )
{
$option = $this->fix_local_option_name( $option );
delete_option( $option, $value );
}
}
}
/**
@brief Gets the proper option name for a local option.
@details Does a 64 char length check and outputs an error in WP_DEBUG mode.
@since 20131211
**/
public function fix_local_option_name( $option )
{
$max = 64;
$name = $this->get_local_option_prefix() . '_' . $option;
if ( defined( 'WP_DEBUG' ) && strlen( $name ) > $max )
{
$text = sprintf( '%s%s',
substr( $name, 0, $max ),
substr( $name, $max )
);
echo "Option $name is longer than $max characters.\n
";
}
return $name;
}
/**
Normalizes the name of an option.
Will prepend the class name in front, to make the options easily findable in the table.
@param $option Option name to fix.
@since 20130416
**/
public function fix_option_name( $option )
{
if ( $this->is_network )
$name = $this->get_site_option_prefix() . '_' . $option;
else
$name = $this->get_local_option_prefix() . '_' . $option;
return $name;
}
/**
@brief Gets the proper option name for a site option.
@details Does a 255 char length check and outputs an error in WP_DEBUG mode.
@since 20131211
**/
public function fix_site_option_name( $option )
{
if ( ! $this->is_network )
return $this->fix_local_option_name( $option );
else
$name = $this->get_site_option_prefix() . '_' . $option;
$max = 255;
if ( defined( 'WP_DEBUG' ) && strlen( $name ) > $max )
{
$text = sprintf( '%s%s',
substr( $text, 0, $max ),
substr( $text, $max )
);
echo "Option $text is longer than $max characters.\n
";
}
return $name;
}
/**
@brief Returns the prefix for local options.
@since 20131211
**/
public function get_local_option_prefix()
{
return preg_replace( '/.*\\\\/', '', $this->paths( 'name' ) );
}
/**
@brief Returns the options prefix.
@details
Override this is you find that your options are a bit too long.
@since 20130416
**/
public function get_option_prefix()
{
return $this->paths( 'name' );
}
/**
@brief Returns the prefix for site options.
@since 20131211
**/
public function get_site_option_prefix()
{
return $this->get_option_prefix();
}
/**
Get a site option.
If this is a network, the site option is preferred.
@param $option Name of option to get.
@return Value.
@since 20130416
**/
public function get_option( $option, $default = 'no_default_value' )
{
if ( $this->is_network )
return $this->get_site_option( $option, $default );
else
return $this->get_local_option( $option, $default );
}
/**
Gets the value of a local option.
@param $option Name of option to get.
@param $default The default value if the option === false
@return Value.
@since 20130416
**/
public function get_local_option( $option, $default = 'no_default_value' )
{
$fixed_option = $this->fix_local_option_name( $option );
$value = get_option( $fixed_option, 'no_default_value' );
if ( $value === 'no_default_value' )
{
$options = $this->local_options();
if ( isset( $options[ $option ] ) )
$default = $options[ $option ];
else
$default = false;
return $default;
}
else
return $value;
}
/**
Gets the value of a site option.
@param $option Name of option to get.
@param $default The default value if the option === false
@return Value.
@since 20130416
**/
public function get_site_option( $option, $default = 'no_default_value' )
{
$fixed_option = $this->fix_site_option_name( $option );
$value = get_site_option( $fixed_option, 'no_default_value' );
// No value returned?
if ( $value === 'no_default_value' )
{
// Return the default from the options array.
$options = $this->site_options();
if ( isset( $options[ $option ] ) )
$default = $options[ $option ];
else
$default = false;
return $default;
}
else
return $value;
}
/**
@brief Return an array of the local options.
@since 2014-05-10 08:46:20
**/
public function local_options()
{
return [];
}
/**
Registers all the options this plugin uses.
@since 20130416
**/
public function register_options()
{
foreach( $this->local_options() as $option=>$value )
{
$option = $this->fix_local_option_name( $option );
if ( get_option( $option ) === false )
update_option( $option, $value );
}
if ( $this->is_network )
{
foreach( $this->site_options() as $option=>$value )
{
$option = $this->fix_site_option_name( $option );
if ( get_site_option( $option ) === false )
update_site_option( $option, $value );
}
}
else
{
foreach( $this->site_options() as $option=>$value )
{
$option = $this->fix_local_option_name( $option );
if ( get_option( $option ) === false)
update_option( $option, $value );
}
}
}
/**
@brief Return an array of the site options.
@since 2014-05-10 08:46:20
**/
public function site_options()
{
return [];
}
/**
Updates a site option.
If this is a network, the site option is preferred.
@param $option Name of option to update.
@param $value New value
@since 20130416
**/
public function update_option( $option, $value )
{
if ( $this->is_network )
$this->update_site_option( $option, $value );
else
$this->update_local_option( $option, $value );
}
/**
Updates a local option.
@param option Name of option to update.
@param $value New value
@since 20130416
**/
public function update_local_option( $option, $value )
{
$option = $this->fix_local_option_name( $option );
update_option( $option, $value );
}
/**
Updates a site option.
@param $option Name of option to update.
@param $value New value
@since 20130416
**/
public function update_site_option( $option, $value )
{
$option = $this->fix_site_option_name( $option );
update_site_option( $option, $value );
}
// -------------------------------------------------------------------------------------------------
// ----------------------------------------- SQL
// -------------------------------------------------------------------------------------------------
/**
Sends a query to wpdb and return the results.
@param $query The SQL query.
@param $wpdb An optional, other WPDB if the standard $wpdb isn't good enough for you.
@return array The rows from the query.
@since 20130416
**/
public function query( $query , $wpdb = null )
{
if ( $wpdb === null )
$wpdb = $this->wpdb;
$results = $wpdb->get_results( $query, 'ARRAY_A' );
return (is_array( $results) ? $results : array());
}
/**
Fire an SQL query and return the results only if there is one row result.
@param $query The SQL query.
@return Either the row as an array, or false if more than one row.
@since 20130416
**/
public function query_single( $query)
{
$results = $this->wpdb->get_results( $query, 'ARRAY_A' );
if ( count( $results) != 1)
return false;
return $results[0];
}
/**
Fire an SQL query and return the row ID of the inserted row.
@param $query The SQL query.
@return The inserted ID.
@since 20130416
**/
public function query_insert_id( $query)
{
$this->wpdb->query( $query);
return $this->wpdb->insert_id;
}
/**
Converts an object to a base64 encoded, serialized string, ready to be inserted into sql.
@param $object An object.
@return Serialized, base64-encoded string.
@since 20130416
**/
public function sql_encode( $object )
{
return base64_encode( serialize( $object) );
}
/**
Converts a base64 encoded, serialized string back into an object.
@param $string Serialized, base64-encoded string.
@return Object, if possible.
@since 20130416
**/
public function sql_decode( $string )
{
return unserialize( base64_decode( $string) );
}
/**
Returns whether a table exists.
@param $table_name Table name to check for.
@return True if the table exists.
@since 20130416
**/
public function sql_table_exists( $table_name )
{
$query = "SHOW TABLES LIKE '$table_name'";
$result = $this->query( $query );
return count( $result) > 0;
}
// -------------------------------------------------------------------------------------------------
// ----------------------------------------- TOOLS
// -------------------------------------------------------------------------------------------------
/**
@brief Convenience function to add a Wordpress action.
@details Using almost the same parameters as add_action(), this method can be used if the action has the same base method name as the callback.
If that is the case, then $callback can be skipped. Priority and parameters can also be skipped if you are using the same default values as Wordpress' add_action().
Example:
@code
$this->add_action( 'plainview_enter_castle', 'action_plainview_enter_castle', 10, 1 ); // All parameters specified
$this->add_action( 'plainview_enter_castle', 'action_plainview_enter_castle' ); // Priority and parameter count skipped (using Wordpress defaults)
$this->add_action( 'plainview_enter_castle', 10, 1 ); // Calls $base->plainview_enter_castle
$this->add_action( 'plainview_enter_castle' ); // Calls $base->plainview_enter_castle
$this->add_action( 'plainview_enter_castle', null, 3 ); // Uses Wordpress default priority and three parameters.
@endcode
@param string $action The name of the action to create.
@param mixed $callback Either the callback, or the priority, or nothing.
@param mixed $priority If $callback is specified, then this is the priority. Else this is the amount of parameters.
@param mixed $parameters Used only if callback and priority are specified.
@since 20130505
**/
public function add_action( $action, $callback = null, $priority = null, $parameters = null )
{
$args = array_merge( array( 'action' ), func_get_args() );
return call_user_func_array( array( $this, 'add_thing' ), $args );
}
/**
@brief Convenience function to add a Wordpress filter.
@details Using almost the same parameters as add_filter(), this method can be used if the filter has the same base method name as the callback.
If that is the case, then $callback can be skipped. Priority and parameters can also be skipped if you are using the same default values as Wordpress' add_filter().
Example:
@code
$this->add_filter( 'plainview_enter_castle', 'filter_plainview_enter_castle', 10, 1 ); // All parameters specified
$this->add_filter( 'plainview_enter_castle', 'filter_plainview_enter_castle' ); // Priority and parameter count skipped (using Wordpress defaults)
$this->add_filter( 'plainview_enter_castle', 10, 1 ); // Calls $base->plainview_enter_castle
$this->add_filter( 'plainview_enter_castle' ); // Calls $base->plainview_enter_castle
$this->add_filter( 'plainview_enter_castle', null, 3 ); // Uses Wordpress default priority and three parameters.
@endcode
@param string $filter The name of the filter to create.
@param mixed $callback Either the callback, or the priority, or nothing.
@param mixed $priority If $callback is specified, then this is the priority. Else this is the amount of parameters.
@param mixed $parameters Used only if callback and priority are specified.
@since 20130505
**/
public function add_filter( $filter, $callback = null, $priority = null, $parameters = null )
{
$args = array_merge( array( 'filter' ), func_get_args() );
return call_user_func_array( array( $this, 'add_thing' ), $args );
}
/**
@brief Convenience method to add a shortwith with the same method name as the shortcode.
@param string $shortcode Name of the shortcode, which should be the same name as the method to be called in the base.
@param string $callback An optional callback method. If null the callback is assumed to have the same name as the shortcode itself.
@since 20130505
**/
public function add_shortcode( $shortcode, $callback = null )
{
if ( $callback === null )
$callback = $shortcode;
return add_shortcode( $shortcode, array( $this, $callback ) );
}
/**
@brief Adds a Wordpress action or filter.
@see add_action
@see add_filter
@since 20130505
**/
public function add_thing()
{
$args = func_get_args();
// The add type is the first argument
$type = 'add_' . array_shift( $args );
$thing = $args[ 0 ];
// If the callback is not specified, then assume the same callback as the thing.
if ( ! isset( $args[ 1 ] ) )
$args[ 1 ] = $args[ 0 ];
// Is the callback anything but a string? That means parameter 1 is the priority.
if ( ! is_string( $args[ 1 ] ) )
array_splice( $args, 1, 0, $thing );
// * ... which is then turned into a self callback.
if ( ! is_array( $args[ 1 ] ) )
$args[ 1 ] = array( $this, $args[ 1 ] );
// No parameter count set? Unset it to allow add_* to use the default Wordpress value.
if ( isset( $args[ 3 ] ) && $args[ 3 ] === null )
unset( $args[ 3 ] );
// Is the priority set to null? Then use the Wordpress default.
if ( isset( $args[ 2 ] ) && $args[ 2 ] === null )
$args[ 2 ] = 10;
return call_user_func_array( $type, $args );
}
/**
@brief Display the time ago as human-readable string.
@param $time_string "2010-04-12 15:19"
@param $time An optional timestamp to base time difference on, if not now.
@return "28 minutes ago"
@since 20130416
**/
public static function ago( $time_string, $time = null)
{
if ( $time_string == '' )
return '';
if ( $time === null )
$time = current_time( 'timestamp' );
$diff = human_time_diff( strtotime( $time_string), $time );
return '' . sprintf( __( '%s ago' ), $diff) . '';
}
/**
@brief Return an xgettext command line that will generate all strings necessary for translation.
@details Will collect keywords from the SDK and the subclass.
@return string xgettext command line suggestion.
@see pot_files()
@see pot_keyswords()
@since 20130505
**/
public function cli_pot()
{
$basedir = dirname( $this->paths( '__FILE__' ) ) . '/';
$files = array_merge( array(
basename( $this->paths( '__FILE__' ) ), // subclass.php
str_replace( $basedir, '', dirname( dirname( __FILE__ ) ) . '/*php' ), // plainview/*php
str_replace( $basedir, '', dirname( dirname( __FILE__ ) ) . '/form2/inputs/*php' ),
str_replace( $basedir, '', dirname( dirname( __FILE__ ) ) . '/form2/inputs/traits/*php' ),
str_replace( $basedir, '', dirname( __FILE__ ) . '/*php' ), // plainview_sdk/wordpress/*.php
), $this->pot_files() );
$filename = preg_replace( '/\.php/', '.pot', $this->paths( '__FILE__' ) );
$keywords = array_merge( array(
'_',
'error_',
'description_', // form2
'message_',
'heading_', // tabs
'label_', // form2
'name_', // tabs
'option_', // form2
'p_',
'text_', // table
'value_', // form2
), $this->pot_keywords() );
$pot = dirname( $filename ) . '/lang/' . basename( $filename );
$command = sprintf( 'xgettext -s -c --no-wrap -d %s -p lang -o "%s" --omit-header%s %s',
get_class( $this ),
$pot,
$this->implode_html( $keywords, ' -k', '' ),
implode( ' ', $files )
);
echo $command;
echo "\n";
}
/**
@brief Handles command line arguments.
@details Using an array of long options, will call the respective method to handle the option.
For example: `php Inherited_Class.php --pot` will call do_pot().
@see long_options
@since 20130505
**/
public function do_cli()
{
$long_options = array_merge( [ 'pot' ], $this->long_options() );
$options = (object) getopt( '', $long_options );
foreach( $options as $option => $value )
{
$f = 'cli_' . $option;
$this->$f( $options );
}
die();
}
/**
@brief Output a file to the browser for downloading.
@param string $file Path to file on disk.
@param string $name Downloaded file's name.
@param string $mime_type Optional mime_type.
@author http://w-shadow.com/blog/2007/08/12/how-to-force-file-download-with-php/
@since 20130416
@todo Have another look at this some time...
**/
public function download( $filepath, $options = array() )
{
if ( ! is_readable( $filepath ) )
throw new \Exception( "The file $filepath could not be read!" );
$o = (object) array_merge( array(
'cache' => true,
'content_disposition' => 'attachment',
'content_type' => '',
'etag' => true,
'expires' => 3600 * 24 * 7, // one week
'filemtime' => filemtime( $filepath ),
'filename' => '',
'filesize' => filesize( $filepath ),
'md5_file' => true,
), $options );
// 304 support
if ( $o->cache && isset( $_SERVER[ 'HTTP_IF_MODIFIED_SINCE' ] ) )
{
$since = $_SERVER[ 'HTTP_IF_MODIFIED_SINCE' ];
$since = strtotime( $since );
if ( $since >= $o->filemtime )
{
header( 'HTTP/1.1 304 Not Modified' );
return;
}
}
if ( $o->filename == '' )
$o->filename = basename( $filepath );
$headers = array(
'Accept-Ranges: bytes',
'Content-Disposition: ' . $o->content_disposition . '; filename="' . $o->filename . '"',
'Content-Transfer-Encoding: binary',
'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', $o->filemtime ) . ' GMT',
);
if ( $o->content_type == '' )
{
$mime_types = array
(
'doc' => 'application/msword',
'exe' => 'application/octet-stream',
'gif' => 'image/gif',
'htm' => 'text/html',
'html' => 'text/html',
'jpeg'=> 'image/jpg',
'jpg' => 'image/jpg',
'pdf' => 'application/pdf',
'php' => 'text/plain',
'ppt' => 'application/vnd.ms-powerpoint',
'png' => 'image/png',
'txt' => 'text/plain',
'xls' => 'application/vnd.ms-excel',
'zip' => 'application/zip',
);
$file_extension = strtolower( substr( strrchr( $o->filename, '.' ), 1 ) );
if ( isset( $mime_types[ $file_extension ] ) )
$o->content_type = $mime_types[ $file_extension ];
else
$o->content_type = 'application/octet-stream';
}
$headers[] = 'Content-Type: ' . $o->content_type;
if ( $o->cache === false )
{
$headers[] = 'Cache-Control: no-cache, no-store';
$headers[] = 'Pragma: private';
$headers[] = 'Expires: Mon, 26 Jul 1995 00:00:00 GMT';
}
else
{
$expires = $o->filemtime + $o->expires;
$headers[] = 'Expires: ' . gmdate( 'D, d M Y H:i:s', $expires ) . ' GMT';
$headers[] = 'Cache-Control: max-age=' . $o->expires;
}
if ( $o->etag !== false )
{
$etag = ( $o->etag !== true ? $o->etag : md5( filesize( $o->filepath ) . filemtime( $o->filepath ) ) );
$headers[] = 'ETag: ' . $etag;
}
if ( $o->md5_file == true )
$headers[] = 'Content-MD5: ' . base64_encode( md5_file( $filepath ) );
// Resume support.
/**
if ( isset( $_SERVER['HTTP_RANGE']) )
{
if ( ! function_exists( 'download_416' ) )
function download_416( $filesize )
{
header( 'HTTP/1.1 416 Requested Range Not Satisfiable' );
header( 'Content-Range: bytes *\/' . $o->filesize); // Required in 416. *\/ *\/ *\/
}
if (!preg_match( '^bytes=\d*-\d*(,\d*-\d*)*$', $_SERVER['HTTP_RANGE'])) {
{
download_416( $o->filesize );
return;
}
$ranges = explode( ',', substr( $_SERVER['HTTP_RANGE'], 6) );
foreach ( $ranges as $range )
{
$parts = explode( '-', $range);
$start = $parts[0]; // If this is empty, this should be 0.
$end = $parts[1]; // If this is empty or greater than than filelength - 1, this should be filelength - 1.
if ( $start > $end)
{
download_416( $o->filesize );
return;
}
}
}
else
**/
{
$size_to_send = $o->filesize;
}
$headers[] = 'Content-Length: ' . $size_to_send;
foreach( $headers as $header )
header( $header );
$chunksize = 65536;
$bytes_sent = 0;
$file = fopen( $filepath, 'r' );
if ( ! $file )
throw new \Exception( "File $filepath could not be opened for reading!" );
/*
if ( isset( $_SERVER['HTTP_RANGE'] ) )
fseek( $file, $range );
**/
while ( ! feof( $file ) && ( ! connection_aborted() ) && ( $bytes_sent < $size_to_send ) )
{
$buffer = fread( $file, $chunksize );
echo ( $buffer );
flush();
$bytes_sent += strlen( $buffer );
}
fclose( $file );
}
/**
@brief Convenience function to call apply_filters.
@details Has same parameters as apply filters. Will insert a null if there are no arguments.
@since 20130416
**/
public static function filters()
{
$args = func_get_args();
if ( count( $args ) < 2 )
$args[] = null;
return call_user_func_array( 'apply_filters', $args );
}
/**
@brief Creates a form2 object.
@see form2
@since 20130416
**/
public function form()
{
$form = new \plainview\sdk_eightb_sold_alerts\wordpress\form2\form( $this );
return $form;
}
/**
@brief Backwards compatibility alias for form.
@return \\plainview\\sdk_eightb_sold_alerts\\form2\\form A new form object.
@since 20130509
**/
public function form2()
{
return $this->form();
}
/**
@brief Return the blog's time offset from GMT.
@since 2014-07-08 10:07:30
**/
public function gmt_offset()
{
$blog_timestamp = current_time( 'timestamp' );
return $blog_timestamp - time();
}
/**
@brief An array of command line options that this subclass can handle via do_LONGOPTION().
@return array Array of long options that this subclass handles.
@see do_cli()
@since 20130505
**/
public function long_options()
{
return array();
}
/**
@brief Load the PHPmailer object, if necessary.
@since 2016-02-01 20:11:34
**/
public static function mail()
{
// This ensures that the PHPmailer class is loaded and ready.
try
{
require_once( ABSPATH . WPINC . '/pluggable.php' );
wp_mail( '' , '', '' );
}
catch ( \phpmailerException $e )
{
}
return parent::mail();
}
/**
@brief Return the menu_page object.
@since 2015-12-26 19:04:58
**/
public function menu_page()
{
if ( ! isset( $this->__menu_page ) )
{
$this->__menu_page = new menu_page\Menu();
$this->__menu_page->set_parent( $this );
}
return $this->__menu_page;
}
/**
@brief Create a nav tabs instance.
@since 2015-12-28 00:05:11
**/
public function nav_tabs()
{
$tabs = new \plainview\sdk_eightb_sold_alerts\wordpress\tabs\Nav_Tabs( $this );
return $tabs;
}
/**
@brief Returns WP's current timestamp (corrected for UTC)
@return string Current timestamp in MYSQL datetime format.
@since 20130416
**/
public static function now()
{
return date( 'Y-m-d H:i:s', current_time( 'timestamp' ) );
}
/**
@brief wpautop's a string, using sprintf to replace arguments.
@param string $string String to wpautop.
@param mixed $args Optional arguments to sprintf.
@return The wpautop'd sprintf string.
@since 20130416
**/
public function p( $string, $args = '' )
{
$args = func_get_args();
$s2 = @ call_user_func_array( 'sprintf', $args );
if ( $s2 == '' )
$s2 = $string;
return wpautop( $s2 );
}
/**
@brief Translate and wpautop a string, using sprintf to replace arguments.
@param string $string String to translate and then wpautop.
@param mixed $args Optional arguments to sprintf.
@return The translated, wpautop'd string.
@since 20130416
**/
public function p_( $string, $args = '' )
{
$args = func_get_args();
return wpautop( call_user_func_array( array( &$this, '_' ), $args ) );
}
/**
@brief Return the paths, or a path, as an object.
@since 2014-09-28 00:16:17
**/
public function paths( $key = null )
{
$paths = (object)$this->paths;
if ( $key === null )
return $paths;
return $paths->$key;
}
/**
@brief Return a list of files that are to be included when creating the .pot file.
@return array List of files (including wildcards) that must be including when preparing the .pot file.
@since 20130505
**/
public function pot_files()
{
return array();
}
/**
@brief Return a list of translation keywords used when creating the .pot file.
@return array Array of translation keywords to use when creating the .pot file.
@since 20130505
**/
public function pot_keywords()
{
return array();
}
/**
@brief Create a row actions object.
@since 2015-12-21 23:24:18
**/
public function row_actions()
{
return new row_actions\Row( $this );
}
/**
@brief Sanitizes (slugs) a string.
@param string $string String to sanitize.
@return string Sanitized string.
@since 20130416
**/
public static function slug( $string )
{
return sanitize_title( $string );
}
/**
@brief Create a subsubsub tabs instance.
@since 2015-12-28 00:05:11
**/
public function subsubsub_tabs()
{
$tabs = new \plainview\sdk_eightb_sold_alerts\wordpress\tabs\Subsubsub_Tabs( $this );
return $tabs;
}
/**
@brief Sanitizes the name of a tab.
@param string $string String to sanitize.
@return string Sanitized string.
@since 20130416
**/
public static function tab_slug( $string )
{
return self::slug( $string );
}
/**
@brief Creates a new table.
@return object A new \\plainview\\sdk_eightb_sold_alerts\\wordpress\\table object.
@since 20130416
**/
public function table()
{
$table = new \plainview\sdk_eightb_sold_alerts\wordpress\table\table( $this );
$table->css_class( 'widefat' );
return $table;
}
/**
@brief Create a tabs instance.
@since 20130416
**/
public function tabs()
{
return $this->nav_tabs();
}
/**
@brief Returns the current time(), corrected for UTC and DST.
@return int Current, corrected timestamp.
@since 20130416
**/
public static function time()
{
return current_time( 'timestamp' );
}
/**
@brief Displays a time difference as a human-readable string.
@param $current "2010-04-12 15:19" or a UNIX timestamp.
@param $reference An optional timestamp to base time difference on, if not now.
@param $wrap Wrap the real time in a span with a title?
@return "28 minutes"
@since 20130810
**/
public static function time_to_string( $current, $reference = null, $wrap = false )
{
if ( $current == '' )
return '';
if ( ! is_int( $current ) )
$current = strtotime( $current );
if ( $reference === null )
$reference = current_time( 'timestamp' );
$diff = human_time_diff( $current, $reference );
if ( $wrap )
$diff = '' . $diff . '';
return $diff;
}
/**
@brief Dies after sprinting the arguments.
@since 2014-04-18 09:16:12
**/
public function wp_die( $message )
{
$args = func_get_args();
$text = call_user_func_array( 'sprintf', $args );
if ( $text == '' )
$text = $message;
wp_die( $text );
}
/**
@brief Outputs the text in Wordpress admin's panel format.
@details To remember the correct parameter order: wrap THIS in THIS.
@param string $title H2 title to display.
@param string $text Text to display.
@return HTML wrapped HTML.
@since 20130416
**/
public static function wrap( $text, $title )
{
echo "$title
$text
";
}
/**
@brief Return a yes or no string.
@param bool $bool Boolean value to convert to a word.
@return string "Yes" is $bool is true. "No" if false.
@since 20130605
**/
public function yes_no( $bool )
{
return $bool ? $this->_( 'yes' ) : $this->_( 'no' );
}
}