If I do this I get many properties shown, including display_name, but the first and last names are NOT shown
$user = get_userdata( 4 );
print_r( $user );
However they clearly exist because if I immediately afterwards do this, I am shown the proper last name. The Wordpress docs also mention last_name as being a property.
echo $user->last_name;
So why doesn't print_r show all of the properties? This casts a lot of doubt on being able to use print_r to discover information.
last_name is not a real property of WP_User, but it's made available via magic methods for backwards compatibility.
It's listed as a public property in the docs, but this is a little misleading. More accurately, you can access it as a public property. But when you look at the code, it's being retrieved and set using magic methods.
Proof from the Code
Here's an excerpt of the most relevant code, showing how Wordpress actually keeps a list of several of these backward-compatibility properties, including last_name, in a private, static property called back_compat_keys. When the user requests one of these properties, the magic method __get is called. The magic method uses get_user_meta() to actually retrieve the data for that property. In other words, the data isn't actually stored in the WP_User object; Wordpress just lets you pretend that it is, and it only fetches it when explicitly requested. Here's the code:
<?php
class WP_User {
// ...
/**
* #static
* #since 3.3.0
* #access private
* #var array
*/
private static $back_compat_keys;
public function __construct( $id = 0, $name = '', $blog_id = '' ) {
if ( ! isset( self::$back_compat_keys ) ) {
$prefix = $GLOBALS['wpdb']->prefix;
self::$back_compat_keys = array(
'user_firstname' => 'first_name',
'user_lastname' => 'last_name',
'user_description' => 'description',
'user_level' => $prefix . 'user_level',
$prefix . 'usersettings' => $prefix . 'user-settings',
$prefix . 'usersettingstime' => $prefix . 'user-settings-time',
);
}
// ...
}
// ...
/**
* Magic method for accessing custom fields.
*
* #since 3.3.0
* #access public
*
* #param string $key User meta key to retrieve.
* #return mixed Value of the given user meta key (if set). If `$key` is 'id', the user ID.
*/
public function __get( $key ) {
// ...
if ( isset( $this->data->$key ) ) {
$value = $this->data->$key;
} else {
if ( isset( self::$back_compat_keys[ $key ] ) )
$key = self::$back_compat_keys[ $key ];
$value = get_user_meta( $this->ID, $key, true );
}
// ...
return $value;
}
/**
* Magic method for setting custom user fields.
*
* This method does not update custom fields in the database. It only stores
* the value on the WP_User instance.
*
* #since 3.3.0
* #access public
*
* #param string $key User meta key.
* #param mixed $value User meta value.
*/
public function __set( $key, $value ) {
if ( 'id' == $key ) {
_deprecated_argument( 'WP_User->id', '2.1.0',
sprintf(
/* translators: %s: WP_User->ID */
__( 'Use %s instead.' ),
'<code>WP_User->ID</code>'
)
);
$this->ID = $value;
return;
}
$this->data->$key = $value;
}
/**
* Magic method for unsetting a certain custom field.
*
* #since 4.4.0
* #access public
*
* #param string $key User meta key to unset.
*/
public function __unset( $key ) {
// ...
if ( isset( $this->data->$key ) ) {
unset( $this->data->$key );
}
if ( isset( self::$back_compat_keys[ $key ] ) ) {
unset( self::$back_compat_keys[ $key ] );
}
}
// ...
}
Related
I'm using this class to use wordpress like hooks and filters in my user management system, I use a autoload class to load all my classes, however it won't recognise this class unless its static, how can i make this class static ?
<?php
class Hooks
{
/**
* $filters holds list of hooks
* #access public
* #since 0.1
* #var array
*/
protected static $filters = [];
/**
* $merged_filters
* #var array
*/
protected static $merged_filters = [];
/**
* $actions
* #var array
*/
protected static $actions = [];
/**
* $current_filter holds the name of the current filter
* #access public
* #since 0.1
* #var array
*/
protected static $current_filter = [];
// Disable object instantiation
private function __construct() {}
/**
* gets instance of this class
* #access public
* #since 0.1
public static function getInstance()
{
if (self::$_instance === null) {
self::$_instance = new Hooks();
}
return self::$_instance;
}
*/
/**
* FILTERS
*/
/**
* add_filter Hooks a function or method to a specific filter action.
* #access public
* #since 0.1
* #param string $tag The name of the filter to hook the $function_to_add to.
* #param callback $function_to_add The name of the function to be called when the filter is applied.
* #param int $priority optional. Used to specify the order in which the functions associated with a particular action are executed (default: 10). Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action.
* #param int $accepted_args optional. The number of arguments the function accept (default 1).
* #return boolean true
*/
public static function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
$idx = self::_filter_build_unique_id($tag, $function_to_add, $priority);
self::$filters[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args);
unset( self::$merged_filters[ $tag ] );
return true;
}
/**
* remove_filter Removes a function from a specified filter hook.
* #access public
* #since 0.1
* #param string $tag The filter hook to which the function to be removed is hooked.
* #param callback $function_to_remove The name of the function which should be removed.
* #param int $priority optional. The priority of the function (default: 10).
* #param int $accepted_args optional. The number of arguments the function accepts (default: 1).
* #return boolean Whether the function existed before it was removed.
*/
public static function remove_filter( $tag, $function_to_remove, $priority = 10 ) {
$function_to_remove = self::_filter_build_unique_id($tag, $function_to_remove, $priority);
$r = isset(self::filters[$tag][$priority][$function_to_remove]);
if ( true === $r) {
unset(self::$filters[$tag][$priority][$function_to_remove]);
if ( empty(self::$filters[$tag][$priority]) )
unset(self::$filters[$tag][$priority]);
unset(self::$merged_filters[$tag]);
}
return $r;
}
/**
* remove_all_filters Remove all of the hooks from a filter.
* #access public
* #since 0.1
* #param string $tag The filter to remove hooks from.
* #param int $priority The priority number to remove.
* #return bool True when finished.
*/
public static function remove_all_filters($tag, $priority = false) {
if( isset(self::$filters[$tag]) ) {
if( false !== $priority && isset(self::$filters[$tag][$priority]) )
unset(self::$filters[$tag][$priority]);
else
unset(self::$filters[$tag]);
}
if( isset(self::$merged_filters[$tag]) )
unset(self::$merged_filters[$tag]);
return true;
}
/**
* has_filter Check if any filter has been registered for a hook.
* #access public
* #since 0.1
* #param string $tag The name of the filter hook.
* #param callback $function_to_check optional.
* #return mixed If $function_to_check is omitted, returns boolean for whether the hook has anything registered.
* When checking a specific function, the priority of that hook is returned, or false if the function is not attached.
* When using the $function_to_check argument, this function may return a non-boolean value that evaluates to false
* (e.g.) 0, so use the === operator for testing the return value.
*/
public static function has_filter($tag, $function_to_check = false) {
$has = !empty(self::$filters[$tag]);
if ( false === $function_to_check || false == $has )
return $has;
if ( !$idx = self::_filter_build_unique_id($tag, $function_to_check, false) )
return false;
foreach ( (array) array_keys(self::$filters[$tag]) as $priority ) {
if ( isset(self::$filters[$tag][$priority][$idx]) )
return $priority;
}
return false;
}
/**
* apply_filters Call the functions added to a filter hook.
* #access public
* #since 0.1
* #param string $tag The name of the filter hook.
* #param mixed $value The value on which the filters hooked to <tt>$tag</tt> are applied on.
* #param mixed $var,... Additional variables passed to the functions hooked to <tt>$tag</tt>.
* #return mixed The filtered value after all hooked functions are applied to it.
*/
public static function apply_filters($tag, $value) {
$args = array();
// Do 'all' actions first
if ( isset(self::$filters['all']) ) {
self::$current_filter[] = $tag;
$args = func_get_args();
self::_call_all_hook($args);
}
if ( !isset(self::$filters[$tag]) ) {
if ( isset(self::$filters['all']) )
array_pop(self::$current_filter);
return $value;
}
if ( !isset(self::$filters['all']) )
self::$current_filter[] = $tag;
// Sort
if ( !isset( self::$merged_filters[ $tag ] ) ) {
ksort(self::$filters[$tag]);
self::$merged_filters[ $tag ] = true;
}
reset( self::$filters[ $tag ] );
if ( empty($args) )
$args = func_get_args();
do {
foreach( (array) current(self::$filters[$tag]) as $the_ )
if ( !is_null($the_['function']) ){
$args[1] = $value;
$value = call_user_func_array($the_['function'], array_slice($args, 1, (int) $the_['accepted_args']));
}
} while ( next(self::$filters[$tag]) !== false );
array_pop( self::$current_filter );
return $value;
}
/**
* apply_filters_ref_array Execute functions hooked on a specific filter hook, specifying arguments in an array.
* #access public
* #since 0.1
* #param string $tag The name of the filter hook.
* #param array $args The arguments supplied to the functions hooked to <tt>$tag</tt>
* #return mixed The filtered value after all hooked functions are applied to it.
*/
public static function apply_filters_ref_array($tag, $args) {
// Do 'all' actions first
if ( isset(self::$filters['all']) ) {
self::$current_filter[] = $tag;
$all_args = func_get_args();
self::_call_all_hook($all_args);
}
if ( !isset(self::$filters[$tag]) ) {
if ( isset(self::$filters['all']) )
array_pop(self::$current_filter);
return $args[0];
}
if ( !isset(self::$filters['all']) )
self::$current_filter[] = $tag;
// Sort
if ( !isset( self::$merged_filters[ $tag ] ) ) {
ksort(self::$filters[$tag]);
self::$merged_filters[ $tag ] = true;
}
reset( self::$filters[ $tag ] );
do {
foreach( (array) current(self::$filters[$tag]) as $the_ )
if ( !is_null($the_['function']) )
$args[0] = call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
} while ( next(self::$filters[$tag]) !== false );
array_pop( self::$current_filter );
return $args[0];
}
/**
* ACTIONS
*/
/**
* add_action Hooks a function on to a specific action.
* #access public
* #since 0.1
* #param string $tag The name of the action to which the $function_to_add is hooked.
* #param callback $function_to_add The name of the function you wish to be called.
* #param int $priority optional. Used to specify the order in which the functions associated with a particular action are executed (default: 10). Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action.
* #param int $accepted_args optional. The number of arguments the function accept (default 1).
*/
public static function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
return self::add_filter($tag, $function_to_add, $priority, $accepted_args);
}
/**
* has_action Check if any action has been registered for a hook.
* #access public
* #since 0.1
* #param string $tag The name of the action hook.
* #param callback $function_to_check optional.
* #return mixed If $function_to_check is omitted, returns boolean for whether the hook has anything registered.
* When checking a specific function, the priority of that hook is returned, or false if the function is not attached.
* When using the $function_to_check argument, this function may return a non-boolean value that evaluates to false
* (e.g.) 0, so use the === operator for testing the return value.
*/
public static function has_action($tag, $function_to_check = false) {
return self::has_filter($tag, $function_to_check);
}
/**
* remove_action Removes a function from a specified action hook.
* #access public
* #since 0.1
* #param string $tag The action hook to which the function to be removed is hooked.
* #param callback $function_to_remove The name of the function which should be removed.
* #param int $priority optional The priority of the function (default: 10).
* #return boolean Whether the function is removed.
*/
public static function remove_action( $tag, $function_to_remove, $priority = 10 ) {
return self::remove_filter( $tag, $function_to_remove, $priority );
}
/**
* remove_all_actions Remove all of the hooks from an action.
* #access public
* #since 0.1
* #param string $tag The action to remove hooks from.
* #param int $priority The priority number to remove them from.
* #return bool True when finished.
*/
public static function remove_all_actions($tag, $priority = false) {
return self::remove_all_filters($tag, $priority);
}
/**
* do_action Execute functions hooked on a specific action hook.
* #access public
* #since 0.1
* #param string $tag The name of the action to be executed.
* #param mixed $arg,... Optional additional arguments which are passed on to the functions hooked to the action.
* #return null Will return null if $tag does not exist in $filter array
*/
public static function do_action($tag, $arg = '') {
if ( ! isset(self::$actions) )
self::$actions = array();
if ( ! isset(self::$actions[$tag]) )
self::$actions[$tag] = 1;
else
++self::$actions[$tag];
// Do 'all' actions first
if ( isset(self::$filters['all']) ) {
self::$current_filter[] = $tag;
$all_args = func_get_args();
self::_call_all_hook($all_args);
}
if ( !isset(self::$filters[$tag]) ) {
if ( isset(self::$filters['all']) )
array_pop(self::$current_filter);
return;
}
if ( !isset(self::$filters['all']) )
self::$current_filter[] = $tag;
$args = array();
if ( is_array($arg) && 1 == count($arg) && isset($arg[0]) && is_object($arg[0]) ) // array(&$this)
$args[] =& $arg[0];
else
$args[] = $arg;
for ( $a = 2; $a < func_num_args(); $a++ )
$args[] = func_get_arg($a);
// Sort
if ( !isset( self::$merged_filters[ $tag ] ) ) {
ksort(self::$filters[$tag]);
self::$merged_filters[ $tag ] = true;
}
reset( self::$filters[ $tag ] );
do {
foreach ( (array) current(self::$filters[$tag]) as $the_ )
if ( !is_null($the_['function']) )
call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
} while ( next(self::$filters[$tag]) !== false );
array_pop(self::$current_filter);
}
/**
* do_action_ref_array Execute functions hooked on a specific action hook, specifying arguments in an array.
* #access public
* #since 0.1
* #param string $tag The name of the action to be executed.
* #param array $args The arguments supplied to the functions hooked to <tt>$tag</tt>
* #return null Will return null if $tag does not exist in $filter array
*/
public static function do_action_ref_array($tag, $args) {
if ( ! isset(self::$actions) )
self::$actions = [];
if ( ! isset(self::$actions[$tag]) )
self::$actions[$tag] = 1;
else
++self::$actions[$tag];
// Do 'all' actions first
if ( isset(self::$filters['all']) ) {
self::$current_filter[] = $tag;
$all_args = func_get_args();
self::_call_all_hook($all_args);
}
if ( !isset(self::$filters[$tag]) ) {
if ( isset(self::$filters['all']) )
array_pop(self::$current_filter);
return;
}
if ( !isset(self::$filters['all']) )
self::$current_filter[] = $tag;
// Sort
if ( !isset( $merged_filters[ $tag ] ) ) {
ksort(self::$filters[$tag]);
$merged_filters[ $tag ] = true;
}
reset( self::$filters[ $tag ] );
do {
foreach( (array) current(self::$filters[$tag]) as $the_ )
if ( !is_null($the_['function']) )
call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
} while ( next(self::$filters[$tag]) !== false );
array_pop(self::$current_filter);
}
/**
* did_action Retrieve the number of times an action is fired.
* #access public
* #since 0.1
* #param string $tag The name of the action hook.
* #return int The number of times action hook <tt>$tag</tt> is fired
*/
public static function did_action($tag) {
if ( ! isset( self::$actions ) || ! isset( self::$actions[$tag] ) )
return 0;
return self::$actions[$tag];
}
/**
* HELPERS
*/
/**
* current_filter Retrieve the name of the current filter or action.
* #access public
* #since 0.1
* #return string Hook name of the current filter or action.
*/
public static function current_filter() {
return end( self::$current_filter );
}
/**
* Retrieve the name of the current action.
*
* #since 0.1.2
*
* #uses current_filter()
*
* #return string Hook name of the current action.
*/
public static function current_action() {
return self::current_filter();
}
/**
* Retrieve the name of a filter currently being processed.
*
* The function current_filter() only returns the most recent filter or action
* being executed. did_action() returns true once the action is initially
* processed. This function allows detection for any filter currently being
* executed (despite not being the most recent filter to fire, in the case of
* hooks called from hook callbacks) to be verified.
*
* #since 0.1.2
*
* #see current_filter()
* #see did_action()
* #global array $wp_current_filter Current filter.
*
* #param null|string $filter Optional. Filter to check. Defaults to null, which
* checks if any filter is currently being run.
* #return bool Whether the filter is currently in the stack
*/
public static function doing_filter( $filter = null ) {
if ( null === $filter ) {
return ! empty( self::$current_filter );
}
return in_array( $filter, self::$current_filter );
}
/**
* Retrieve the name of an action currently being processed.
*
* #since 0.1.2
*
* #uses doing_filter()
*
* #param string|null $action Optional. Action to check. Defaults to null, which checks
* if any action is currently being run.
* #return bool Whether the action is currently in the stack.
*/
public static function doing_action( $action = null ) {
return self::doing_filter( $action );
}
/**
* _filter_build_unique_id Build Unique ID for storage and retrieval.
* #param string $tag Used in counting how many hooks were applied
* #param callback $function Used for creating unique id
* #param int|bool $priority Used in counting how many hooks were applied. If === false and $function is an object reference, we return the unique id only if it already has one, false otherwise.
* #return string|bool Unique ID for usage as array key or false if $priority === false and $function is an object reference, and it does not already have a unique id.
*/
private static function _filter_build_unique_id($tag, $function, $priority) {
static $filter_id_count = 0;
if ( is_string($function) )
return $function;
if ( is_object($function) ) {
// Closures are currently implemented as objects
$function = array( $function, '' );
} else {
$function = (array) $function;
}
if (is_object($function[0]) ) {
// Object Class Calling
if ( function_exists('spl_object_hash') ) {
return spl_object_hash($function[0]) . $function[1];
} else {
$obj_idx = get_class($function[0]).$function[1];
if ( !isset($function[0]->filter_id) ) {
if ( false === $priority )
return false;
$obj_idx .= isset(self::$filters[$tag][$priority]) ? count((array)self::$filters[$tag][$priority]) : $filter_id_count;
$function[0]->filter_id = $filter_id_count;
++$filter_id_count;
} else {
$obj_idx .= $function[0]->filter_id;
}
return $obj_idx;
}
} else if ( is_string($function[0]) ) {
// Static Calling
return $function[0].$function[1];
}
}
/**
* __call_all_hook
* #access public
* #since 0.1
* #param (array) $args [description]
*/
public static function __call_all_hook($args) {
reset( self::$filters['all'] );
do {
foreach( (array) current(self::$filters['all']) as $the_ )
if ( !is_null($the_['function']) )
call_user_func_array($the_['function'], $args);
} while ( next(self::$filters['all']) !== false );
}
}//end class
/**
* Hooks Shortcuts not in class
*/
function add_action($hook, $function) {
return Hooks::add_action($hook, $function);
}
function has_action($hook, $function) {
return Hooks::has_action($hook, $function);
}
function do_action($hook, $args = '') {
return Hooks::do_action($hook, $args);
}
function remove_action($hook, $function, $priority = '') {
return Hooks::remove_action($hook, $function, $priority);
}
function remove_all_actions($hook, $priority = '') {
return Hooks::remove_all_actions($hook, $priority);
}
?>
EDIT: Heres my autoloader class:
<?php
class Autoloader {
/**
* File extension as a string. Defaults to ".php".
*/
protected static $fileExt = '.php';
/**
* The top level directory where recursion will begin. Defaults to the current
* directory.
*/
protected static $pathTop = __DIR__;
/**
* A placeholder to hold the file iterator so that directory traversal is only
* performed once.
*/
protected static $fileIterator = null;
/**
* Autoload function for registration with spl_autoload_register
*
* Looks recursively through project directory and loads class files based on
* filename match.
*
* #param string $className
*/
public static function loader($className) {
$directory = new RecursiveDirectoryIterator(static::$pathTop, RecursiveDirectoryIterator::SKIP_DOTS);
if (is_null(static::$fileIterator)) {
static::$fileIterator = new RecursiveIteratorIterator($directory, RecursiveIteratorIterator::LEAVES_ONLY);
}
$filename = $className . static::$fileExt;
foreach (static::$fileIterator as $file) {
if (strtolower($file->getFilename()) === strtolower($filename)) {
if ($file->isReadable()) {
include_once $file->getPathname();
}
break;
}
}
}
/**
* Sets the $fileExt property
*
* #param string $fileExt The file extension used for class files. Default is "php".
*/
public static function setFileExt($fileExt) {
static::$fileExt = $fileExt;
}
/**
* Sets the $path property
*
* #param string $path The path representing the top level where recursion should
* begin. Defaults to the current directory.
*/
public static function setPath($path) {
static::$pathTop = $path;
}
}
Autoloader::setFileExt('.php');
spl_autoload_register('Autoloader::loader');
?>
You cannot declare a class as static, but you can do the following:
restricting object instantiation:
private function __construct() {} // Constructor disabled
private function __clone() {} // Cloning disabled
private function __wakeup() {} // Serialization disabled
declare all properties static
declare all methods static
and you have a basically static-like class.
For example:
<?php
class Hooks
{
protected static $filters = [];
protected static $merged_filters = [];
protected static $actions = [];
protected static $current_filter = [];
// You don't need an instance unless you want to implement a simpleton pattern.
// protected static $_instance;
// Disable object instantiation
private function __construct() {}
private function __clone() {}
private function __serialize() {}
// You don't need this either:
// public static function getInstance() { ... }
public static function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1)
{
$idx = self::filter_build_unique_id($tag, $function_to_add, $priority);
self::$filters[$tag][$priority][$idx] = ['function' => $function_to_add, 'accepted_args' => $accepted_args];
unset( self::$merged_filters[ $tag ] );
return true;
}
//
// ...and so on...
//
to answer my issue of autoloader not loading my class, i moved the require to my autoloader to before session_start(); in my system and bam ! autoloaded nicely :)
I'm attempting to remove an action and add it with a different priority.
Below are all the code snippets that assist in generating a Message:
Include required frontend files
private function frontend_includes() {
require_once( $this->get_plugin_path() . '/includes/wc-memberships-template-functions.php' );
require_once( $this->get_plugin_path() . '/includes/class-wc-memberships-shortcodes.php' );
WC_Memberships_Shortcodes::initialize();
$this->frontend = $this->load_class( '/includes/frontend/class-wc-memberships-frontend.php', 'WC_Memberships_Frontend' );
$this->checkout = $this->load_class( '/includes/frontend/class-wc-memberships-checkout.php', 'WC_Memberships_Checkout' );
$this->restrictions = $this->load_class( '/includes/frontend/class-wc-memberships-restrictions.php', 'WC_Memberships_Restrictions' );
}
Get the product purchasing restricted message
/**
* #param int $post_id Optional. Defaults to current post.
* #return string
*/
public function get_product_purchasing_restricted_message( $post_id = null ) {
if ( ! $post_id ) {
global $post;
$post_id = $post->ID;
}
$products = $this->get_products_that_grant_access( $post_id );
$message = $this->get_restriction_message( 'product_purchasing_restricted', $post_id, $products );
/**
* Filter the product purchasing restricted message
*
* #since 1.0.0
* #param string $message The restriction message
* #param int $product_id ID of the product being restricted
* #param array $products Array of product IDs that grant access to this product
*/
return apply_filters( 'wc_memberships_product_purchasing_restricted_message', $message, $post_id, $products );
}
Restriction class, handles content restriction on frontend
class WC_Memberships_Restrictions {
/** #var array associative array of content conditions for current user **/
private $user_content_access_conditions;
/** #var array of post IDs that content restriction has been applied to **/
private $content_restriction_applied = array();
/** #var string Product content restriction password helper **/
private $product_restriction_password = null;
/** #var bool Product thumbnail removed helper **/
private $product_thumbnail_restricted = false;
public function __construct() {
// Desired action to remove and re-prioritize
add_action( 'woocommerce_single_product_summary', array( $this, 'single_product_purchasing_restricted_message' ), 30 );
}
}
I literally just need to alter the priority to 15 from 30 in the action of the WC_Memberships_Restrictions class. The issue is that there's no clear way to call the removal. Any suggestions?
Well the code you provided shows that the instance of the WC_Memberships_Restrictions class is stored in the main class' restrictions property.
$this->restrictions = $this->load_class( '/includes/frontend/class-wc-memberships-restrictions.php', 'WC_Memberships_Restrictions' );
From there I just had to look up how to access the instance of the main Membership class, from the bottom of the main plugin file you see:
/**
* Returns the One True Instance of Memberships
*
* #since 1.0.0
* #return WC_Memberships
*/
function wc_memberships() {
return WC_Memberships::instance();
}
This means that now to access the instance of the restrictions class we need to access the main class's restriction property. While that sounds clear as mud, basically it means this:
wc_memberships()->restrictions
Knowing this, we can known remove and add actions from that class:
function so_41431558_change_hook_priority(){
if( function_exists( 'wc_memberships' ) ){
remove_action( 'woocommerce_single_product_summary', array( wc_memberships()->restrictions, 'single_product_purchasing_restricted_message' ), 30 );
add_action( 'woocommerce_single_product_summary', array( wc_memberships()->restrictions, 'single_product_purchasing_restricted_message' ), 15 );
}
}
add_action( 'woocommerce_single_product_summary', 'so_41431558_change_hook_priority', 1 );
I have a meta box I'm coding for the product post type that comes with woocommerce. I've run into a problem I can't pass in that the 'save_post' hook does not seem to be working at all with products. It works perfectly for posts, but since I've changed my code to work for products it does nothing. The save_post function I've hooked to does absolutely nothing at the moment. I've added all sorts of code to it and it doesn't matter, the script just doesn't seem to get that far. am I missing something obvious?
Edit: as an aside, I added
?> <script type="text/javascript">
var post_id = '<?php $post_id ?>';
console.log("id is: " + post_id );
</script><?php
But it returns absolutely nothing.
<?php
/*
* Represents the plugin's Meta Box
*
* #since 0.0.1
* #package BBPlugin
* #subpackage BBPlugin
* #author Christopher Dando <captaindando#gmail.com>
*/
/*
* Represents the plugin's Meta Box
*
* Register's the meta box with the WordPress API, sets its properties,
* by including the markup from its associated view
*
* #package BBPlugin
* #subpackage BBPlugin/admin
* #author Christopher Dando <captaindando#gmail.com>
*/
class BBPlugin_Meta_Box{
/*
* Register this class with the wordpress API
*
* #since 0.0.1
*/
public function initialize_hooks(){
//add_action( 'add_meta_boxes_product', array( $this, 'add_meta_box' ) );
add_action( 'add_meta_boxes', array( $this, 'BBadd_meta_box' ) );
// This checks when wordpress is saving or
// updating a post.
add_action( 'save_post', array( $this, 'save_post' ) );
$junk = $post_id;
?> <script type="text/javascript">
var post_id = '<?php global $post; echo $post->ID; ?>';
console.log("id is: " + post_id );
</script><?php
}
// add_meta_boxes is the wordpress function. add_meta_box is our new function
/*
* The function responsible for creating the actual meta box.
*
* #since 0.0.1
*/
public function BBadd_meta_box(){
?> <script>console.log("meta box added");</script><?php
add_meta_box(
'BBPlugin',
"Brave Books",
array( $this, 'display_meta_box' ),
'product',
'normal',
'default'
);
}
// This defines the properties of the meta box.
/*
* Renders the content of the meta box.
*
* #since 0.0.1
*/
public function display_meta_box(){
include_once( 'views/BBPlugin-navigation.php' );
}
/**
* Sanitizes and serializes the information associated with this post.
*
* #since 0.0.1
*
* #param int $post_id The ID of the post that's currently being edited.
*/
// strangely, this calls if the meta box does not render
public function save_post( $post_id ) {
?><script>alert("post saved");</script><?php
/* If we're not working with a 'product' post type or the
user doesn't have permission to save,
then we exit the function.
*/
if ( ! $this->user_can_save( $post_id, 'BBPlugin_nonce', 'BBPlugin_save' ) ) {
return;
}
/*
We need to 'Sanitise' our information before
we can save it to the database. What this means
is that we must strip it of html tags
and extract the text itself.
*/
// If the 'Resources' inputs exist, iterate through them and sanitize them
if ($this->value_exists( 'BBPlugin-resources' ) ) {
// This is all divs with the id of meta-box-resources
$this->update_post_meta(
$post_id,
'BBPlugin-resources',
$this->sanitize_data( 'BBPlugin-resources', true )
);
}
else {
// leaving an input blank on the front end will remove that specific input.
$this->delete_post_meta( $post_id, 'BBPlugin-resources' );
}
}
/**
* Determines whether or not a value exists in the $_POST collection
* identified by the specified key.
*
* #since 0.0.1
*
* #param string $key The key of the value in the $_POST collection.
* #return bool True if the value exists; otherwise, false.
*/
private function value_exists( $key ) {
return ! empty( $_POST[ $key ] );
}
/**
* Deletes the specified meta data associated with the specified post ID
* based on the incoming key.
*
* #since 0.0.1
* #access private
* #param int $post_id The ID of the post containing the meta data
* #param string $meta_key The ID of the meta data value
*/
private function delete_post_meta( $post_id, $meta_key ) {
if ( '' !== get_post_meta( $post_id, $meta_key, true ) ) {
delete_post_meta( $post_id, '$meta_key' );
}
}
private function update_post_meta( $post_id, $meta_key, $meta_value ) {
if ( is_array( $_POST[ $meta_key ] ) ) {
$meta_value = array_filter( $_POST[ $meta_key ] );
}
/*
Update_post_meta also adds to a database if there is nothing there already.
parameters are as follows:
1. The post ID used to associate this information with the post.
2. A meta key that's used to uniquely identify the value.
3. The actual value associated with the meta key.
*/
update_post_meta( $post_id, $meta_key, $meta_value );
}
/**
* Sanitizes the data in the $_POST collection identified by the specified key
* based on whether or not the data is text or is an array.
*
* #since 1.0.0
* #access private
* #param string $key The key used to retrieve the data from the $_POST collection.
* #param bool $is_array Optional. True if the incoming data is an array.
* #return array|string The sanitized data.
*/
private function sanitize_data( $key, $is_array = false ) {
$sanitized_data = null;
if ( $is_array ) {
$resources = $_POST[ $key ];
$sanitized_data = array();
foreach ( $resources as $resource ) {
$resource = esc_url( strip_tags( $resource ) );
if ( ! empty( $resource ) ) {
$sanitized_data[] = $resource;
}
}
}
else {
$sanitized_data = '';
$sanitized_data = trim( $_POST[ $key ] );
$sanitized_data = esc_textarea( strip_tags( $sanitized_data ) );
}
return $sanitized_data;
}
/**
* Verifies that the post type that's being saved is actually a post (versus a page or another
* custom post type.
*
*
* #since 0.0.1
* #access private
* #return bool Return if the current post type is a post; false, otherwise.
*/
private function is_valid_post_type() {
return ! empty( $_POST['post_type'] ) && 'post' == $_POST['post_type'];
}
/**
* Determines whether or not the current user has the ability to save meta data associated with this post.
*
* #since 0.0.1
* #access private
* #param int $post_id The ID of the post being save
* #param string $nonce_action The name of the action associated with the nonce.
* #param string $nonce_id The ID of the nonce field.
* #return bool Whether or not the user has the ability to save this post.
*/
private function user_can_save( $post_id, $nonce_action, $nonce_id ) {
$is_autosave = wp_is_post_autosave( $post_id );
$is_revision = wp_is_post_revision( $post_id );
$is_valid_nonce = ( isset( $_POST[ $nonce_action ] ) && wp_verify_nonce( $_POST[ $nonce_action ], $nonce_id ) );
// Return true if the user is able to save; otherwise, false.
return ! ( $is_autosave || $is_revision ) && $this->is_valid_post_type() && $is_valid_nonce;
}
}
?>
In Wordpress, save_post isn't a destination in itself; it is an action carried out effectively 'between' pages: you hit Update, and Wordpress will carry out a series of actions behind the scenes before returning you to the appropriate page (invariably the post you were just editing, with a notification about the status of that save).
As such, you will never see the results of an echo, print_r, or JS alert or console.log, because save_post isn't a user-facing action.
If you want to see if your save_post action is being carried out in this way, I would recommend throwing in a die(), like so:
public function save_post($post_id) {
?><script>alert("post saved");</script><?php
die();
}
If the save_post action is being fired correctly, then you should see the JS alert over a blank page. If you want to see if your function is carrying out any actual Wordpress-style functionality, I'd recommend a simple update_post_meta to confirm:
public function save_post($post_id) {
// Insert some actual logic to ensure you're not doing this on every post all the time
update_post_meta($post_id, 'i_am_saved', 'totes saved to post #' . $post_id);
}
You can then check the database (or click to view the custom fields within that post) to see if your custom metadata has been added.
I would also recommend attaching your save_post action specifically to the product post type that's used by WooCommerce:
add_action('save_post_product', array($this, 'save_post'));
That will save some redundancy checking later.
I am trying to programmatically set the label value of a widget after performing some checks but my below attempts are not working. Can anyone see what I am doing wrong? Note that the label already has a value and I just want to clear it. That is in symfony 1.4.
class customFormSome extends sfWidgetFormTextarea {
/**
* Constructor.
*
* #see sfWidgetFormTextarea
* */
protected function configure($options = array(), $attributes = array()) {
$this->addOption('element_id');
}
/**
* #param string $name The element name
* #param string $value The value displayed in this widget
* #param array $attributes An array of HTML attributes to be merged with the default HTML attributes
* #param array $errors An array of errors for the field
*
* #see sfWidget
* */
public function render($name, $value = null, $attributes = array(), $errors = array()) {
/*** SOME PROCESSING HERE******/
$this->setAttribute('label', ''); //---->DOESNT WORK
$this->setAttribute('label', FALSE); //---->DOESNT WORK
$this->setAttribute('label', NULL); //---->DOESNT WORK
$fields = $this->parent->setLabel($this->getOption('element_id'), '');//---->DOESNT WORK
}
It's too late to call setAttiribute() in render method, it gets attributes from $attributes parameter, so you only need to overwrite it:
public function render($name, $value = null, $attributes = array(), $errors = array()) {
/*** SOME PROCESSING HERE******/
$attributes['label'] = $this->getOption('element_id');
return parent::render($name, $value, $attributes, $errors);
}
I'm creating an object registry to easily retrieve objects and handle global objects ( objects of which i need just one instance like wrappers around wp_functions or factories )
Basically i have various scenarioes to handle.
1) the object i need to create is a simple class.
2) the object i need to create is a simple class but there is no need for different instances.
3) the object i need to create is created by a factory.
4) the object i need to created needs some parameters.
This is the code i have
<?php
/**
* #author nicola
*
*/
class Ai1ec_Object_Registry implements Ai1ec_Registry_Interface {
CONST PREFIX = 'Ai1ec_';
static private $_objects = array();
static private $_classes = array();
/**
* (non-PHPdoc)
*
* #see Ai1ec_Registry_Interface::get()
*
*/
public function get( $key ) {
$classname = $this->get_classname();
if( ! isset ( self::$_classes[$classname] ) ) {
throw new Ai1ec_Registry_Exception(
'The class "' . $classname . '" was not registered'
);
}
$options = self::$_classes[$classname];
// if it's a global object and it's already set, return it
if ( isset( $options['global'] ) &&
isset( self::$_objects[$classname] ) ) {
return self::$_objects[$classname];
}
$params = array();
if( func_num_args() > 1 ) {
$params = func_get_arg( 1 );
}
// check if the object needs a factory
if ( isset( $options['factory'] ) ) {
return $this->dispatch(
$options['factory'][0],
$options['factory'][1],
$params
);
} else {
if ( empty( $params ) ) {
return new $classname();
} else {
$class = new ReflectionClass( $classname );
return $class->newInstanceArgs( $params );
}
}
}
/**
* (non-PHPdoc)
*
* #see Ai1ec_Registry_Interface::set()
*
*/
public function set( $key, $val ) {
if ( ! is_object( $val ) ) {
throw new Ai1ec_Registry_Exception( 'Only Objects can be stored in the registry' );
}
$classname = $this->get_classname();
if ( isset( self::$_objects[$classname] ) ) {
throw new Ai1ec_Registry_Exception( 'Only one object for each key is allowed' );
}
self::$_objects[$classname] = $val;
}
/**
* Register a class into the registry
*
* #param string $class_name The name of the class to registr
* #param array $options An array of options about the class.
*/
public function register( $class_name, array $options ) {
if( isset( self::$_classes[$class_name] ) ) {
throw new Ai1ec_Registry_Exception( 'A class can\'t be registered twice' );
}
self::$_classes[$class_name] = $options;
}
/**
* A call_user_func_array alternative.
*
* #param string $class
* #param string $method
* #param array $params
*
* #return mixed
*/
public function dispatch( $class, $method, $params = array() ) {
// get an instance of the class
$class = $this->get( $class );
switch ( count( $params) ) {
case 0:
return $class->{$method}();
case 1:
return $class->{$method}( $params[0] );
case 2:
return $class->{$method}( $params[0], $params[1] );
case 3:
return $class->{$method}( $params[0], $params[1], $params[2] );
case 4:
return $class->{$method}(
$params[0],
$params[1],
$params[2],
$params[3]
);
case 5:
return $class->{$method}(
$params[0],
$params[1],
$params[2],
$params[3],
$params[4]
);
default:
return call_user_func_array( array( $class, $method ), $params );
}
}
/**
* Return the class name from the key.
*
* #param string $key
*
* #return string
*/
private function get_classname( $key ) {
return self::PREFIX . $key;
}
}
it should handle all the cases, but is this the best way to do this? Doesn't this introduce too much overhead?