Does anyone know how can I add a custom product attribute with a widget renderer?
You can see this in Promo rules if you select SKU you'll got an Ajax popup with product selection.
so how would I go about it?
in :
$installer->addAttribute(Mage_Catalog_Model_Product::ENTITY...
In other words, how can I use a widget to select custom attribute values?
EDIT:
The scenario is as follows:
I would like to create a product attribute that will, upon a button click, open a product selection widget.
After the selection, the selected SKU's will go in in a comma delimited format.
This behavior can be seen in the catalog and shopping cart price rules.
If you filter the rule by SKU (SKU attribute must be enabled to "apply to rules"), you'll get a field and a button that will open the product selection widget.
Here is some thoughts that should get you going on the right track:
First, in a setup script, create your entity:
$installer->addAttribute('catalog_product', 'frontend_display', array(
'label' => 'Display Test',
'type' => 'varchar',
'frontend_model' => 'Test_Module/Entity_Attribute_Frontend_CsvExport',
'input' => 'select',
'required' => 0,
'user_defined' => false,
'group' => 'General'
));
Make sure to set the frontend_model to the model that you are going to use. The frontend model affects the display of the attribute (both in the frontend and the adminhtml sections).
Next, create yourself the class, and override one or both of the following functions:
public function getInputType()
{
return parent::getInputType();
}
public function getInputRendererClass()
{
return "Test_Module_Block_Adminhtml_Entity_Renderer_CsvExport";
}
The first (getInputType()) is used to change the input type to a baked in input type (see Varien_Data_Form_Element_* for the options). However, to set your own renderer class, use the latter function - getInputRendererClass(). That is what I am going to demonstrate below:
public function getElementHtml()
{
return Mage::app()->getLayout()->createBlock('Test_Module/Adminhtml_ExportCsv', 'export')->toHtml();
}
Here, to clean things up, I am instantiating another block, as the element itself doesn't have the extra functions to display buttons and the like.
Then finally, create this file:
class Test_Module_Block_Adminhtml_ExportCsv extends Mage_Adminhtml_Block_Widget
{
protected function _prepareLayout()
{
$button = $this->getLayout()->createBlock('adminhtml/widget_button')
->setData(array(
'label' => $this->__('Generate CSV'),
'onclick' => '',
'class' => 'ajax',
));
$this->setChild('generate', $button);
}
protected function _toHtml()
{
return $this->getChildHtml();
}
}
This doesn't cover the AJAX part, but will get you very close to getting the rest to work.
Related
I need to add some fields to prestashop product (HSN code and one more). I am very new to prestashop and there is no guide to do the same with latest build 1.7.
I have followed answers made on stackoverflow and I am able to show the form fields but unable to save and validate the value.
Here is the code snippet I have used (I preferred this because it uses the hooks).
use PrestaShopBundle\Form\Admin\Type\TranslateType;
use PrestaShopBundle\Form\Admin\Type\FormattedTextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
public function hookDisplayAdminProductsExtra($params)
{
$productAdapter = $this->get('prestashop.adapter.data_provider.product');
$product = $productAdapter->getProduct($params['id_product']);
$formData = [
'ebay_reference' => $product->ebay_reference,
];
$formFactory = $this->get('form.factory');
$form = $formFactory->createBuilder(FormType::class, $formData)
->add('ebay_reference', TranslateType::class, array(
'required' => false,
'label' => 'Ebay reference',
'locales' => Language::getLanguages(),
'hideTabs' => true,
'required' => false
))
->getForm()
;
return $this->get('twig')->render(_PS_MODULE_DIR_.'MyModule/views/display-admin-products-extra.html.twig', [
'form' => $form->createView()
]) ;
}
public function hookActionAdminProductsControllerSaveBefore($params)
{
$productAdapter = $this->get('prestashop.adapter.data_provider.product');
$product = $productAdapter->getProduct($_REQUEST['form']['id_product']);
foreach(Language::getLanguages() as $language){
$product->ebay_reference[ $language['id_lang'] ] =
$_REQUEST['form']['ebay_reference'][$language['id_lang']];
}
$product->save();
}
I am stucked at data saving part. Need some guidance to it in recommended way. Also need the suggestion to read the code of any module bundled with prestashop to help in this.
Add field in product Prestashop 1.7
This part of the code just describes how to create a form with necessary fields but it doesn't handle product class extending. So if you would have this attribute(ebay_reference) with all relations in your product class everything would work. So I suppose that you need to implement steps for /classes/Product.php and for src/PrestaShopBundle/Model/Product/AdminModelAdapter.php from the original answer of here Add field in product Prestashop 1.7 and add necessary field to the DB.
Also, if you don't want to modify or override default product class, you can create own table(s) to keep your data there like with id_product key, but it could be more difficult to propagate that data to all product instances in the store.
I'm creating a website using Drupal 8. I want to create a menu item link that I could add HTML/Javascript code in it (I'm trying to display a widget that expands on click in the menu rather than displaying it in its own block next to the menu). The only way I could see to add a menu item is to link to a page.
You could work with a derivative. This lets you customize pretty much everything about it and control what is to be made. An example below:
Note: I am assuming you have a general knowledge of custom modules. If not follow this link
Create the following file in your custom module:
# my_module.links.menu.yml
my_module.custom_links:
deriver: \Drupal\my_module\Plugin\Derivative\CustomLinkDerivative
And now for the derivative class (Located under my_module/src/Plugin/Derivative)
<?php
namespace Drupal\my_module\Plugin\Derivative;
use Drupal\Component\Plugin\Derivative\DeriverBase;
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class CustomLinkDerivative extends DeriverBase implements ContainerDeriverInterface {
public static function create(ContainerInterface $container, $base_plugin_id) {
return new static();
}
/**
* {#inheritdoc}
*/
public function getDerivativeDefinitions($base_plugin_definition) {
$links['custom_menulink'] = [
'title' => t('Custom menulink'),
'menu_name' => 'main',
'route_name' => 'entity.node.canonical',
'parent' => footer,
'route_parameters' => [
'node' => 1,
]
] + $base_plugin_definition;
return $links;
}
}
Note: Derivatives get triggered during rebuild of cache!
This just creates a link in the footer that directs to node 1. You can add all sort of stuff and logic to your liking. Hope this helps you :)
I'm planning to build an extension like Shopping Cart, Price Rule, or Catalog Price Rule.
I've already tried to learn something from existing Magento code, that you can see on:
app/code/core/Mage/Adminhtml/Block/Promo/Quote/Edit/Tab/Conditions.php
To show a Conditions Rule field, I've tried to add this script, but it didn't work properly
$fieldset->addField('conditions', 'text', array(
'name' => 'conditions',
'label' => Mage::helper('salesrule')->__('Conditions'),
'title' => Mage::helper('salesrule')->__('Conditions'),
))->setRule($model)->setRenderer(Mage::getBlockSingleton('rule/conditions'));
The question is:
How to display the conditional field properly on my custom field?
How to apply rule conditions on the front-end?
Thanks in advance.
update,
take a look at my screenshot
https://docs.google.com/file/d/0BwLN4KpQhoGbU181R0ZKanJSdVE/edit?usp=drivesdk
this is my form.php:
<?php
class KS_Kscoba_Block_Adminhtml_Tcoba_Edit_Tab_Form
extends Mage_Adminhtml_Block_Widget_Form
/*
extends Mage_Adminhtml_Block_Widget_Form
implements Mage_Adminhtml_Block_Widget_Tab_Interface
*/
{
protected function _prepareForm()
{
$model = Mage::registry('current_promo_quote_rule');
$form = new Varien_Data_Form();
$this->setForm($form);
$fieldset = $form->addFieldset("kscoba_form", array("legend"=>Mage::helper("kscoba")->__("Item information")));
$fieldset->addField("kolom1", "text", array(
"label" => Mage::helper("kscoba")->__("Kolom 1"),
"name" => "kolom1",
));
$fieldset->addField('kolom2', 'select', array(
'label' => Mage::helper('kscoba')->__('Kolom 2'),
'values' => KS_Kscoba_Block_Adminhtml_Tcoba_Grid::getValueArray1(),
'name' => 'kolom2',
));
/*
problem start here
*/
$renderer = Mage::getBlockSingleton('adminhtml/widget_form_renderer_fieldset')
->setTemplate('promo/fieldset.phtml')
->setNewChildUrl($this->getUrl('*/promo_quote/newConditionHtml/form/rule_conditions_fieldset'));
$fieldset = $form->addFieldset('conditions_fieldset', array(
'legend'=>Mage::helper('salesrule')->__('Apply the rule only if the following conditions are met (leave blank for all products)')
))->setRenderer($renderer);
$fieldset->addField('conditions', 'text', array(
'name' => 'conditions',
'label' => Mage::helper('salesrule')->__('Conditions'),
'title' => Mage::helper('salesrule')->__('Conditions'),
))->setRule($model)->setRenderer(Mage::getBlockSingleton('rule/conditions'));
if (Mage::getSingleton("adminhtml/session")->getTcobaData())
{
$form->setValues(Mage::getSingleton("adminhtml/session")->getTcobaData());
Mage::getSingleton("adminhtml/session")->setTcobaData(null);
}
elseif(Mage::registry("tcoba_data")) {
$form->setValues(Mage::registry("tcoba_data")->getData());
}
return parent::_prepareForm();
}
}
am I missing something?
1. Conditions Field
I may be overlooking another issue, but when I tested your form.php, the conditions field was missing because Mage::registry('current_promo_quote_rule') was undefined. The conditions field appeared on the page after I populated $model with a Mage_SalesRule_Model_Rule object.
Magento 1.8 registers the current_promo_quote_rule in _initRule() and editAction() of the Mage_Adminhtml_Promo_QuoteController (app/code/core/Mage/Adminhtml/controllers/Promo/QuoteController.php).
2. Frontend
Using shopping cart price rules as an example, the discounted price is applied in the frontend through the checkout module.
Mage/Checkout/controllers/CartController.php has a couponPostAction() function which is called when the user submits a coupon code from the cart or checkout page. This function gets the cart's Mage_Sales_Model_Quote object, sets the coupon code on that object, and refreshes the totals of each item using the collectTotals() function of Mage_Sales_Model_Quote.
The quote object's collectTotals() gets the related Mage_Sales_Model_Quote_Address objects and calls their collectTotals() functions. Those functions get each of the collector objects associated with the address and call its collect() method.
One of those collector objects is a Mage_SalesRule_Model_Quote_Discount, whose collect() method gets each Mage_Sales_Model_Quote_Item associated with this address, then calculates and stores its discount using a Mage_SalesRule_Model_Validator.
The specific logic in the conditions is read and applied deeper in the SalesRule module.
Background: In Drupal 7, I have created a form with CCK (aka the Field UI). I used the Field group module to create a fieldgroup, but I need it to be conditional, meaning it will only display depending on a previous answer.
Previous research: To create a conditional field, you can use hook_form_alter() to edit the #states attribute like so:
function MYMODULE_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'person_info_node_form') {
// Display 'field_maiden_name' only if married
$form['field_maiden_name']['#states'] = array(
'visible' => array(
':input[name="field_married[und]"]' => array('value' => 'Yes'),
),
);
}
}
However, there seems to be no way to use the States API for fieldgroups. One thing to note is that, while fields are stored in $form, fieldgroups are stored in $form['#groups'] as well as in $form['#fieldgroups']. I don't know how to distinguish between these, and with this in mind, I have tried to apply a #states attribute to a fieldgroup in the same manner as above. However, it only produces server errors.
Question: Is there a way to make a fieldgroup display conditionally using the States API or some alternative approach?
you have to use the hook_field_group_build_pre_render_alter()
Simply :
function your_module_field_group_build_pre_render_alter(&$element) {
$element['your_field_group']['#states'] = array(
'visible' => array(
':input[name="field_checkbox"]' => array('checked' => TRUE),
),
);
}
This works perfecly. If the group A is in an another group, do this
$element['groupA']['groupB']['#states'] etc....
You may need to add an id attribute if none exists:
$element['your_field_group']['#attributes']['id'] = 'some-id';
$element['yout_field_group']['#id'] = 'some-id';
Here's the simplest solution I came up with. There are essentially 2 parts to this: (1.) programmatically alter the display of the form, and (2.) use the GUI to alter the display of the content.
(1.) First, I used hook_form_alter() to programmatically create the conditional fieldset and add existing fields to it. The code is shown below.
function MYMODULE_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'FORM_ID_node_form') {
// programmatically create a conditional fieldset
$form['MYFIELDSET'] = array( // do NOT name the same as a 'Field group' fieldset or problems will occur
'#type' => 'fieldset',
'#title' => t('Conditional fieldset'),
'#weight' => intval($form['field_PARENT']['#weight'])+1, // put this fieldset right after it's "parent" field
'#states' => array(
'visible' => array(
':input[name="field_PARENT[und]"]' => array('value' => 'Yes'), // only show if field_PARENT == 'Yes'
),
),
);
// add existing fields (created with the Field UI) to the
// conditional fieldset
$fields = array('field_MYFIELD1', 'field_MYFIELD2', 'field_MYFIELD3');
$form = MYMODULE_addToFieldset($form, 'MYFIELDSET', $fields);
}
}
/**
* Adds existing fields to the specified fieldset.
*
* #param array $form Nested array of form elements that comprise the form.
* #param string $fieldset The machine name of the fieldset.
* #param array $fields An array of the machine names of all fields to
* be included in the fieldset.
* #return array $form The updated form.
*/
function MYMODULE_addToFieldSet($form, $fieldset, $fields) {
foreach($fields as $field) {
$form[$fieldset][$field] = $form[$field]; // copy existing field into fieldset
unset($form[$field]); // destroy the original field or duplication will occur
}
return $form;
}
(2.) Then I used the Field group module to alter the display of the content. I did this by going to my content type and using the 'Manage display' tab to create a field group and add my fields to it. This way, the fields will appear to be apart of the same group on both the form and the saved content.
Maybe you can try to look at the code of this module to help you find an idea.
In the magento system, I added the columns subscriber_firstname and subscriber_lastname to the newsletter_subscriber db table.
In the admin area of magento, I want the Newsletter>Newsletter Subscribers grid table to show:
customer first name if it exists, otherwise show newsletter_subscriber.subscriber_firstname if it exists, otherwise show nothing
customer last name if it exists, otherwise show newsletter_subscriber.subscriber_lastname if it exists, otherwise show nothing
Which magento files do I need to edit to make this work? How do I go about editing the files to make this work?
app/code/core/Mage/Adminhtml/Block/Newsletter/Subscriber/Grid.php
You'll want to condition this based off if subscriber_firstname or subscriber_lastname have values or not:
$this->addColumn('subscribername', array(
'header' => Mage::helper('newsletter')->__('Subscriber First Name'),
'index' => 'subscriber_firstname',
'default' => '----'
));
Also, make sure to make a copy of the core files and NOT edit them directly!
the quick and easy solution is to create a column render and select the correct field based on the subscriber type e.g.
app/code/local/Mage/Adminhtml/Block/Newsletter/Subscriber/Renderer/FirstName.php
class Mage_Adminhtml_Block_Newsletter_Subscriber_Renderer_FirstName extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Abstract {
public function render(Varien_Object $row) {
$value = '';
if ($row->getData('type') == 2) {
$value = $row->getData('customer_firstname');
}
else {
$value = $row->getData('subscriber_firstname');
}
return $value;
}
}
then add your render to a local copy of the subscriber grid class
app/code/local/Mage/Adminhtml/Block/Newsletter/Subscriber/Grid.php
$this->addColumn('firstname', array(
'header' => Mage::helper('newsletter')->__('First Name'),
'index' => 'customer_firstname',
'default' => '----',
'renderer' => 'Mage_Adminhtml_Block_Newsletter_Subscriber_Renderer_FirstName'
));
Note. the search and sort will not work on the subscriber name fields, to get this working you will need to extend app/code/core/Mage/Newsletter/Model/Mysql4/Subscriber/Collection.php