Discussion:
Need WP/PHP guru eyeballs/feedback on my WP_Widget wrapper class
Micky Hulse
2013-06-25 17:55:42 UTC
Permalink
Hello,

Currently, I have a setup for custom widgets where I create a simple
class for each new widget. For example:

class.widget_1.php
class.widget_2.php
class.widget_3.php
...

While the above works well, I'm finding that I'm repeating a little
bit of boilerplate code for each widget (even after extending an
abstract class with most of the boilerplate in that).

In an attempt to improve my code, and avoid repeating myself, I
created this class:

<https://gist.github.com/mhulse/5860561>

Inspired by WPAlchemy, I thought it would be cool to create my custom
widgets like so:

[code]

$medium_rectangle_1 = new foo_Widget(
array(
'id_base' => 'medium_rectangle_1',
'name' => 'Medium Rectangle 1',
'description' => 'Standard Advertising Unit',
'template' => STYLESHEETPATH .
'/includes/widgets/medium-rectangle-1.php',
)
);

[/code]

Unfortunately, I keep getting this PHP notice:

[snip]

Notice: Undefined property: Foo_Widget::$option_name in
/.../wp-includes/widgets.php on line 291 Warning: array_merge():
Argument #2 is not an array in /.../wp-includes/widgets.php on line
777

[/snip]

... and the widget does not show in the admin (well, there's an empty,
useless, widget box with no label).

Now, I know my code could use some more work (I'm kinda pushing the
limits of my WP/PHP skillz) ... I just wanted to see if anyone here
had any tips as to what I might be doing wrong?

Thanks!
M
Micky Hulse
2013-06-25 17:59:08 UTC
Permalink
On Tue, Jun 25, 2013 at 10:55 AM, Micky Hulse
Post by Micky Hulse
$medium_rectangle_1 = new foo_Widget(
Oops, typo: That should be "new Foo_Widget(...". With a capital "F".
Dobri
2013-06-25 18:11:55 UTC
Permalink
Kind of hard to debug your code having no idea what version of wordpress you're using. Someone would have to download your thing and run it himself to figure out what's going on. A version number would be helpful for on-the-fly debugging.

Also, Xdebug.

http://xdebug.org/

~Dobri
Post by Micky Hulse
Hello,
Currently, I have a setup for custom widgets where I create a simple
class.widget_1.php
class.widget_2.php
class.widget_3.php
...
While the above works well, I'm finding that I'm repeating a little
bit of boilerplate code for each widget (even after extending an
abstract class with most of the boilerplate in that).
In an attempt to improve my code, and avoid repeating myself, I
<https://gist.github.com/mhulse/5860561>
Inspired by WPAlchemy, I thought it would be cool to create my custom
[code]
$medium_rectangle_1 = new foo_Widget(
array(
'id_base' => 'medium_rectangle_1',
'name' => 'Medium Rectangle 1',
'description' => 'Standard Advertising Unit',
'template' => STYLESHEETPATH .
'/includes/widgets/medium-rectangle-1.php',
)
);
[/code]
[snip]
Notice: Undefined property: Foo_Widget::$option_name in
Argument #2 is not an array in /.../wp-includes/widgets.php on line
777
[/snip]
... and the widget does not show in the admin (well, there's an empty,
useless, widget box with no label).
Now, I know my code could use some more work (I'm kinda pushing the
limits of my WP/PHP skillz) ... I just wanted to see if anyone here
had any tips as to what I might be doing wrong?
Thanks!
M
_______________________________________________
wp-hackers mailing list
http://lists.automattic.com/mailman/listinfo/wp-hackers
Micky Hulse
2013-06-25 18:20:21 UTC
Permalink
Thanks for the feedback. I apologize for lack of WordPress version.

I'm running version 3.5.1.

I'll try to create a simple version of my code. I'm pretty sure I get
the same errors when I remove everything but the very basic code.

Thanks for the kick in the pants! :)

