I added custom buttons to the panels ipe toolbar. The toolbar only shows when you have the right permissions, and when the page is a panelized page. I want to display the ipe toolbar also for other pages, containing that page his tabs (view/edit/devel/translate). Is it possible?
yes, this is possible. I had a similar need in one of my projects. What I did in a custom module was:
Use hook_page_alter to add the ipe toolbar when buttons DON'T exist (Panels IPE adds them when they do exist)
Use hook_theme_registry_alter to use my own template function instead of the one provided by Panels IPE.
Create a custom theme function that adds my custom buttons
In code it is something like this:
/**
* Implements of hook_page_alter()
*/
function MYMODULE_page_alter(&$page) {
// Check if Panels IPE is turned on.
if (!module_exists('panels_ipe'))
return;
// Let Panels IPE add the buttons if they exist > If there are no buttons
// then we'll still add the toolbar anyway.
$buttons = &drupal_static('panels_ipe_toolbar_buttons', array());
if (!empty($buttons)) {
return;
}
$output = theme('panels_ipe_toolbar', array('buttons' => $buttons));
$page['page_bottom']['panels_ipe'] = array(
'#markup' => $output,
);
}
/**
* Implements hook_theme_registry_alter().
*/
function MYMODULE_theme_registry_alter(&$theme_registry) {
// Check if Panels IPE is turned on.
if (!module_exists('panels_ipe'))
return;
// Inject our own theme function instead of the one from Panels IPE
$theme_registry['panels_ipe_toolbar']['function'] = 'theme_MYMODULE_panels_ipe_toolbar';
}
// This function is to be adjusted to add buttons and things.
function theme_MYMODULE_panels_ipe_toolbar($vars) {
$buttons = $vars['buttons'];
$output = "<div id='panels-ipe-control-container' class='clearfix'>";
foreach ($buttons as $key => $ipe_buttons) {
$output .= "<div id='panels-ipe-control-$key' class='panels-ipe-control'>";
// Controls in this container will appear when the IPE is not on.
$output .= '<div class="panels-ipe-button-container clearfix">';
foreach ($ipe_buttons as $button) {
$output .= is_string($button) ? $button : drupal_render($button);
}
$output .= '</div>';
// Controls in this container will appear when the IPE is on. It is usually
// filled via AJAX.
$output .= '<div class="panels-ipe-form-container clearfix"></div>';
$output .= '</div>';
}
$output .= "</div>";
return $output;
}
Related
I'm trying to develop a plugin in Moodle. One of the requirements is to add an element to the Settings Menu, in which I was able to achieve with the help of this guide
https://docs.moodle.org/dev/Local_plugins#Adding_an_element_to_the_settings_menu
And this is my code in local/myplugin/lib.php
<?php
function local_myplugin_extends_settings_navigation($settingsnav, $context) {
// question_extend_settings_navigation
global $CFG, $PAGE;
// Only add this settings item on non-site course pages.
if (!$PAGE->course or $PAGE->course->id == 1) {
return;
}
// Only let users with the appropriate capability see this settings item.
/*if (!has_capability('moodle/backup:backupcourse', context_course::instance($PAGE->course->id))) {
return;
}*/
if ($settingnode = $settingsnav->find('courseadmin', navigation_node::TYPE_COURSE)) {
$strfoo = get_string('classrecord', 'local_myplugin');
$url = new moodle_url('/course/classrecord.php', array('id' => $PAGE->course->id));
$foonode = navigation_node::create(
$strfoo,
$url,
navigation_node::NODETYPE_LEAF,
'myplugin',
'myplugin',
new pix_icon('i/grades', $strfoo)
);
if ($PAGE->url->compare($url, URL_MATCH_BASE)) {
$foonode->make_active();
}
$settingnode->add_node($foonode);
}
}
?>
I allowed the students to see the element "Class Record" in the settings menu
My concern is that how can I hide/show Class Record I added?
Any ideas would be great!
If you want only certain users to see the link, then create an appropriate capability in local/myplugin/db/access.php, e.g. 'local/myplugin:viewclassrecord', defaulting to being assigned to the 'student' role. Then check for it in the function you have defined.
e.g.
if (!has_capability('local/myplugin:viewclassrecord', $context)) {
return;
}
I want to customize the list view based on condition so i followed this blog to add where condition in list view
Developer Blog From Sugar where clause for sugar list-view pages
but after doing this i am not getting search options in my custom list view. Can any one guide me on this?
Following is the modified list view(i followed mentioned blog for this)
<?php
require_once('include/MVC/View/views/view.list.php');
require_once('custom/modules/Contacts/ContactsListViewSmarty.php');
class ContactsViewList extends ViewList
{
/**
* #see ViewList::preDisplay()
*/
var $where = "";
function AccountsViewList()
{
parent::ViewList();
}
public function preDisplay(){
require_once('modules/AOS_PDF_Templates/formLetter.php');
formLetter::LVPopupHtml('Contacts');
parent::preDisplay();
if($_GET['parentTab']=='Sales'){
$this->where .= "contacts.title ='IT Developer'";
}elseif ($_GET['parentTab']=='Marketing') {
$this->where .= "contacts.title ='Director Sales'";
}
$this->lv = new ContactsListViewSmarty();
}
function listViewProcess()
{
$this->lv->setup($this->seed, 'include/ListView/ListViewGeneric.tpl', $this->where, $this->params);
echo $this->lv->display();
}
}
You are using function AccountsViewList instead of ContactsViewList.
Also you will have to copy function prepareSearchForm() from include/MVC/View/views/view.list.php to show your search form.
$this->processSearchForm(); // for search form
$this->lv->searchColumns = $this->searchForm->searchColumns;
if(!$this->headers)
return;
if(empty($_REQUEST['search_form_only']) || $_REQUEST['search_form_only'] == false){
$this->lv->ss->assign("SEARCH",true);
$this->lv->setup($this->seed, 'include/ListView/ListViewGeneric.tpl', $this->where, $this->params); // call the listview's file
$savedSearchName = empty($_REQUEST['saved_search_select_name']) ? '' : (' - ' . $_REQUEST['saved_search_select_name']); // save the last search
echo $this->lv->display(); // display your search
this code should be in listViewProcess()
I want my main menu to not include any categories that are empty. I've done this for the layered navigation very easily in the relevant phtml file by using
$_category->getProductCount()
However, for the navigation menu, I'm finding it impossible to do this as easily (I have seen the Prattski example but it does seem rather OTT).
The main menu seems to be built in Mage_Page_Block_Html_Topmenu.php, specifically in the function _getHtml. This gets all the children in the menu and if I try something like $child->getId(), I get something like "category-node-36".
It doesn't seem like I'm too far from being able to use getProductCount() and so test if it's more than zero.
Is it possible to do this? Can somebody point me to how?
If I can, I'll extend the class with my version.
To do this, go to:
app/code/core/Mage/Catalog/Block Folder and copy Navigation.php and override it in your local package.
Open Navigation.php of your package and paste below code in this file:
if ($category->getIsActive()) {
$cat = Mage::getModel('catalog/category')->load($category->getId());
$products = Mage::getResourceModel('catalog/product_collection')->addCategoryFilter($cat);
Mage::getSingleton('catalog/product_status')->addVisibleFilterToCollection($products);
Mage::getSingleton('catalog/product_visibility')->addVisibleInCatalogFilterToCollection($products);
Mage::getSingleton('cataloginventory/stock')->addInStockFilterToCollection($products);
if(count($products)==0)
return;
}
I hope my code will help you.
I finally cracked it although I'm far from convinced it's an optimum solution. Anyway, I'll described what I did here and hopefully somebody can make it more efficient. I'll give a blow-by-blow description as I was ufamiliar with quite a few areas. So apologies for the length.
As I said, in my case at least, the main menu is built via Topmenu.php in app/code/core/Mage/Page/Block/Html, specifically the method _getHtml. I very definitely don't want to modify a core file so I found out how to extend this method via a new module. (You can skip this bit if you're familiar with creating new modules.)
Configuring a new module
I needed to create a new module (I'll call it MYMOD below). As I'm overwriting the core magento page block, I had to create new folders: app/code/local/MYMOD/Page and in there two sub-folders, Block and etc (I believe they are case sensitive). And within Block another subfolder Html. You can see this is exactly mirroring the folder structure from app/code/core/Mage.
The etc folder holds the specification for the new module in a config.xml file. This is what mine looks like:
<?xml version="1.0" encoding="UTF-8"?>
<!-- The root node for Magento module configuration -->
<config>
<!--
The module's node contains basic
information about each Magento module
-->
<modules>
<!--
This must exactly match the namespace and module's folder
names, with directory separators replaced by underscores
-->
<MYMOD_Page>
<!-- The version of our module, starting at 0.0.1 -->
<version>0.0.1</version>
</MYMOD_Page>
</modules>
<global>
<blocks>
<page>
<rewrite>
<html_topmenu>MYMOD_Page_Block_Html_Topmenu</html_topmenu>
</rewrite>
</page>
</blocks>
</global>
</config>
You can find out about the whys and wherefors of this elsewhere.
Unfortunately (in my opinion!), that's not all you have to do to specify a new module in Magento. You also have to create a file called "MYMOD_Page.xml" in app/etc/modules. This is just telling Magento about your module and where to look for it. Mine looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<modules>
<MYMOD_Page>
<!-- Whether our module is active: true or false -->
<active>true</active>
<!-- Which code pool to use: core, community or local -->
<codePool>local</codePool>
</MYMOD_Page>
</modules>
</config>
OK, sorry for the irrelevant instructions on modules but I do like self-contained blow-by-blow explanations.
Overwriting the method
I can now create a new file in my module with a subclass in which I can have methods (functions) that will be used instead of the core Magento ones. The file name has to be the same as the original file, Topmenu.php and it goes in app/code/local/MYMOD/Page/Block/Html.
Remember, the object oriented structure means that all of the functions in the original core version of Topmenu.php are available to me, I don't have to copy them in my new version (great for maintainability). My version of Topmenu.php only has to contain any new functions I might want (in this case I didn't need any) and redeclare any functions I want to overwite with my own version. In my case, I needed to modify two functions: _getHtml and _getMenuItemClasses.
_getHtml needs additional checks so any empty categories aren't included.
_getMenuItemClasses needs additional checks so that the class "parent" isn't added to categories whose children are empty.
Here's how I did it (with comments). I'm sure there are better ways but I'm still fairly new to Magento.
class MYMOD_Page_Block_Html_Topmenu extends Mage_Page_Block_Html_Topmenu
// Create my subclass, in accordance with how I've defined the new module
{
/**
* Recursively generates top menu html from data that is specified in $menuTree
*
* #param Varien_Data_Tree_Node $menuTree
* #param string $childrenWrapClass
* #return string
*/
protected function _getHtml(Varien_Data_Tree_Node $menuTree, $childrenWrapClass)
{
$html = '';
$children = $menuTree->getChildren();
$parentLevel = $menuTree->getLevel();
$childLevel = is_null($parentLevel) ? 0 : $parentLevel + 1;
$counter = 1;
$childrenCount = $children->count();
$parentPositionClass = $menuTree->getPositionClass();
$itemPositionClassPrefix = $parentPositionClass ? $parentPositionClass . '-' : 'nav-';
foreach ($children as $child) {
$child->setLevel($childLevel);
$child->setIsFirst($counter == 1);
$child->setIsLast($counter == $childrenCount);
$child->setPositionClass($itemPositionClassPrefix . $counter);
$outermostClassCode = '';
$outermostClass = $menuTree->getOutermostClass();
if ($childLevel == 0 && $outermostClass) {
$outermostClassCode = ' class="' . $outermostClass . '" ';
$child->setClass($outermostClass);
}
/*
* Find out if this category has any products. I don't know an easier way.
* The id of every child returned by getID is of the form "category-node-nnn"
* where nnn is the id that can be used to select the category details.
* substr strips everything leaving just the nnn.
* Then use getModel-> getCollection with a filter on the id. Although this looks
* like it will return many, obviously category ids are unique so in fact it only
* returns the category we're currently looking at.
*/
$_gcategoryId = substr($child->getId(), 14, 6);
$_gcategories = Mage::getModel('catalog/category')->getCollection()->addFieldToFilter('entity_id', array('eq', $_gcategoryId));
foreach ($_gcategories as $_gcategory) {
$_gcategoryCount = $_gcategory->getProductCount();
}
/*
* Now only include those categories that have products.
* In my case I also wanted to include the top level categories come what may.
*/
if (($childLevel == 0) || ($_gcategoryCount > 0)) {
$html .= '<li ' . $this->_getRenderedMenuItemAttributes($child) . '>';
$html .= '<a href="' . $child->getUrl() . '" ' . $outermostClassCode . '><span>'
. $this->escapeHtml($child->getName()) . '</span></a>';
if ($child->hasChildren()) {
if (!empty($childrenWrapClass)) {
$html .= '<div class="' . $childrenWrapClass . '">';
}
$html .= '<ul class="level' . $childLevel . '">';
$html .= $this->_getHtml($child, $childrenWrapClass);
$html .= '</ul>';
if (!empty($childrenWrapClass)) {
$html .= '</div>';
}
}
$html .= '</li>';
}
$counter++;
}
return $html;
}
/**
* Returns array of menu item's classes
*
* #param Varien_Data_Tree_Node $item
* #return array
*/
protected function _getMenuItemClasses(Varien_Data_Tree_Node $item)
{
$classes = array();
$classes[] = 'level' . $item->getLevel();
$classes[] = $item->getPositionClass();
if ($item->getIsFirst()) {
$classes[] = 'first';
}
if ($item->getIsActive()) {
$classes[] = 'active';
}
if ($item->getIsLast()) {
$classes[] = 'last';
}
if ($item->getClass()) {
$classes[] = $item->getClass();
}
if ($item->hasChildren()) {
/*
* Don't just check if there are children but, if there are, are they all empty?
* If so, then the changes in _getHtml will mean none of them will be included
* and so this one has no children displayed and so the "parent" class is not appropriate.
*/
$children = $item->getChildren(); // Get all the children from this menu category
foreach ($children as $child) { // Loop over each child and find out how many products (see _getHtml)
$_gcategoryId = substr($child->getId(), 14, 6);
$_gcategories = Mage::getModel('catalog/category')->getCollection()->addFieldToFilter('entity_id', array('eq', $_gcategoryId));
foreach ($_gcategories as $_gcategory) { // Remember, there's actually only one category that will match the child's id
$_gcategoryCount = $_gcategory->getProductCount();
}
if ($_gcategoryCount > 0) { // As soon as one child has products, then we have a parent and can stop looking
$classes[] = 'parent';
break;
}
}
}
return $classes;
}
}
I hope this is clear. It does what I want (my store is small) but any suggestions for improvement welcome.
path: app/design/frontend/rwd/default/template/page/html/topmenu/renderer.phtml
Make this query (it is 0.0004 sec), under the foreach ($children as $child) {
$mageconnection = Mage::getSingleton("core/resource")->getConnection("core_read");
$query="select count(cataloginventory_stock_item.is_in_stock) as subcount,catalog_category_flat_store_1.`name` from catalog_category_flat_store_1 INNER JOIN
catalog_category_product_index on catalog_category_product_index.category_id=catalog_category_flat_store_1.entity_id INNER JOIN
cataloginventory_stock_item on cataloginventory_stock_item.product_id=catalog_category_product_index.product_id
where cataloginventory_stock_item.is_in_stock=1 and catalog_category_product_index.category_id=";
$subCatqueryId = str_replace('category-node-', '', $child->getId());
$prodCollection = $mageconnection->fetchAll("$query'{$subCatqueryId}'");
if($prodCollection[0]["subcount"] > 0) {
$child->setLevel($childLevel);
$child->setIsFirst($counter == 1);
// these are the existing code ..
...
...
$counter++;
}
}
It is very fast and secure way to control product count.
I have 2 buttons with the same name. For design reasons only one of them is visible at the same time.
I want to click on any visible button.
If first button is hided this expression
$this->byCssSelector('[name="saveAndClose"]')->click()
returns
Element is not currently visible and so may not be interacted with
How to click on visible button?
I have written simple code to this.
public function clickOnDisplayedElementByName($name)
{
$elements = $this->elements($this->using('css selector')->value('[name="' . $name . '"]'));
foreach ($elements as $element)
{
if ($element->displayed())
{
$element->click();
return;
}
}
$this->fail('There is no visible elements with name ' . $name);
}
I am trying to implement embedded widget. Administrators will be able to configure this widget and embed it inside WYSIWYG editor. Two of the many configuration options are list of products that should show up on frontend and list of categories.
I want to allow this selection with "adminhtml/catalog_product_widget_chooser" and "adminhtml/catalog_category_widget_chooser". I tried to implement these widgets with sparse documentation available on the web but all I managed to accomplish is implementation for selecting one product or selecting one category. I need multiselect behavior.
As far as I can see no multiselection possibility is allowed by the current implementation. I checked code for both classes and grid.phtml template and it seams it is badly written and not extensible beyond current intention of use. For example this is how you would suppose to initialize helper block for a widget parameter to allow multiple select:
<helper_block>
<type>adminhtml/catalog_product_widget_chooser</type>
<data>
<button translate="open">
<open>Select Products...</open>
</button>
<use_massaction>1</use_massaction>
</data>
</helper_block>
But product chooser is hard coded for use without mass actions with this part of the code:
public function prepareElementHtml(Varien_Data_Form_Element_Abstract $element)
{
$uniqId = Mage::helper('core')->uniqHash($element->getId());
$sourceUrl = $this->getUrl('*/catalog_product_widget/chooser', array(
'uniq_id' => $uniqId,
'use_massaction' => false,
));
...
And grid.phtml template that is supposed to have some kind of button to confirm multiple selection is just showing "Search" and "Reset filter" buttons. And there is no handling of adding another button. For example here is the default code responsible for printing button html:
public function getMainButtonsHtml()
{
$html = '';
if($this->getFilterVisibility()){
$html.= $this->getResetFilterButtonHtml();
$html.= $this->getSearchButtonHtml();
}
return $html;
}
Only these two buttons are going to be printed by default.
So I started my own implementation based on two implementations mentioned above and it is getting ugly and could end up as an unmaintainable mess of copy-pasta. And I work by principle that if things start to look ugly then I am doing something wrong.
So is there a straightforward way to implement multiple product and multiple category selection on widget configuration screen by using grid widget?
I've found a quick way to get category multiselects on widget parameters using a source model based on adminhtml/system_config_source_category. I've removed the root-level filter and added indentation for subcategories.
widget.xml:
<widgets>
<my_widget type="mymodule/block" translate="name" module="mymodule">
<name>Widget with Multiselect Categories</name>
<parameters>
<category_ids translate="label description">
<visible>1</visible>
<required>1</required>
<label>Categories</label>
<type>multiselect</type>
<source_model>mymodule/system_config_source_category</source_model>
</category_ids>
</parameters>
</my_widget>
</widgets>
The source model:
class Mynamespace_Mymodule_Model_System_Config_Source_Category
{
public function toOptionArray()
{
$collection = Mage::getResourceModel('catalog/category_collection');
$collection->addAttributeToSelect('name')
->addFieldToFilter('path', array('neq' => '1'))
->load();
$options = array();
foreach ($collection as $category) {
$depth = count(explode('/', $category->getPath())) - 2;
$indent = str_repeat('-', max($depth * 2, 0));
$options[] = array(
'label' => $indent . $category->getName(),
'value' => $category->getId()
);
}
return $options;
}
}
The result:
Source: http://www.magentocommerce.com/knowledge-base/entry/tutorial-creating-a-magento-widget-part-2
I have added an answer to this question.
Implement multiple product chooser widget Magento
I have checked the Module that is under https://github.com/dio5/magento-multiproducts-widget.
Use the FORK option instead of Download ZIP.
It works and gives us the exact results i.e Multiple Products Selection in WIDGET. If there are any errors do let me know.
Let me know if that works for you.
Thanks!
[Editing my previous comment, upon request of code here directly]
/Namespace/Modulename/etc/widget.xml
<widgets>
<catalog_product_multiproducts type="namespace_modulename/widget_catalog_product_multiproducts" translate="name description" module="namespace_modulename">
<name>Catalog Multiple Products Widget</name>
<description>Select multiple products for display</description>
<parameters>
<title translate="label">
<visible>1</visible>
<label>Title</label>
<type>text</type>
</title>
<products_count translate="label">
<visible>1</visible>
<required>1</required>
<label>No of Products</label>
<type>text</type>
</products_count>
<ids translate="label">
<visible>1</visible>
<required>1</required>
<label>Products</label>
<type>label</type>
<helper_block>
<type>namespace_modulename/adminhtml_catalog_product_widget_multiproducts_chooser</type>
<data>
<button translate="open">
<open>Select Products...</open>
</button>
</data>
</helper_block>
<sort_order>10</sort_order>
</ids>
<template translate="label description">
<required>1</required>
<visible>1</visible>
<label>Product Carousel Template</label>
<type>text</type>
<value>catalog/product/widget/products_carousel.phtml</value>
<values>
<default translate="label"> <value>catalog/product/widget/products_carousel.phtml</value>
<label>New Products Grid Template</label>
</default>
<list translate="label">
<value>catalog/product/widget/new/content/new_list.phtml</value>
<label>New Products List Template</label>
</list>
</values>
<description>Template path cannot be changed/updated</description>
</template>
</parameters>
</catalog_product_multiproducts>
</widgets>
/NameSpace/ModuleName/Block/Adminhtml/Catalog/Product/MultiProducts/Chooser.php
This function will call the DOCHOOSE() function which will help "Choose" the checked/selected products.
/**
* prepare layout for products grid
*
* #return type Mage_Adminhtml_Block_Catalog_Product_Widget_Chooser
*/
protected function _prepareLayout()
{
$this->setChild('choose_button', $this->getLayout()->createBlock('adminhtml/widget_button')
->setData(array(
'label' => Mage::helper('adminhtml')->__('Choose Selected Products'),
'onclick' => $this->getJsObjectName() . '.doChoose()'
))
);
return parent::_prepareLayout();
}
The below function needs to be used to prepare the product element's HTML, in the format {1}{2}
/**
* Prepare chooser element HTML
*
* #param Varien_Data_Form_Element_Abstract $element Form Element
* #return Varien_Data_Form_Element_Abstract
*/
public function prepareElementHtml(Varien_Data_Form_Element_Abstract $element)
{
$uniqueId = Mage::helper('core')->uniqHash($element->getId());
$sourceUrl = $this->getUrl('*/multiproducts/chooser', array(
'uniq_id' => $uniqueId,
'use_massaction' => true,
));
$chooser = $this->getLayout()->createBlock('widget/adminhtml_widget_chooser')
->setElement($element)
->setTranslationHelper($this->getTranslationHelper())
->setConfig($this->getConfig())
->setFieldsetId($this->getFieldsetId())
->setSourceUrl($sourceUrl)
->setUniqId($uniqueId);
if ($element->getValue())
{
$label = "";
$ids = explode('}{', $element->getValue());
$cleanIds = array();
foreach ($ids as $id)
{
$id = str_replace('{', '', $id);
$id = str_replace('}', '', $id);
$cleanIds[] = $id;
}
$products = $this->_getProductsByIDs($cleanIds);
if ($products)
{
$label .= '<ul>';
foreach ($products as $product)
{
$label .= '<li>' . $product->getName() . '</li>';
}
$label .= '</ul>';
$chooser->setLabel($label);
}
}
$element->setData('after_element_html', $chooser->toHtml());
return $element;
}
JS for checkbox checked/unchecked
/**
* Checkbox Check JS Callback
*
* #return string
*/
public function getCheckboxCheckCallback()
{
if ($this->getUseMassaction())
{
return "function (grid, element) {
$(grid.containerId).fire('product:changed', {element: element});
}";
}
}
JS for Row/Product Clicked/Checked/Selected
/**
* Grid Row JS Callback
*
* #return string
*/
public function getRowClickCallback()
{
if (!$this->getUseMassaction())
{
$chooserJsObject = $this->getId();
return '
function (grid, event) {
var trElement = Event.findElement(event, "tr");
var productId = trElement.down("td").innerHTML;
var productName = trElement.down("td").next().next().innerHTML;
var optionLabel = productName;
var optionValue = "product/" + productId.replace(/^\s+|\s+$/g,"");
if (grid.categoryId) {
optionValue += "/" + grid.categoryId;
}
if (grid.categoryName) {
optionLabel = grid.categoryName + " / " + optionLabel;
}
' . $chooserJsObject . '.setElementValue(optionValue);
' . $chooserJsObject . '.setElementLabel(optionLabel);
' . $chooserJsObject . '.close();
}
';
}
}
JS code, if user is interested in selecting products from specific category.
/**
* Category Tree node onClick listener js function
*
* #return string
*/
public function getCategoryClickListenerJs()
{
$js = '
function (node, e) {
{jsObject}.addVarToUrl("category_id", node.attributes.id);
{jsObject}.reload({jsObject}.url);
{jsObject}.categoryId = node.attributes.id != "none" ? node.attributes.id : false;
{jsObject}.categoryName = node.attributes.id != "none" ? node.text : false;
}
';
$js = str_replace('{jsObject}', $this->getJsObjectName(), $js);
return $js;
}
Additional JS for preparing the POST element with product ids.
/**
* return additional JS for controls
*
* #return JS
*/
public function getAdditionalJavascript()
{
$chooserJsObject = $this->getId();
$js = '
{jsObject}.initChecked = function() {
$$("#' . $chooserJsObject . '_table tbody input:checkbox").each(function(element, i) {
var values = ' . $chooserJsObject . '.getElementValue();
var capture = values.replace("{"+element.value+"}", "match");
var searchValue = "match";
if(capture.search(searchValue) != -1)
{
element.checked = true;
}
});
}
{jsObject}.initChecked();
var values = ' . $chooserJsObject . '.getElementValue();
$("' . $chooserJsObject . '").insert({bottom: "<div class=\"filter\"><input type=\"hidden\" value=\"+values+\" name=\"selected_products\" /></div>"});
$$("#' . $chooserJsObject . '_table tbody input:checkbox").invoke("observe", "change", function(event) {
var element = Event.element(event);
var label = element.up("td").next().next().next().innerHTML;
label = label.replace(/^\s\s*/, "").replace(/\s\s*$/, "");
if(element.checked)
{
{jsObject}.addValue(element.value);
{jsObject}.addLabel(label);
} else {
{jsObject}.removeValue(element.value);
{jsObject}.removeLabel(label);
}
});
{jsObject}.removeValue = function(value) {
var currentValue = ' . $chooserJsObject . '.getElementValue();
currentValue = currentValue.replace("{"+value+"}", "");
' . $chooserJsObject . '.setElementValue(currentValue);
}
{jsObject}.addValue = function(value) {
var currentValue = ' . $chooserJsObject . '.getElementValue();
currentValue = currentValue.replace("{"+value+"}", "");
currentValue = currentValue + "{"+value+"}";
' . $chooserJsObject . '.setElementValue(currentValue);
}
{jsObject}.removeLabel = function(label) {
var currentLabel = ' . $chooserJsObject . '.getElementLabelText();
currentLabel = currentLabel.replace("<li>"+label+"</li>", "");
' . $chooserJsObject . '.setElementLabel(currentLabel);
}
{jsObject}.addLabel = function(label) {
var currentLabel = ' . $chooserJsObject . '.getElementLabelText();
if(currentLabel.search("ul") != -1)
{
currentLabel = currentLabel.replace("</ul>", "");
currentLabel = currentLabel.replace("<li>"+label+"</li>", "");
} else {
currentLabel = "<ul>";
}
currentLabel = currentLabel +"<li>"+label+"</li></ul>";
' . $chooserJsObject . '.setElementLabel(currentLabel);
}
{jsObject}.doChoose = function(node,e) {
' . $chooserJsObject . '.close();
}
';
$js = str_replace('{jsObject}', $this->getJsObjectName(), $js);
return $js;
}
The above are the major functions which will help you select multiple products from the GRID within a pop up.
There is a bit more to the code which can be checked here: https://github.com/dio5/magento-multiproducts-widget
Steps:
Navigate to a CMS Page in ADMIN panel
Click on "Insert Widget" in WYSIWYG editor
Select Widget Type - Catalog Multiple Products Widget
Enter Title, Products Count
Choose a template (One can add as many templates as required as an option)
Click on "Select Products" button
Select products from the GRID
Click on "Choose Selected Products" button
Hope this helps someone!
Happy Coding...
It looks as though you're not the first to go down the path of developing your own implementation for this.
David Manners appears to have tackled the same issue, with his Manners_Widgets.
Features of the Manners_Widgets Extension:
Multiple select for products and categories
I've not had contact with David, nor have I used this solution, so can't comment on quality (or completeness) of this code... but if you haven't already seen this solution, it might save you some time (or at worst, give you a point of contact for collaboration on this issue).
Hope this helps you, good luck with it!
Here's a quick fix: don't use the product widget chooser, but use a textfield instead that allows for comma separated SKUs.
Then in your code explode the skus and get the products by sku. Return that to your template. Much easier :)
Try to https://github.com/dio5/magento-multiproducts-widget.
It seems very useful.