Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
parameters:
level: 9
paths:
- src
- widget-command.php
scanDirectories:
- vendor/wp-cli/wp-cli/php
scanFiles:
- vendor/php-stubs/wordpress-stubs/wordpress-stubs.php
treatPhpDocTypesAsCertain: false
ignoreErrors:
- identifier: missingType.parameter
- identifier: missingType.return
3 changes: 3 additions & 0 deletions src/Sidebar_Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
*/
class Sidebar_Command extends WP_CLI_Command {

/**
* @var string[]
*/
private $fields = [
'name',
'id',
Expand Down
46 changes: 33 additions & 13 deletions src/Widget_Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
*/
class Widget_Command extends WP_CLI_Command {

/**
* @var string[]
*/
private $fields = [
'name',
'id',
Expand Down Expand Up @@ -156,7 +159,7 @@ public function add( $args, $assoc_args ) {
}
unset( $option_keys['_multiwidget'] );
$option_keys = array_keys( $option_keys );
$last_key = array_pop( $option_keys );
$last_key = (int) array_pop( $option_keys );
$option_index = $last_key + 1;
$widget_options[ $option_index ] = $this->sanitize_widget_options( $name, $assoc_args, array() );
$this->update_widget_options( $name, $widget_options );
Expand Down Expand Up @@ -624,7 +627,7 @@ private function validate_sidebar_widget( $widget_id ) {
* Gets the widgets (and their associated data) for a given sidebar
*
* @param string $sidebar_id
* @return array
* @return list<object{name: string, id: string, position: int, options: array<string, mixed>}&\stdClass>
*/
private function get_sidebar_widgets( $sidebar_id ) {

Expand All @@ -640,24 +643,33 @@ private function get_sidebar_widgets( $sidebar_id ) {
$prepared_widget = new stdClass();

$parts = explode( '-', $widget_id );
$option_index = array_pop( $parts );
$option_index = (string) array_pop( $parts );
$widget_name = implode( '-', $parts );

$prepared_widget->name = $widget_name;
$prepared_widget->id = $widget_id;
$prepared_widget->position = $key + 1;
$widget_options = get_option( 'widget_' . $widget_name );
$prepared_widget->options = $widget_options[ $option_index ];
$widget_options = get_option( 'widget_' . $widget_name, [] );
/**
* @var array<string, mixed> $widget_options
*/
$prepared_widget->options = $widget_options[ $option_index ];

$prepared_widgets[] = $prepared_widget;
}

/**
* @phpstan-var list<object{name: string, id: string, position: int, options: array<string, mixed>}&\stdClass> $prepared_widgets
*/

return $prepared_widgets;
}

/**
* Re-implementation of wp_get_sidebars_widgets()
* because the original has a nasty global component
* because the original has a nasty global component.
*
* @return array<string, array<int, string>>
*/
private function wp_get_sidebars_widgets() {
$sidebars_widgets = get_option( 'sidebars_widgets', array() );
Expand All @@ -666,14 +678,18 @@ private function wp_get_sidebars_widgets() {
unset( $sidebars_widgets['array_version'] );
}

/**
* @var array<string, array<int, string>> $sidebars_widgets
*/

return $sidebars_widgets;
}

/**
* Gets the widget's name, option index, sidebar, and sidebar index from its ID
*
* @param string $widget_id
* @return array
* @return array{0: string, 1: string, 2: string, 3: int}
*/
private function get_widget_data( $widget_id ) {

Expand All @@ -694,24 +710,28 @@ private function get_widget_data( $widget_id ) {
}
}

return array( $name, $option_index, $sidebar_id, $sidebar_index );
return array( $name, $option_index, (string) $sidebar_id, (int) $sidebar_index );
}

/**
* Gets the options for a given widget
*
* @param string $name
* @return array
* @return array<string, mixed>
*/
private function get_widget_options( $name ) {
return get_option( 'widget_' . $name, array() );
$options = get_option( 'widget_' . $name, array() );
/**
* @var array<string,mixed> $options
*/
return $options;
Comment on lines 719 to +727
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_widget_options() is documented/annotated as array<string, mixed>, but throughout this class it is accessed with both string keys (e.g. _multiwidget) and numeric instance indexes. This docblock will misrepresent the type for PHPStan and can lead to offset-type errors; update it to a key type that matches real usage (e.g. array<int|string, mixed> or a more precise shape), and consider normalizing get_option() to an array in case it returns false.

Copilot uses AI. Check for mistakes.
}

/**
* Updates the options for a given widget
*
* @param string $name
* @param mixed
* @param mixed $value
*/
private function update_widget_options( $name, $value ) {
update_option( 'widget_' . $name, $value );
Expand Down Expand Up @@ -785,7 +805,7 @@ private function get_widget_obj( $id_base ) {
* @param string $id_base Name of the widget
* @param mixed $dirty_options
* @param mixed $old_options
* @return mixed
* @return array<string, mixed>
*/
private function sanitize_widget_options( $id_base, $dirty_options, $old_options ) {

Expand All @@ -797,6 +817,6 @@ private function sanitize_widget_options( $id_base, $dirty_options, $old_options
// No easy way to determine expected array keys for $dirty_options
// because Widget API dependent on the form fields
// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- Whitelisting due to above reason.
return @$widget->update( $dirty_options, $old_options );
return @$widget->update( $dirty_options, $old_options ); // @phpstan-ignore argument.type, argument.type
}
}