Micky
Post by Dobri
Kind of hard to debug your code having no idea what version of wordpress you're using. Someone would have to download your thing and run it himself to figure out what's going on. A version number would be helpful for on-the-fly debugging.
Also, Xdebug.
http://xdebug.org/
~Dobri
Post by Micky Hulse
Hello,
Currently, I have a setup for custom widgets where I create a simple
class.widget_1.php
class.widget_2.php
class.widget_3.php
...
While the above works well, I'm finding that I'm repeating a little
bit of boilerplate code for each widget (even after extending an
abstract class with most of the boilerplate in that).
In an attempt to improve my code, and avoid repeating myself, I
<https://gist.github.com/mhulse/5860561>
Inspired by WPAlchemy, I thought it would be cool to create my custom
[code]
$medium_rectangle_1 = new foo_Widget(
array(
'id_base' => 'medium_rectangle_1',
'name' => 'Medium Rectangle 1',
'description' => 'Standard Advertising Unit',
'template' => STYLESHEETPATH .
'/includes/widgets/medium-rectangle-1.php',
)
);
[/code]
[snip]
Notice: Undefined property: Foo_Widget::$option_name in
Argument #2 is not an array in /.../wp-includes/widgets.php on line
777
[/snip]
... and the widget does not show in the admin (well, there's an empty,
useless, widget box with no label).
Now, I know my code could use some more work (I'm kinda pushing the
limits of my WP/PHP skillz) ... I just wanted to see if anyone here
had any tips as to what I might be doing wrong?
Thanks!
M
_______________________________________________
wp-hackers mailing list
http://lists.automattic.com/mailman/listinfo/wp-hackers
_______________________________________________
wp-hackers mailing list
http://lists.automattic.com/mailman/listinfo/wp-hackers
--
http://hulse.me
Micky Hulse
2013-06-25 20:33:02 UTC
Permalink
On Tue, Jun 25, 2013 at 11:20 AM, Micky Hulse
Post by Micky Hulse
Thanks for the kick in the pants! :)
Well, here's a new version of my code:

https://gist.github.com/mhulse/5861847

I tried to boil it down to just the basics.

Now that I've simplified the code, I think I discovered a core problem:

----------

In Foo_Widget's constructor, this works:

parent::__construct('eeeeeeeeee', 'wtf son?', $widget_ops, $control_ops);

... but this does not:

parent::__construct($id_base, $name, $widget_ops, $control_ops);

Why can't I pass $id_base and $name as string variables to the parent
WP_Widget constructor?

----------

I feel like the above issue could be the root of my problems.

Another question:

----------

In Foo_Widget's constructor, if I do this:

... __construct($arr) ...

I get this PHP notice:

"Undefined variable: arr in /.../class.foo_widget.php on line 9".

If I change the constructor to this:

... __construct($arr = array()) ...

... the PHP notice goes away.

Why does this happen?

Shouldn't $arr be defined by the time it reaches line #9? Is this a WP
timing thing, or just a general PHP5 OOP constructor thing that I've
never been privy to? :D

I don't mind setting a default argument value here, it just feels
overkill and I've never run into this type of "notice" before.

----------

With all that said, I hope you folks can see what I'm trying to do.
Basically, I would like to wrap WP_Widget in a Class which has some
customizations, and then call my custom widget class like so:


[code]

include_once('class.foo_widget.php');

$foo_test_widget_1 = new Foo_Widget(
array(
'id_base' => 'foo_test_widget_1',
'name' => 'Foo Test Widget 1'
)
);

$foo_test_widget_2 = new Foo_Widget(
array(
'id_base' => 'foo_test_widget_2',
'name' => 'Foo Test Widget 2'
)
);

[/code]

... and so on.

Maybe what I'm trying to do isn't feasible? All the examples I've seen
show a new class for each new widget; this is what I'm doing now, and
that technique works great ... I just thought it would be even better
if I could create new widgets using the syntax above (i.e. one custom
widget class that extends WP_Widget where the name/title/other are
passed during instantiation).

I hope that helps to clarify what I'm trying to do.

I guess, at this point, I'm look for tips ... I feel like I'm close to
getting this code to work ... I'm kinda confused as to why I can't
seem to pass variables to the WP_Widget constructor but hard-coded
strings work no problems.

Thanks for listening.

Micky
Micky Hulse
2013-06-25 22:34:19 UTC
Permalink
Just as an update, a few folks have been helping me out in the
comments of my latest gist:

https://gist.github.com/mhulse/5861847

It's looking like it's not possible for me to instantiate my custom
widget in the way that I desire.

I guess I'll stick to the more standard way of creating widgets (e.g.
one class, that extends WP_Widget, per new custom widget).

Thanks for pro/guru help Dobri and JD, I really appreciate it!!!
Thanks to everyone for listening.

