3

I'm looking for a better way to create widgets dynamically for my plugin. I've read this article and I believe I've grasped the basic usage of how to create a custom widget.

Now my question is how I can create multiple widgets dynamically based on predefined options. One way I can think of is to use eval() to declare each extended class but as the class gets bigger, it would be too complicated. I don't think I can handle the php code passed as a function parameter; it's too much work to escape characters. Also it is said that using eval() is not safe and should be avoided if possible.

The code below is ready to run as a plugin. Just add a header comment and activate it and you'll see the two widgets are added.

add_action( 'widgets_init', 'load_mywidgets');
function load_mywidgets() {

    // prepare widgets
    $arrWidgets = array(
        array('id' => 'Bar', 'description' => 'This is a description for Bar', 'title' => 'This is Bar'),
        array('id' => 'Foo', 'description' => 'This is a description for Foo', 'title' => 'This is Foo')
    );

    // define widget class(es) 
    foreach ($arrWidgets as $arrWidget) {
        eval('
            class ' . $arrWidget["id"] . ' extends WP_Widget {

                function ' . $arrWidget["id"] . '() {
                    $widget_ops = array("classname" => "' . $arrWidget["id"] . '"
                                        , "description" => "' . $arrWidget["description"] . '" );
                    $this->WP_Widget("' . $arrWidget["id"] . '", "' . $arrWidget["title"] . '", $widget_ops);           
                }

                function form($instance) {
                    $instance = wp_parse_args( (array) $instance, array( "title" => "" ) );
                    $title = $instance["title"];
                    echo "<p><label for=\"" . $this->get_field_id("title") . "\">Title: <input class=\"widefat\" id=\"";
                    echo $this->get_field_id("title") . "\" name=\"" . $this->get_field_name("title") . "\" type=\"text\" value=\"" . attribute_escape($title) . "\" /></label></p>";
                }

                function update($new_instance, $old_instance) {
                    $instance = $old_instance;
                    $instance["title"] = $new_instance["title"];
                    return $instance;
                }

                function widget($args, $instance) {
                    extract($args, EXTR_SKIP);

                    echo $before_widget;
                    $title = empty($instance["title"]) ? " " : apply_filters("widget_title", $instance["title"]);

                    if (!empty($title))
                        echo $before_title . $title . $after_title;

                    // WIDGET CODE GOES HERE
                    echo "<h1>This is my new widget!</h1>";

                    echo $after_widget;
                }           
            }
        ');
        register_widget($arrWidget["id"]);
    }
}

Is there a simpler way of doing this? I think passing the options to the parameters of the constructor when instantiating the class much more makes sense. But as I view the core, the constructor is already defined and wondering how I can overwrite it. It appears that the WP_Widget is not designed to be instantiated.

Thanks for your info.

[Edit] Found a similar issue here: widget create dynamiclly in wordpress plugin But the suggested solution also uses eval() and basically it is the same way I presented above. As I keep reading the core, it appears register_widget() only accepts a class name for the parameter, calling WP_Widget_Factory::register(). So eval() may be the only way to do this. But it's not intuitive. I'm still looking for a simpler way of doing this.

Community
  • 1
  • 1
Teno
  • 2,582
  • 4
  • 35
  • 57
  • 1
    I think you are looking for a 'factory'. I haven't done it myself so I can't do much but point you to this: http://stackoverflow.com/questions/2083424/what-is-a-factory-design-pattern-in-php Maybe that will help. – s_ha_dum Oct 14 '12 at 15:41
  • Did you ever find a solution to this? Trying to do something similar. Thanks! – Daron Spence Oct 21 '14 at 06:19

0 Answers0