How To Add Attribute to Magento 2.1.x Product Page - customization

I hope this is a really simple question created only by my newb status to PhP and Magento.
Question: Given the details described below, in the catalog_product_view.xml first attribute. What should this be to ensure I get my custom attribute gsc_payment? I can everything to work using a built in attribute like UPC, but not my custom attribute.
I created a new attribute and made it visible on Magento's Products Page.
Attribute Code: gsc_payment
Default Label: ARC 90 Payment
I opened catalog_product_view.xml from
/home/XXXXXXXX/public_html/app/design/frontend/Venustheme/gosmart/Magento_Catalog/layout/catalog_product_view.xml and added the referenceContainer shown below.
<referenceContainer name="product.info.main">
<block class="Magento\Catalog\Block\Product\View\Description"
name="product.info.gsc"
template="Magento_Catalog::product/view/gsc.phtml"
after="product.info.upc">
<arguments>
<argument name="at_call" xsi:type="string">getGSC_Payment</argument>
<argument name="at_code" xsi:type="string">gsc_payment</argument>
<argument name="css_class" xsi:type="string">gsc_payment</argument>
<argument name="at_label" xsi:type="string">Arc 90 Payment:</argument>
<argument name="add_attribute" xsi:type="string">itemprop="gsc_payment"</argument>
</arguments>
</block>
</referenceContainer>
<referenceContainer name="product.info.main">
<block class="Ves\Themesettings\Block\Product\View" name="ves.product.info.main" template="Magento_Catalog::product/view/product_info_main.phtml">
<move element="product.info.sku" as="product_info_sku" destination="ves.product.info.main"/>
<move element="product.info.review" as="product_info_review" destination="ves.product.info.main"/>
<move element="product.price.final" as="product_price_final" destination="ves.product.info.main"/>
<move element="product.price.tier" as="product_price_tier" destination="ves.product.info.main"/>
<move element="alert.urls" as="alert_urls" destination="ves.product.info.main"/>
<move element="product.info" as="product_info" destination="ves.product.info.main"/>
<move element="product.info.overview" as="product_info_overview" destination="ves.product.info.main"/>
<move element="require-cookie" as="require_cookie" destination="ves.product.info.main"/>
<move element="product.info.extrahint" as="product_info_extrahint" destination="ves.product.info.main"/>
<move element="product.info.type" as="product_info_type" destination="ves.product.info.main"/>
</block>
</referenceContainer>
<container name="product.info.extrahint" as="extrahint" label="Product View Extra Hint">
<container name="product.info.social" label="Product social links container" after="product.info.overview">
<block class="Magento\Catalog\Block\Product\View" name="product.info.categories" template="product/view/categories.phtml"/>
</container>
I created a new file here /home/XXXXXXXXX/public_html/vendor/magento/module-catalog/view/frontend/templates/product/view/gsc.phtml with the following block code copied from internet.
<?php
$_helper = $this->helper('Magento\Catalog\Helper\Output');
$_product = $block->getProduct();
$_code = $block->getAtCode();
$_className = $block->getCssClass();
$_attributeLabel = $block->getAtLabel();
$_attributeType = $block->getAtType();
$_attributeAddAttribute = $block->getAddAttribute();
if ($_attributeLabel && $_attributeLabel == 'default') {
$_attributeLabel = $_product->getResource()->getAttribute($_code)->getFrontendLabel();
}
$_attributeValue =$_product->getResource()->getAttribute($_code)->getFrontend()->getValue($_product);
?>
<?php if ($_attributeValue): ?>
<div class="product attibute <?php echo $_className?>">
<?php if ($_attributeLabel != 'none'): ?><strong class="type"><?php echo $_attributeLabel?></strong><?php endif; ?>
<div class="value" <?php echo $_attributeAddAttribute;?>><?php echo $_attributeValue; ?></div>
</div>
<?php endif; ?>
I then opened /home/XXXXXXXXXXX/public_html/app/design/frontend/Venustheme/gosmart/Magento_Catalog/templates/product/view/product_info_main.phtml and added the following code inside the existing .
<div>
<table style="width: 100%; border-color: #ac1a2f; border-style: solid; border-width: 2px;">
<tbody>
<tr>
<td>
<p style="color: red; font-size: 300%; text-align: center;">Buy Today!</p>
<div style="color: green; font-size: 400%; text-align: center;">$
<?php echo $this->getChildHtml('product_info_gsc_payment') ?>
<?php echo "Hello"?>
<?php $_product = $block->getProduct();
echo $_product->getPrice();
echo $_product->getAttributeText('color');
?>
</div>
<p style="font-size: 150%; text-align: center;">bi-weekly/12 months</p>
<p style="color: red; font-size: 150%; text-align: center;">90 Days Same As Cash</p>
<p style="text-align: center;">20-25% Down Payment Required</p>
<p style="text-align: center;">Estimated Payment</p>
</td>
<td>
<div style="text-align: center;">
<p><img style="width: 25%; height: 25%;" src="https://1792armory.com/public/firearms/arc90_logo_big.png" border="0" /></p>
<p> <img style="align: center;" src="https://mail.globalcheck.com/images/qualify1.jpg" border="0" /> </p>
</div>
</td>
</tr>
</tbody>
</table>