Have an excellent day.

Cheers,
Micky
Micky Hulse
2013-06-25 22:40:19 UTC
Permalink
Post by Micky Hulse
Thanks for pro/guru help Dobri and JD, I really appreciate it!!!
Ooops, I want to also thank Drew as well! :)
J.D. Grimes
2013-06-26 00:33:26 UTC
Permalink
Hey Micky, I was thinking about this and I think I've found a good solution for you. Just extend the Foo_Widget class with child classes like this:


class Foo_Widget_2 extends Foo_Widget {

function __construct() {

parent::__construct(
array(
'id_base' => 'foo_test_widget',
'name' => 'Foo Test Widget'
)
);
}
}

I've tested this and it works fine as far as I can tell.

J.D. Grimes
Post by Micky Hulse
Post by Micky Hulse
Thanks for pro/guru help Dobri and JD, I really appreciate it!!!
Ooops, I want to also thank Drew as well! :)
_______________________________________________
wp-hackers mailing list
http://lists.automattic.com/mailman/listinfo/wp-hackers
Micky Hulse
2013-06-26 01:55:11 UTC
Permalink
Hi J.D.! Thanks so much for the additional help! Totally unexpected but
much appreciated. :)
Interesting!

You know, that's not much more typing than my desired way of doing it.
I'll play around with your suggestion. :)

In fact, what you have posted is kinda close to my current setup:

<https://gist.github.com/mhulse/5864117>

(see "3. class.foo_widget_1.php",
https://gist.github.com/mhulse/5864117#file-3-class-foo_widget_1-php)

The above was about as modular as I could make it without doing a lot
of repeating of code.

Anyway, thanks for the tip off. I'll play with your idea. I like the
thought of using Foo_Widget() as the code is all in one class file
(compared to the code linked to above, which uses a few different
classes to do things ... Six of one, half dozen of the other, but I
think I'd prefer Foo_Widget() and extending like you show).

Thanks again! I'll be back with my updated code/findings. :)
Micky Hulse
2013-06-28 22:52:50 UTC
Permalink
Hi J.D.,

I finally had a chance to test your suggestion using my test
Foo_Widget class. Unfortunately, I'm getting the same results as
before.

[snip]

include_once('class.foo_widget.php');

class Foo_Widget_2 extends Foo_Widget {

function __construct() {

parent::__construct(
array(
'id_base' => 'foo_test_widget',
'name' => 'Foo Test Widget',
)
);

}
}

new Foo_Widget_2();

[/snip]

The above gets include_once into my functions.php.

This is the Foo_Widget() class (same one from before):

<https://gist.github.com/mhulse/5861847>

When I test the above code, I just see an empty widget under
"Available Widgets". When inspecting with Firebug, neither "id_base"
or "name" made it through.

If it's not too much trouble, could you confirm that the code you are
using is the same as the stuff I'm using?

If you got it to work, I must be doing something wrong (or, maybe I
need to upgrade to the latest WP? We're one version behind).

Thanks so much! I owe you one! :-)
J.D. Grimes
2013-06-29 13:04:41 UTC
Permalink
Hi Micky,

You need to register the widget with the register_widget() function like this:

function myplugin_register_widgets() {
register_widget( 'Foo_Widget_2' );
}
add_action( 'widgets_init', 'myplugin_register_widgets' );

Then it should work.

-J.D.
Post by Micky Hulse
Hi J.D.,
I finally had a chance to test your suggestion using my test
Foo_Widget class. Unfortunately, I'm getting the same results as
before.
[snip]
include_once('class.foo_widget.php');
class Foo_Widget_2 extends Foo_Widget {
function __construct() {
parent::__construct(
array(
'id_base' => 'foo_test_widget',
'name' => 'Foo Test Widget',
)
);
}
}
new Foo_Widget_2();
[/snip]
The above gets include_once into my functions.php.
<https://gist.github.com/mhulse/5861847>
When I test the above code, I just see an empty widget under
"Available Widgets". When inspecting with Firebug, neither "id_base"
or "name" made it through.
If it's not too much trouble, could you confirm that the code you are
using is the same as the stuff I'm using?
If you got it to work, I must be doing something wrong (or, maybe I
need to upgrade to the latest WP? We're one version behind).
Thanks so much! I owe you one! :-)
_______________________________________________
wp-hackers mailing list
http://lists.automattic.com/mailman/listinfo/wp-hackers
Micky Hulse
2013-06-29 18:17:16 UTC
Permalink
Post by J.D. Grimes
Then it should work.
Ahh, that makes sense. Thank you for the clarification, I really appreciate it.

I assumed that I did not need to register_widget() because I have that
in the class I'm extending.

add_action(
'widgets_init',
function() {
register_widget(__CLASS__);
}
);

Maybe if I passed __CLASS__ from the child class into the parent
class's register_widget()? I'll have to play around with that.

Either way, thanks to your help, I now have a better understanding of
WP widgets. Thanks so much for your help and guidance. :)

Thanks again to everyone who has given me help.

Cheers,
Micky
J.D. Grimes
2013-06-29 21:47:48 UTC
Permalink
Post by Micky Hulse
Maybe if I passed __CLASS__ from the child class into the parent
class's register_widget()? I'll have to play around with that.
I think you could do this instead of using __CLASS__:
$class = get_class( $this );
See here:
http://stackoverflow.com/a/1166592/1924128

I'm not sure if that works in all versions of PHP, but according to the poster there it works in 5.2.9.

-J.D.
Post by Micky Hulse
Post by J.D. Grimes
Then it should work.
Ahh, that makes sense. Thank you for the clarification, I really appreciate it.
I assumed that I did not need to register_widget() because I have that
in the class I'm extending.
add_action(
'widgets_init',
function() {
register_widget(__CLASS__);
}
);
Maybe if I passed __CLASS__ from the child class into the parent
class's register_widget()? I'll have to play around with that.
Either way, thanks to your help, I now have a better understanding of
WP widgets. Thanks so much for your help and guidance. :)
Thanks again to everyone who has given me help.
Cheers,
Micky
_______________________________________________
wp-hackers mailing list
http://lists.automattic.com/mailman/listinfo/wp-hackers
Micky Hulse
2013-06-29 22:15:26 UTC
Permalink
Post by J.D. Grimes
Post by Micky Hulse
Maybe if I passed __CLASS__ from the child class into the parent
class's register_widget()? I'll have to play around with that.
$class = get_class( $this );
http://stackoverflow.com/a/1166592/1924128
I'm not sure if that works in all versions of PHP, but according to the poster there it works in 5.2.9.
Ooooh, that's cool!

