Remember in my last post when I said we would start reworking the multiline widget to display different content than it does out of the box?
I have a confession to make.
Before we can look into extending a view to do something new and interesting, we should first look into widget extension itself, and how the wizard works. While it is still possible to create a new widget without using the wizard, in the vast majority of cases, you will want to use this. It will create the scaffolding correctly for you, stub out methods for easy overriding and create the yui file for you. If you later decide you have to add more functionality to the widget (I actually needed to extend the logic file…or I need an AJAX endpoint in my controller) then you have two options, you can either update the other files and edit the yml file manually (later post), or you can back up the work you’ve done, delete your widget, create a new one, and replace the code you’ve already developed. In most cases, I would recommend this as constructing your own logic or controller extension file is something of a pain.
So, what should we expect from the widget wizard? Well, first you have to figure out if you’re going from scratch or extending a current widget.
It all starts here
If you’re old school, this is a pretty easy decision to understand. If you would go in and copy the Sample widget, rename it and then start creating your own view, logic and controller code, you’re going to want to select Create a New Widget. If, instead, you were going to go copy a widget to custom, rename it and then start tweaking, you’re going to want to select extend the widget. Details for creating a new widget may come in a future post, but for today, in order to get our feet wet with updating an existing widget, we’re going to select extend a widget.
Clicking this presents us with three input boxes, the first asks what widget we are extending. Just start typing the widget you want to use in, then select it from the drop down. Simple. Next, we are asked what we want to call our custom widget. There is code in the wizard that makes sure your widget name doesn’t already exist in the path you specify (more on that in the third field) and, should you accidentally be creating a duplicate widget, the system will save you from yourself and not let you create the widget. Finally, you’re asked what path you want to put the widget in. This is something of a change from the old file scheme, and generally a welcome one. All widgets must be nested in a folder, you can no longer create a widget at the root /custom/ level. This forces us to categorize our widgets. In the case of custom ones, this is generally pretty easy. In most cases, you will use the same subfolder in custom that you copied from in standard.
Major Decisions here
Next up we get to define the components of our new widget. As we are extending from another widget (in this case a ProductCategorySearchFilter widget) we have to tell the wizard what parts we want to extend. For anything server side, such as form submission, retrieving data from the database, writing data TO the database (usually db writes will happen as part of an AJAX based form submission), new data components being exposed to the view, or other server side actions, such as working with a session variable and data manipulation, we need to extend the controller. If you’re going to add new communication between front end and back end, such as looking something up from the DB based upon user interaction on the page, you will need to both extend the controller and select yes for the controller doing its own AJAX handling, which brings us into the second radio button. Spending a bit more time on the first though, the effect of selecting yes to the widget having its own controller is to cause the system to generate a controller file with a baseline constructor which pulls in all the code of its parent, and stubs for all of the methods of the controller allowing you to either add to, or override those methods. If you decide to override a method, bear in mind that future updates to that widget that touch those methods might impact your widget. RNT/Oracle will generally communicate in the patch notes if these updates are likely to impact custom code. If so, you can choose on a per widget basis not to go to the new widget version until you have sanity checked that your own widget does not break.
Next you need to select if your widget modifies the parent view. This is probably the most common type of edit you would do to a widget (outside of basic CSS restyling), though getting used to extending a view can take some effort. The recommended option is to extend the view. This allows you to add content to the widget between the block tags that exist within the parent widget. In cases of view code contained between block declarations in the view, this allows you to override that section of HTML/PHP. This takes some getting used to as some view code is not contained between blocks and has to, in my experience be duplicated within a block and then the original removed from the DOM using the logic file, but this allows you toÂ more cleanly edit the view without erasing the content already there. Short upshot of view extending, if you’re just adding content, you’re golden no matter what. If you’re changing content in the parent view, and that content exists between an opening and closing block tag, you can override it (more on this in the extending the view tutorial), and if it exists outside of an opening and closing block tag, you create your own DOM elements either before or after the element in question and then use JS to remove the original element from the DOM.
Your other option with a view modification is to override it. Use this option sparingly. There are two reasons for this. First, it obviously breaks the entire view for later inheritance. More importantly, however, it breaks the link to the logic file, forcing you to construct your own. This is likely due to the tight interaction between the DOM, generally presented by the view and the JS logic that acts on it with subscriptions, events, etc. For this reason, overriding the view will, in nearly all circumstances, cause functionality to fail and should generally be avoided.
View also asks you if you want to include the parent CSS. In most cases, you will want to do this (I don’t know why this isn’t defaulted to yes) as you will want to start from the basic look and feel and then potentially tweak the css from there. If you leave it set to no, the widget will not have its parent css applied and you will have to create your own styling from scratch.
Old school CP developers will remember attributes living in the Controller file. These days they exist in the YML file and can be manually added and edited there, however the widget allows you a user friendly mode of adding new attributes, for use by the controller, view or logic files. These populate to the ci/admin page for your widget and allow for easy reference of what attributes the widget has.
This final piece might not seem important at first, but two years later when you’re doing a code audit, you’ll be kicking yourself if you don’t pay special attention to the Additional Details drop down. This allows you to add a Widget description to the reference page. Here is where you are going to want to outline exactly what your widget does, and how it differs from the baseline widget. This will make it easy for you to go in on a code review and bring that widget up to standard as you will know where in the widget to look. Please don’t ever ignore this.
Finally, you will be presented with the following page showing you all the files you have created with the widget generator. Feel free to drop the widget onto your page now..it should be fully functional as-is…but it will be a clone of its parent. From here you can go into the view, the controller or the logic files (if you created them) and begin editing. Next up, we go in and look at one of those view extension files and talk about how we can modify the view of the widget we’re working with.