You can create custom attribute using Setup/upgradeData.php
<?php
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
namespace Custom\Product\Setup;
use Magento\Framework\Setup\UpgradeDataInterface;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface;
class UpgradeData implements UpgradeDataInterface {
public function __construct(\Magento\Eav\Setup\EavSetupFactory $eavSetupFactory) {
$this->eavSetupFactory = $eavSetupFactory;
}
public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) {
$setup->startSetup();
$eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
if (version_compare($context->getVersion(), '2.1.24') < 0) {
$eavSetup->addAttribute(
\Magento\Catalog\Model\Product::ENTITY, 'product_height', [
'type' => 'varchar',
'label' => 'Product Height in cm',
'input' => 'text',
'required' => false,
'class' => '',
'backend' => '',
'source' => '',
'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL,
'visible' => true,
'user_defined' => false,
'searchable' => false,
'filterable' => false,
'filterable_in_search' => false,
'comparable' => false,
'visible_on_front' => false,
'unique' => false,
'group' => 'General',
'is_used_in_grid' => false,
'is_visible_in_grid' => false,
'is_filterable_in_grid' => true,
]
);
}
$setup->endSetup();
}
}
?>

Related

Regex to detect empty tags recursively

I need to detect all <p> tags that do not contain text, whatever the <p> tag contains other empty tags (such as <strong>, <em>, <span>...).
Then I need to replace the content of the <p> tag by a entity.
A few examples below :
1 - I want to transform the HTML below :
<p style="font-size: 16px;"></p>
in :
<p style="font-size: 16px;"> </p>
2 - I want to transform the HTML below :
<p style="font-size: 16px;"><em></em></p>
in :
<p style="font-size: 16px;"> </p>
3 - I want to transform the HTML below :
<p style="font-size: 16px;"><strong><em></em></strong></p>
in :
<p style="font-size: 16px;"> </p>
4 - I DON'T want to transform the HTML below :
<p style="font-size: 16px;"><em>lorem ipsum</em></p>
I've been able to build a regex which works only for a single tag (or none) contained in the <p> tag :
<p([^>]*)>(?:<[^\/>][^>]*><\/[^>]+>)?<\/p>
I don't find a way to make it work with several tags imbricated in the <p> tag (example 3).
Any idea ?
Use a beautiful DOM parser instead:
<?php
$data = <<<DATA
<div>
<p style="font-size: 16px;"></p>
<p style="font-size: 16px;"><em></em></p>
<p style="font-size: 16px;"> </p>
<p style="font-size: 16px;"><strong><em></em></strong></p>
<p style="font-size: 16px;"> </p>
<p style="font-size: 16px;"><em>lorem ipsum</em></p>
</div>
DATA;
$dom = new DOMDocument();
$dom->loadHTML($data, LIBXML_HTML_NOIMPLIED);
#$dom->removeChild($dom->doctype);
$xpath = new DOMXPath($dom);
$lines = $xpath->query("//p[not(normalize-space())]");
foreach ($lines as $line) {
while ($line->hasChildNodes()) {
$line->removeChild($line->firstChild);
}
$line->nodeValue = ' ';
}
echo $dom->saveHTML();
?>
See a demo on ideone.com.
This produces:
<div>
<p style="font-size: 16px;"> </p>
<p style="font-size: 16px;"> </p>
<p style="font-size: 16px;"> </p>
<p style="font-size: 16px;"> </p>
<p style="font-size: 16px;"> </p>
<p style="font-size: 16px;"><em>lorem ipsum</em></p>
</div>
You can easily accomplish it using JavaScript within a DOM structure, which by the way is much faster than using Regular Expressions, because regex parsing the whole string, when browsing in a DOM tree you are looking for an already parsed information (Element's data like textContent is a static data, and it is not calculated when you call it).
var elements = documnet.getElementsByTagName('p'), element, i;
for ( i in elements )
{
element = elements[i];
if ( element instanceof HTMLParagraphElement
&& !element.textContent.trim() )
{
element.innerHTML = ' ';
}
}
Good luck.

Why cart library is not working in codeigniter 3 when using MX hmvc?

Tryint to experiment the cart library, it is working ok without mx hmvc in in CI3. But as soon as i am inserting MX hmvc files (i.e MY_Loader.php and MY_Router.php in application/core folder and MX folder inside third_party folder) it is throwing error saying
Severity: Notice
Message: Undefined property: Welcome::$Session
Filename: MX/Loader.php
Line Number: 171
I am not even inside the modules just trying to use codeigniter's default controller and view.
My modified codeigniter's controller welcome.php is as below
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Welcome extends CI_Controller {
function __construct()
{
parent::__construct();
}
public function index()
{
$this->load->helper('form');
$this->load->helper('url');
// Load the cart library to use it.
$this->load->library('cart');
// Assuming this is the products from our database
$data['products'] = array(
array(
'id' => 'sku_888',
'qty' => 1,
'price' => 39.95,
'name' => 'T-Shirt',
'options' => array('Size' => 'xxx', 'Color' => 'White')
),
array(
'id' => 'sku_888',
'qty' => 1,
'price' => 39.95,
'name' => 'T-Shirt',
'options' => array('Size' => 'xx', 'Color' => 'green')
),
array(
'id' => 'sku_777',
'qty' => 1,
'price' => 9.95,
'name' => 'Coffee Mug'
),
array(
'id' => 'sku_666',
'qty' => 1,
'price' => 29.95,
'name' => 'Shot Glass'
)
);
// Insert the product to cart
if ($this->input->get('id') != '' && array_key_exists($this->input->get('id'), $data['products']))
{
$this->cart->insert($data['products'][$this->input->get('id')]);
}
// Lets update our cart
if ($this->input->post('update_cart'))
{
unset($_POST['update_cart']);
$contents = $this->input->post();
foreach ($contents as $content)
{
$info = array(
'rowid' => $content['rowid'],
'qty' => $content['qty']
);
$this->cart->update($info);
}
}
$this->load->view('welcome_message', $data);
}
}
and the default codeigniter view welcome_message.php, i modified as below
<b>Products</b>
<table width="100%" border="1">
<tr>
<td width="37%">ID</td>
<td width="30%">Name</td>
<td width="16%">Price</td>
<td width="16%"> </td>
</tr>
<?php $product_array_index = 0;?>
<?php foreach($products as $product):?>
<tr>
<td><?php echo $product['id'];?></td>
<td>
<?php
echo $product['name'] ;
if (array_key_exists('options', $product)) {
echo '<hr>';
foreach ($product['options'] as $key => $value)
{
echo '<strong>' . $key . '</strong> : '. $value . '<br/>';
}
}
?>
</td>
<td><?php echo $product['price'];?></td>
<td>Add to Cart</td>
</tr>
<?php $product_array_index ++;?>
<?php endforeach;?>
</table>
<hr>
<b>Your Cart</b>
<?php echo form_open(base_url()); ?>
<table cellpadding="6" cellspacing="1" style="width:100%" border="1">
<tr>
<th>QTY</th>
<th>Item Description</th>
<th style="text-align:right">Item Price</th>
<th style="text-align:right">Sub-Total</th>
</tr>
<?php $i = 1; ?>
<?php foreach ($this->cart->contents() as $items): ?>
<?php echo form_hidden($i.'[rowid]', $items['rowid']); ?>
<tr>
<td><?php echo form_input(array('name' => $i.'[qty]', 'value' => $items['qty'], 'maxlength' => '3', 'size' => '5')); ?></td>
<td>
<?php echo $items['name']; ?>
<?php if ($this->cart->has_options($items['rowid']) == TRUE): ?>
<p>
<?php foreach ($this->cart->product_options($items['rowid']) as $option_name => $option_value): ?>
<strong><?php echo $option_name; ?>:</strong> <?php echo $option_value; ?><br />
<?php endforeach; ?>
</p>
<?php endif; ?>
</td>
<td style="text-align:right"><?php echo $this->cart->format_number($items['price']); ?></td>
<td style="text-align:right">$<?php echo $this->cart->format_number($items['subtotal']); ?></td>
</tr>
<?php $i++; ?>
<?php endforeach; ?>
<tr>
<td colspan="2"></td>
<td class="right"><strong>Total</strong></td>
<td class="right" align="right">$<?php echo $this->cart->format_number($this->cart->total()); ?></td>
</tr>
</table>
<p><?php echo form_submit('update_cart', 'Update your Cart'); ?></p>
How to make it work?

Nokogiri parsing with xpath returns empty string

I have the following HTML:
<div>
<table>
<tr>
<td>
<div class="w135">
<div style="float: left; padding-right: 10px;" class="imageThumbnail playerDiv">
<a href="/sport/tennis/2014/10/djokovic-through-wozniacki-out-china-open-2014101114115427766.html" id="ctl00_ctl00_DataList1_ctl00_Thumbnail1_lnkImage10" target="_parent">
<img src="/mritems/imagecache/89/135/mritems/images/2014/10/1/2014101114447491734_20.jpg" id="ctl00_ctl00_DataList1_ctl00_Thumbnail1_imgSmall10" border="0" class="imageThumbnail">
</a>
</div>
</div>
</td>
</tr>
</table>
</div>
When i attempt the rake, i get the error:
NoMethodError: undefined method `at_css' for ["id","ctl00_cphBody_ctl01_DataList1_ctl00_Thumbnail1_Layout17"]:Array
This is the code:
#request = HTTParty.get(url)
#html = Nokogiri::HTML(#request.body)
#html.css(".w135")[0].map do |item|
url = item.at_css("div.playerDiv a")
puts url.inspect
end
I'm really not sure what the issue is and have been trying to fix this for a while. The error occurs on this line url = item.at_css("div.playerDiv a")
Any suggestion is appreciated!
Thanks
I'd do it using something like:
require 'nokogiri'
doc = Nokogiri::HTML(<<EOT)
<div>
<table>
<tr>
<td>
<div class="w135">
<div style="float: left; padding-right: 10px;" class="imageThumbnail playerDiv">
<a href="/sport/tennis/2014/10/djokovic-through-wozniacki-out-china-open-2014101114115427766.html" id="ctl00_ctl00_DataList1_ctl00_Thumbnail1_lnkImage10" target="_parent">
<img src="/mritems/imagecache/89/135/mritems/images/2014/10/1/2014101114447491734_20.jpg" id="ctl00_ctl00_DataList1_ctl00_Thumbnail1_imgSmall10" border="0" class="imageThumbnail">
</a>
</div>
</div>
</td>
</tr>
</table>
</div>
EOT
puts doc.search('.w135 div.playerDiv a').map(&:inspect)
Which outputs:
# >> #<Nokogiri::XML::Element:0x3ff0918b132c name="a" attributes=[#<Nokogiri::XML::Attr:0x3ff0918b1250 name="href" value="/sport/tennis/2014/10/djokovic-through-wozniacki-out-china-open-2014101114115427766.html">, #<Nokogiri::XML::Attr:0x3ff0918b123c name="id" value="ctl00_ctl00_DataList1_ctl00_Thumbnail1_lnkImage10">, #<Nokogiri::XML::Attr:0x3ff0918b1228 name="target" value="_parent">] children=[#<Nokogiri::XML::Text:0x3ff0918a5b6c "\n ">, #<Nokogiri::XML::Element:0x3ff0918a5360 name="img" attributes=[#<Nokogiri::XML::Attr:0x3ff0918a4d20 name="src" value="/mritems/imagecache/89/135/mritems/images/2014/10/1/2014101114447491734_20.jpg">, #<Nokogiri::XML::Attr:0x3ff0918a4cbc name="id" value="ctl00_ctl00_DataList1_ctl00_Thumbnail1_imgSmall10">, #<Nokogiri::XML::Attr:0x3ff0918a4b90 name="border" value="0">, #<Nokogiri::XML::Attr:0x3ff0918a4a28 name="class" value="imageThumbnail">]>, #<Nokogiri::XML::Text:0x3ff091871920 "\n ">]>
If you're trying to access the "href" parameter, instead of using inspect, use:
puts doc.search('.w135 div.playerDiv a').map{ |n| n['href'] }
# >> /sport/tennis/2014/10/djokovic-through-wozniacki-out-china-open-2014101114115427766.html

OpenCart render front-end

Hy all,
I'm trying to give users an confirmation message when they unsubscribe to an newsletter. But i'm only getting the confirmation message without the rest of the website.
Here's the url so you can see what's going on...
In the unsubscribe controller class i have this code to render the page:
$this->language->load('newsletter/unsubscribe');
$this->data['heading_title'] = $this->language->get('heading_title');
$this->data['breadcrumbs'] = array();
$this->data['breadcrumbs'][] = array(
'text' => $this->language->get('text_home'),
'href' => $this->url->link('common/home'),
'separator' => false
);
$this->template = 'default/template/newsletter/newsletter.tpl';
$this->children = array(
'common/column_left',
'common/column_right',
'common/content_top',
'common/content_bottom',
'common/footer',
'common/header'
);
$this->response->setOutput($this->render());
My template file looks like this:
<div class="box">
<div class="box-heading">Uitschrijven</div>
<div class="box-content">
<div id="notification">
<div class="success" style="">
U bent succesvol uitgeschreven.
<img src="catalog/view/theme/metroshop/image/close.png" alt="" class="close">
</div>
</div>
</div>
</div>
When i look at the other's ( the product controller or the account, and google ) it says that this is the right way to render the page ( with the childs like that ). But as you can see, the children ( the rest of the site ) isn't renderd.
What did i miss? Why isn't this working?
Alright, i've figured it out. I could delete my question, but mayby does this help others in the future so i'm answering it...
My template file looked like this:
<div class="box">
<div class="box-heading">Uitschrijven</div>
<div class="box-content">
<div id="notification">
<div class="success" style="">
U bent succesvol uitgeschreven.
<img src="catalog/view/theme/metroshop/image/close.png" alt="" class="close">
</div>
</div>
</div>
</div>
That's only the content. But you also need to echo the header, footer and all that kind of stuff. So you've got to do something like thisedi:
<?php echo $header; ?>
<?php echo $column_left; ?>
<?php echo $column_right; ?>
<div id="content">
<?php echo $content_top; ?>
<h1 style="display: none;">
<?php echo $heading_title; ?>
</h1>
<div class="box">
<div class="box-heading">Uitschrijven</div>
<div class="box-content">
<div id="notification">
<div class="success" style="">
U bent succesvol uitgeschreven.
<img src="catalog/view/theme/metroshop/image/close.png" alt="" class="close">
</div>
</div>
</div>
</div>
<?php echo $content_bottom; ?>
</div>
<?php echo $footer; ?>
And that's working fine now. Hope that this help's somebody in the future.

Opencart how to add product options into a tab

Opencart 1.5.3. Im trying to get the product options on the page to be displayed inside a tab. If I use the following code I get no errors and it looks fine, but clicking add to cart does nothing. If the code is outside the tab it works fine. Im not sure what Im doing wrong.
<div id="tabs_container">
<ul id="tabs">
<li class="active">tab1</li>
<li>tab2</li>
<li>tab3</li>
<li>tab4</li>
</ul>
</div>
<div id="tabs_content_container">
<div id="tab1" class="tab_content" style="display:block"></div><!--tab1-->
<div id="tab2" class="tab_content"></div><!--tab2-->
<div id="tab3" class="tab_content"></div><!--tab3-->
<div id="tab4" class="tab_content">
<?php if ($options) { ?>
<div class="options">
<h2><?php echo $text_option; ?></h2>
<br />
<?php foreach ($options as $option) { ?>
<?php if ($option['type'] == 'select') { ?>
<div id="option-<?php echo $option['product_option_id']; ?>" class="option">
<?php if ($option['required']) { ?>
<span class="required">*</span>
<?php } ?>
<b><?php echo $option['name']; ?>:</b><br />
<select name="option[<?php echo $option['product_option_id']; ?>]">
<option value=""><?php echo $text_select; ?></option>
<?php foreach ($option['option_value'] as $option_value) { ?>
<option value="<?php echo $option_value['product_option_value_id']; ?>"><?php echo $option_value['name']; ?>
<?php if ($option_value['price']) { ?>
(<?php echo $option_value['price_prefix']; ?><?php echo $option_value['price']; ?>)
<?php } ?>
</option>
<?php } ?>
</select>
</div>
<br />
<?php } ?>
<?php } ?>
</div>
</div><!--tab4-->
</div><!--tabs_content_container-->
Here is the javascript for the form submit that Opencart uses.
<script type="text/javascript"><!--
$('#button-cart').bind('click', function() {
$.ajax({
url: 'index.php?route=checkout/cart/add',
type: 'post',
data: $('.product-info input[type=\'text\'], .product-info input[type=\'hidden\'], .product-info input[type=\'radio\']:checked, .product-info input[type=\'checkbox\']:checked, .product-info select, .product-info textarea'),
dataType: 'json',
success: function(json) {
$('.success, .warning, .attention, information, .error').remove();
if (json['error']) {
if (json['error']['option']) {
for (i in json['error']['option']) {
$('#option-' + i).after('<span class="error">' + json['error']['option'][i] + '</span>');
}
}
}
if (json['success']) {
$('#notification').html('<div class="success" style="display: none;">' + json['success'] + '<img src="catalog/view/theme/default/image/close.png" alt="" class="close" /></div>');
$('.success').fadeIn('slow');
$('#cart-total').html(json['total']);
$('html, body').animate({ scrollTop: 0 }, 'slow');
}
}
});
});
//--></script>
The problem will be that the closing </form> tag won't be around the tab content. You need to move the </form> after your content and that should do it