get_class($this) looks really convenient. I'll play around with that.

Thanks again J.D.! You rock! :)

Have an awesome weekend.

Cheers,
Micky
Nikola Nikolov
2013-06-30 06:33:39 UTC
Permalink
By the way you can also do the registration of all widgets in one function.
Store all of your widget classes in a static variable in your "Foo_Widget"
class - like "self::$registered_widgets[] = get_class( $this );"

And then you can add the action like this:

if ( ! has_action( 'widgets_init', array( 'Foo_Widget', 'register_widgets'
) ) ) {
add_action( 'widgets_init', array( 'Foo_Widget', 'register_widgets' ) );
}

And then in your static "register_widgets" function, you can loop through
"self::$registered_widgets" and call register_widget() with each class
name.

Of course, you'll have to define "$registered_widgets" as a static array in
your class first :)
Post by J.D. Grimes
Post by J.D. Grimes
Post by Micky Hulse
Maybe if I passed __CLASS__ from the child class into the parent
class's register_widget()? I'll have to play around with that.
$class = get_class( $this );
http://stackoverflow.com/a/1166592/1924128
I'm not sure if that works in all versions of PHP, but according to the
poster there it works in 5.2.9.
Ooooh, that's cool!
get_class($this) looks really convenient. I'll play around with that.
Thanks again J.D.! You rock! :)
Have an awesome weekend.
Cheers,
Micky
_______________________________________________
wp-hackers mailing list
http://lists.automattic.com/mailman/listinfo/wp-hackers
Micky Hulse
2013-06-30 07:05:01 UTC
Permalink
Post by Nikola Nikolov
By the way you can also do the registration of all widgets in one function.
Store all of your widget classes in a static variable in your "Foo_Widget"
class - like "self::$registered_widgets[] = get_class( $this );"
Oooh, that's a good idea! I'm looking forward to playing with this technique.

After I've experimented, I may be back with some questions. ;)

Thank you Nikola! I really appreciate the help!

Cheers,
Micky

Loading...