Permalink
Browse files

Fixed a compatibility issue with some third-parties which attempt to …

…instantiate the framework widget class without given any parameters. Resolves #273
  • Loading branch information...
michaeluno committed Jul 7, 2018
1 parent 824e0d1 commit bf4b7fc95133254435274d165fe24d580859b3cc
@@ -6,7 +6,7 @@
* Author: Michael Uno
* Author URI: http://en.michaeluno.jp/
* Requirements: PHP 5.2.4 or above, WordPress 3.3 or above.
* Version: 3.8.16
* Version: 3.8.17b01
*/
/**
@@ -16,7 +16,7 @@
*/
class AdminPageFrameworkLoader_Registry_Base {
const VERSION = '3.8.16'; // <--- DON'T FORGET TO CHANGE THIS AS WELL!!
const VERSION = '3.8.17b01'; // <--- DON'T FORGET TO CHANGE THIS AS WELL!!
const NAME = 'Admin Page Framework - Loader'; // the name is not 'Admin Page Framework' because warning messages gets confusing.
const SHORTNAME = 'Admin Page Framework'; // used for a menu title etc.
const DESCRIPTION = 'Loads Admin Page Framework which facilitates WordPress plugin and theme development.';
@@ -35,11 +35,11 @@
* @download_latest https://github.com/michaeluno/admin-page-framework/archive/master.zip
* @download_stable http://downloads.wordpress.org/plugin/admin-page-framework.latest-stable.zip
* @catchcopy The framework for all WordPress developers.
* @version 3.8.16
* @version 3.8.17b01
*/
abstract class AdminPageFramework_Registry_Base {
const VERSION = '3.8.16'; // <--- DON'T FORGET TO CHANGE THIS AS WELL!!
const VERSION = '3.8.17b01'; // <--- DON'T FORGET TO CHANGE THIS AS WELL!!
const NAME = 'Admin Page Framework';
const DESCRIPTION = 'Facilitates WordPress plugin and theme development.';
const URI = 'http://en.michaeluno.jp/admin-page-framework';
@@ -28,43 +28,95 @@
protected $_sStructureType = 'widget';
/**
* The constructor of the class object.
*
* Registers necessary hooks and sets up internal properties.
*
* <h4>Example</h4>
* <code>
* new APF_Widget( __( 'Admin Page Framework', 'admin-page-framework-demo' ) ); // the widget title
* new APF_Widget_CustomFieldTypes( __( 'APF - Advanced', 'admin-page-framework-demo' ) );
* new APF_Widget_Example( __( 'APF - GitHub Button', 'admin-page-framework-demo' ) );
* </code>
*
* @return void
*/
public function __construct( $sWidgetTitle, $aWidgetArguments=array(), $sCapability='edit_theme_options', $sTextDomain='admin-page-framework' ) {
if ( empty( $sWidgetTitle ) ) {
return;
}
// Properties
$_sProprtyClassName = isset( $this->aSubClassNames[ 'oProp' ] )
? $this->aSubClassNames[ 'oProp' ]
: 'AdminPageFramework_Property_' . $this->_sStructureType;
$this->oProp = new $_sProprtyClassName(
$this, // caller object
null, // the caller script path
get_class( $this ), // class name
$sCapability, // capability
$sTextDomain, // text domain
$this->_sStructureType // fields type
);
$this->oProp->sWidgetTitle = $sWidgetTitle;
$this->oProp->aWidgetArguments = $aWidgetArguments;
* The constructor of the class object.
*
* Registers necessary hooks and sets up internal properties.
*
* <h4>Example</h4>
* <code>
* new APF_Widget( __( 'Admin Page Framework', 'admin-page-framework-demo' ) ); // the widget title
* new APF_Widget_CustomFieldTypes( __( 'APF - Advanced', 'admin-page-framework-demo' ) );
* new APF_Widget_Example( __( 'APF - GitHub Button', 'admin-page-framework-demo' ) );
* </code>
*
* @since 3.2.0
* @since 3.8.17 Made it accept an empty parameter for cases that some third-parties assume this is a WP_Widget extending class.
* @remark If nothing is passed to the class constructor, it could be a third-party attempts to instantiate this class by misunderstanding that this is an extended class of the `WP_Widget` class.
* @param string The widget title
* @param array Widget arguments
* @param string Capability
* @param string Text domain for translation
*/
public function __construct( /* $sWidgetTitle, $aWidgetArguments=array(), $sCapability='edit_theme_options', $sTextDomain='admin-page-framework' */ ) {
$_sThisClassName = get_class( $this );
$_bAssumedAsWPWidget = 0 === func_num_args();
$_aDefaults = array( '', array(), 'edit_theme_options', 'admin-page-framework' );
$_aParameters = $_bAssumedAsWPWidget
? $this->___getConstructorParametersUsedForThisClassName( $_sThisClassName ) + $_aDefaults
: func_get_args() + $_aDefaults;
$this->___setProperties( $_aParameters, $_sThisClassName, $_bAssumedAsWPWidget );
parent::__construct( $this->oProp );
}
/**
* Sets up properties.
* @since 3.8.17
* @return void
*/
private function ___setProperties( $aParameters, $sThisClassName, $_bAssumedAsWPWidget ) {
$sWidgetTitle = $aParameters[ 0 ];
$aWidgetArguments = $aParameters[ 1 ];
$sCapability = $aParameters[ 2 ];
$sTextDomain = $aParameters[ 3 ];
$_sPropertyClassName = isset( $this->aSubClassNames[ 'oProp' ] )
? $this->aSubClassNames[ 'oProp' ]
: 'AdminPageFramework_Property_' . $this->_sStructureType;
$this->oProp = new $_sPropertyClassName(
$this, // caller object
null, // the caller script path
$sThisClassName, // class name
$sCapability, // capability
$sTextDomain, // text domain
$this->_sStructureType // fields type
);
$this->oProp->sWidgetTitle = $sWidgetTitle;
$this->oProp->aWidgetArguments = $aWidgetArguments;
$this->oProp->bAssumedAsWPWidget = $_bAssumedAsWPWidget;
if ( $_bAssumedAsWPWidget ) {
$this->oProp->aWPWidgetMethods = get_class_methods( 'WP_Widget' );
$this->oProp->aWPWidgetProperties = get_class_vars( 'WP_Widget' );
}
}
/**
* Finds used parameter values to this class constructor of the given extended class name that is already registered.
*
* @param string $sClassName
* @return array Parameters passed to this class constructor of the given class name.
* @since 3.8.17
*/
private function ___getConstructorParametersUsedForThisClassName( $sClassName ) {
if ( ! is_object( $GLOBALS[ 'wp_widget_factory' ] ) ) {
return array();
}
if ( ! isset( $GLOBALS[ 'wp_widget_factory' ]->widgets[ $sClassName ] ) ) {
return array();
}
// At this point, the widget of the given name is already registered.
$_oWPWidget = $GLOBALS[ 'wp_widget_factory' ]->widgets[ $sClassName ];
return array(
$_oWPWidget->oCaller->oProp->sWidgetTitle, // 1. widget title,
$_oWPWidget->oCaller->oProp->aWidgetArguments, // 2. widget arguments
$_oWPWidget->oCaller->oProp->sCapability, // 3. capability
$_oWPWidget->oCaller->oProp->sTextDomain, // 4. text domain
);
}
}
@@ -188,7 +188,12 @@ public function form( $aSavedFormData ) {
* @since 3.7.0
*/
private function _loadFrameworkFactory() {
// @since 3.8.17
if ( $this->oCaller->oProp->bAssumedAsWPWidget ) {
return;
}
/**
* Call the load method only once per class. Also the added field registrations in the class also done once.
* @since 3.7.9
@@ -107,20 +107,19 @@ public function _replyToHandleSubmittedFormData( $aSavedData, $aArguments, $aSec
* @return void
*/
public function _replyToRegisterWidget() {
global $wp_widget_factory;
if ( ! is_object( $wp_widget_factory ) ) {
if ( ! is_object( $GLOBALS[ 'wp_widget_factory' ] ) ) {
return;
}
$wp_widget_factory->widgets[ $this->oProp->sClassName ] = new AdminPageFramework_Widget_Factory(
$GLOBALS[ 'wp_widget_factory' ]->widgets[ $this->oProp->sClassName ] = new AdminPageFramework_Widget_Factory(
$this,
$this->oProp->sWidgetTitle,
$this->oUtil->getAsArray( $this->oProp->aWidgetArguments )
);
// [3.5.9+] Store the widget object in the property.
$this->oProp->oWidget = $wp_widget_factory->widgets[ $this->oProp->sClassName ];
$this->oProp->oWidget = $GLOBALS[ 'wp_widget_factory' ]->widgets[ $this->oProp->sClassName ];
}
@@ -46,6 +46,37 @@ public function __construct( $oProp ) {
*/
public function _replyToLoadComponents( /* $oScreen */ ) {
return;
}
}
/**
* @param $sMethodName
* @param null|array $aArguments
*
* @return mixed
* @since 3.8.17
*/
public function __call( $sMethodName, $aArguments=null ) {
if ( $this->oProp->bAssumedAsWPWidget ) {
if ( in_array( $sMethodName, $this->oProp->aWPWidgetMethods ) ) {
return call_user_func_array(
array( $this->oProp->oWidget, $sMethodName ),
$aArguments
);
}
}
return parent::__call( $sMethodName, $aArguments );
}
/**
* Responds to a request to an undefined property.
* @since 3.8.17
*/
public function __get( $sPropertyName ) {
if ( $this->oProp->bAssumedAsWPWidget ) {
if ( isset( $this->oProp->aWPWidgetProperties[ $sPropertyName ] ) ) {
return $this->oProp->oWidget->$sPropertyName;
}
}
return parent::__get( $sPropertyName );
}
}
@@ -105,7 +105,23 @@ class AdminPageFramework_Property_widget extends AdminPageFramework_Property_Bas
*/
// public $_sFormRegistrationHook = 'admin_enqueue_scripts';
// public $_sFormRegistrationHook = '';
/**
* Indicates whether the class is instantiated by being assumed as a WP_Widget subclass object.
* @since 3.8.17
*/
public $bAssumedAsWPWidget = false;
/**
* Stores method names of the `WP_Widget` class, referred when the class is assumed as a WP_Widget subclass.
* @since 3.8.17
*/
public $aWPWidgetMethods = array();
/**
* Stores property names of the `WP_Widget` class, , referred when the class is assumed as a WP_Widget subclass.
* @since 3.8.17
*/
public $aWPWidgetProperties = array();
/**
* Sets up properties.
* @since 3.7.0
View
@@ -505,6 +505,9 @@ See examples, https://gist.github.com/michaeluno/c30713fcfe0d9d45d89f, https://g
== Changelog ==
= 3.8.17 =
- Fixed a compatibility issue with some third-parties which attempt to instantiate the framework widget class without given any parameters.
= 3.8.16 - 2018/07/06 =
- Fixed a bug that the default sub-menu page of a custom top-level menu page could not be removed when the PHP class with a namespace is used.

0 comments on commit bf4b7fc

Please sign in to comment.