0

I'm trying to implement a custom widget in wordpress 5.2.1, but the widget is not actually added to the sidebar and lost again after reload.

This is my widget code:


class DW_Center_Address_Widget extends WP_Widget {

    const ID = 'dw-center-address';

    var $formDefinition;

    function __construct() {

        parent::__construct(
            self::ID,
            // name of the widget
            Connector::get_translation('DW Center Address'),
            // widget options
            array (
                'description' => Connector::get_translation( 'Displays the address of a Center stored in the SSO.' )
            )
        );

        $this->formDefinition = [
            [
                'type' => 'info',
                'label' => Connector::get_translation("Change Center data at the:") . '<br/>' . '<a target="_blank" class="button" style="margin-top: 10px;" href="the.sso">' . Connector::get_translation('SSO') . '</a>'
            ],
            [
                'type' => 'text',
                'key' => Shortcodes::ATTR_SLUG,
                'id' => $this->get_field_id(Shortcodes::ATTR_SLUG),
                'name' => $this->get_field_name(Shortcodes::ATTR_SLUG),
                'label' => Connector::get_translation('Center Slug or Id'),
                'value' => '' // the default value
            ]
        ];

    }

    function form( $instance ) {
        for ($i = 0; $i < count($this->formDefinition); $i++) {
            if (array_key_exists('key', $this->formDefinition[$i])) {
                $key = $this->formDefinition[$i]['key'];

                if (array_key_exists($key, $instance)) {
                    $this->formDefinition[$i]['value'] = $instance[$this->formDefinition[$i]['key']];
                }
            }
        }

        // generates the form html
        echo Template::render('admin/forms/widget_form.html.twig', [
            'form' => $this->formDefinition
        ]);
    }

    function update( $new_instance, $old_instance ) {
        $instance = $old_instance;

        foreach ($this->formDefinition as $def) {
            if (array_key_exists('key', $def)) {
                $instance[ $def['key'] ] = trim($new_instance[ $def['key']]);
            }
        }

        return $instance;
    }

    function widget( $args, $instance ) {
        echo Shortcodes::dw_center($args);
    }

}

By everything I could see in other places, it should work, but it does not...

  • Any console errors? – WebElaine May 28 '19 at 15:14
  • Nope, all looks good - also the /wp-admin/admin-ajax.php returns a 200. – Andreas May 28 '19 at 23:46
0

Alright, so I found it after some sleepless hours:

  1. The call to $this->get_field_id($key) in the Widget constructor was a mistake. It has to happen during the function form() (probably due to some usage of global variables* )
  2. Most of the pain came from the fact, that it did not save the widget in the sidebar. The reason for this was, that it was all getting messed up during development in the database. Wordpress seems to expect a certain order between the id_base and the actual created instances in the database. If you want a clear picture, try to change the id_base to something fresh.

The working code in the end:

class DW_Center_Address_Widget extends WP_Widget {

    // I changed the id_base a couple of times
    const ID = 'dwbn-center-address-3';

    var $formDefinition;
    var $widgetArguments = [];

    function __construct() {
        //Constructor
        $widget_ops = array('classname' => self::ID, 'description' => Connector::get_translation( 'Displays the address of a Center stored in the SSO.' ) );
        parent::__construct( self::ID, Connector::get_translation('DW Center Address'), $widget_ops );

        $this->formDefinition = [
            // a title field makes the wordpress widget definetly more usefull, it will display this value in gray
            [
                'type' => 'text',
                'key' => Shortcodes::ATTR_TITLE,
                'label' => __('Title'), // just take the standard translation
                'value' => '' // the default value
            ],
            [
                'type' => 'info',
                'label' => Connector::get_translation("Change Center data at the:") . '<br/>' . '<a target="_blank" class="button" style="margin-top: 10px;" href="the.sso">' . Connector::get_translation('SSO') . '</a>'
            ],
            [
                'type' => 'text',
                'key' => Shortcodes::ATTR_SLUG,
                'label' => Connector::get_translation('Center Slug or Id'),
                'value' => '' // the default value
            ]
        ];

        foreach ($this->formDefinition as $def) {
            if (array_key_exists('key', $def)) {
                $this->widgetArguments[$def['key']] = array_key_exists('value', $def) ? $def['value'] : '';
            }
        }
    }

    /**
     * @param array $args - holds context information
     * @param array $instance - the actual parameters
     */
    function widget($args, $instance) {
        echo Shortcodes::dw_center($instance);
    }

    function update($new_instance, $old_instance) {
        $instance = [];

        foreach ($this->widgetArguments as $key => $val) {
            $instance[ $key ] = trim(strip_tags($new_instance[ $key ]));
        }

        return $instance;
    }

    function form( $instance ) {
        $instance = wp_parse_args( (array) $instance, $this->widgetArguments );
        $form = [];

        for ($i = 0; $i < count($this->formDefinition); $i++) {

            $form[] = $this->formDefinition[$i];

            if (array_key_exists('key', $form[$i])) {
                $key = $form[$i]['key'];

                if (array_key_exists($key, $instance)) {
                    $form[$i]['value'] = $instance[$key];
                }

                // it is important, that this functions are called during runtime, otherwise the widget ids will not be correct
                $form[$i]['id'] = $this->get_field_id($key);
                $form[$i]['name'] = $this->get_field_name($key);
            }
        }

        echo Template::render('admin/forms/widget_form.html.twig', [
            'form' => $form
        ]);

    }
}

* this is jet one more example why not to rely on a global namespace - wordpress will not change, but if you ever build a new system that millions of people will use, please try to avoid it ;).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.