diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php
index e054a9d49b437..817de6828e48d 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php
@@ -69,6 +69,7 @@ class Save extends Attribute
* @var LayoutFactory
*/
private $layoutFactory;
+
/**
* @var Presentation
*/
@@ -124,6 +125,7 @@ public function execute()
{
$data = $this->getRequest()->getPostValue();
if ($data) {
+ $this->preprocessOptionsData($data);
$setId = $this->getRequest()->getParam('set');
$attributeSet = null;
@@ -313,6 +315,28 @@ public function execute()
return $this->returnResult('catalog/*/', [], ['error' => true]);
}
+ /**
+ * Extract options data from serialized options field and append to data array.
+ *
+ * This logic is required to overcome max_input_vars php limit
+ * that may vary and/or be inaccessible to change on different instances.
+ *
+ * @param array $data
+ * @return void
+ */
+ private function preprocessOptionsData(&$data)
+ {
+ if (isset($data['serialized_options'])) {
+ $serializedOptions = json_decode($data['serialized_options'], JSON_OBJECT_AS_ARRAY);
+ foreach ($serializedOptions as $serializedOption) {
+ $option = [];
+ parse_str($serializedOption, $option);
+ $data = array_replace_recursive($data, $option);
+ }
+ }
+ unset($data['serialized_options']);
+ }
+
/**
* @param string $path
* @param array $params
diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/options.js b/app/code/Magento/Catalog/view/adminhtml/web/js/options.js
index 787516a9abf29..6ea005915763c 100644
--- a/app/code/Magento/Catalog/view/adminhtml/web/js/options.js
+++ b/app/code/Magento/Catalog/view/adminhtml/web/js/options.js
@@ -13,12 +13,16 @@ define([
'jquery/ui',
'prototype',
'form',
- 'validation'
+ 'validation',
+ 'mage/translate'
], function (jQuery, mageTemplate, rg) {
'use strict';
return function (config) {
- var attributeOption = {
+ var optionPanel = jQuery('#manage-options-panel'),
+ optionsValues = [],
+ editForm = jQuery('#edit_form'),
+ attributeOption = {
table: $('attribute-options-table'),
itemCount: 0,
totalItems: 0,
@@ -150,7 +154,7 @@ define([
attributeOption.remove(event);
});
- jQuery('#manage-options-panel').on('render', function () {
+ optionPanel.on('render', function () {
attributeOption.ignoreValidate();
if (attributeOption.rendered) {
@@ -176,7 +180,31 @@ define([
});
});
}
+ editForm.on('submit', function () {
+ optionPanel.find('input')
+ .each(function () {
+ if (this.disabled) {
+ return;
+ }
+ if (this.type === 'checkbox' || this.type === 'radio') {
+ if (this.checked) {
+ optionsValues.push(this.name + '=' + jQuery(this).val());
+ }
+ } else {
+ optionsValues.push(this.name + '=' + jQuery(this).val());
+ }
+ });
+ jQuery('')
+ .attr({
+ type: 'hidden',
+ name: 'serialized_options'
+ })
+ .val(JSON.stringify(optionsValues))
+ .prependTo(editForm);
+ optionPanel.find('table')
+ .replaceWith(jQuery('
').text(jQuery.mage.__('Sending attribute values as package.')));
+ });
window.attributeOption = attributeOption;
window.optionDefaultInputType = attributeOption.getOptionInputType();
diff --git a/app/code/Magento/Swatches/Controller/Adminhtml/Product/Attribute/Plugin/Save.php b/app/code/Magento/Swatches/Controller/Adminhtml/Product/Attribute/Plugin/Save.php
index dfda76372df1f..383c97a166d34 100644
--- a/app/code/Magento/Swatches/Controller/Adminhtml/Product/Attribute/Plugin/Save.php
+++ b/app/code/Magento/Swatches/Controller/Adminhtml/Product/Attribute/Plugin/Save.php
@@ -11,7 +11,7 @@
use Magento\Swatches\Model\Swatch;
/**
- * Class Save
+ * Plugin for product attribute save controller.
*/
class Save
{
@@ -24,7 +24,17 @@ class Save
public function beforeDispatch(Attribute\Save $subject, RequestInterface $request)
{
$data = $request->getPostValue();
+
if (isset($data['frontend_input'])) {
+ //Data is serialized to overcome issues caused by max_input_vars value if it's modification is unavailable.
+ //See subject controller code and comments for more info.
+ if (isset($data['serialized_swatch_values'])
+ && in_array($data['frontend_input'], ['swatch_visual', 'swatch_text'])
+ ) {
+ $data['serialized_options'] = $data['serialized_swatch_values'];
+ unset($data['serialized_swatch_values']);
+ }
+
switch ($data['frontend_input']) {
case 'swatch_visual':
$data[Swatch::SWATCH_INPUT_TYPE_KEY] = Swatch::SWATCH_INPUT_TYPE_VISUAL;
diff --git a/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js b/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js
index 1187e6bc4fdaa..01411523108cf 100644
--- a/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js
+++ b/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js
@@ -414,6 +414,8 @@ define([
};
$(function () {
+ var editForm = $('#edit_form');
+
$('#frontend_input').bind('change', function () {
swatchProductAttributes.bindAttributeInputType();
});
@@ -427,6 +429,34 @@ define([
$('.attribute-popup .collapse, [data-role="advanced_fieldset-content"]')
.collapsable()
.collapse('hide');
+
+ editForm.on('submit', function () {
+ var activePanel,
+ swatchValues = [],
+ swatchVisualPanel = $('#swatch-visual-options-panel'),
+ swatchTextPanel = $('#swatch-text-options-panel');
+
+ activePanel = swatchTextPanel.is(':visible') ? swatchTextPanel : swatchVisualPanel;
+
+ activePanel
+ .find('table input')
+ .each(function () {
+ swatchValues.push(this.name + '=' + $(this).val());
+ });
+
+ $('
')
+ .attr({
+ type: 'hidden',
+ name: 'serialized_swatch_values'
+ })
+ .val(JSON.stringify(swatchValues))
+ .prependTo(editForm);
+
+ [swatchVisualPanel, swatchTextPanel].forEach(function (el) {
+ $(el).find('table')
+ .replaceWith($('
').text($.mage.__('Sending swatch values as package.')));
+ });
+ });
});
window.saveAttributeInNewSet = swatchProductAttributes.saveAttributeInNewSet;
diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_authentication.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_authentication.less
index e1e23a9ffbb15..c5a26b3bc83ac 100644
--- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_authentication.less
+++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_authentication.less
@@ -25,6 +25,7 @@
padding: @block-auth__dropdown__padding;
}
}
+
.authentication-wrapper {
float: right;
margin-top: -1.5*@indent__xl;
diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payment-options.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payment-options.less
index 4e1156949de3a..3ce46a73a11c4 100644
--- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payment-options.less
+++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payment-options.less
@@ -198,6 +198,7 @@
.payment-option-title {
.lib-css(padding-left, @checkout-payment-option-content__padding__xl);
}
+
.payment-option-content {
.payment-option-inner {
+ .actions-toolbar {
diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping.less
index e7f0259fc9ce3..0a463a95e3182 100644
--- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping.less
+++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping.less
@@ -188,6 +188,7 @@
}
}
}
+
.row-error {
td {
border-top: none;
@@ -285,6 +286,7 @@
.lib-css(max-width, @checkout-shipping-address__max-width);
}
}
+
.table-checkout-shipping-method {
width: auto;
}
@@ -324,6 +326,7 @@
}
}
}
+
.table-checkout-shipping-method {
min-width: 500px;
}
diff --git a/app/design/frontend/Magento/blank/Magento_GiftRegistry/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_GiftRegistry/web/css/source/_module.less
index d05bcec38cbed..03a474012cb0c 100644
--- a/app/design/frontend/Magento/blank/Magento_GiftRegistry/web/css/source/_module.less
+++ b/app/design/frontend/Magento/blank/Magento_GiftRegistry/web/css/source/_module.less
@@ -15,6 +15,7 @@
.actions-toolbar:not(:last-child) {
margin-bottom: @indent__xl;
}
+
.fieldset {
.nested {
.field:not(.choice) {
diff --git a/app/design/frontend/Magento/blank/Magento_Multishipping/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Multishipping/web/css/source/_module.less
index 1e5769f3d7396..47dcd045ed46d 100644
--- a/app/design/frontend/Magento/blank/Magento_Multishipping/web/css/source/_module.less
+++ b/app/design/frontend/Magento/blank/Magento_Multishipping/web/css/source/_module.less
@@ -35,13 +35,16 @@
.shipping-item {
margin-left:84px;
}
+
.shipping-label {
font-weight: @font-weight__bold;
margin-right: @indent__s;
}
+
.shipping-address {
font-weight: @font-weight__regular;
}
+
.error-block {
color: @color-red10;
@@ -49,6 +52,7 @@
font-weight: @font-weight__bold;
margin-right: @indent__s;
}
+
.error-description {
font-weight: @font-weight__regular;
}
@@ -64,6 +68,7 @@
.order-id {
float:left;
}
+
.shipping-item {
margin-left:100px;
}
diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_shipping.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_shipping.less
index 512751df1cb35..d0ce87beb6ad3 100644
--- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_shipping.less
+++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_shipping.less
@@ -296,6 +296,7 @@
}
}
}
+
.opc-wrapper {
.form-login,
.form-shipping-address {
@@ -307,6 +308,7 @@
padding-bottom: @indent__base;
}
}
+
.table-checkout-shipping-method {
width: auto;
}
@@ -346,6 +348,7 @@
}
}
}
+
.table-checkout-shipping-method {
min-width: 500px;
}
diff --git a/app/design/frontend/Magento/luma/Magento_InstantPurchase/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_InstantPurchase/web/css/source/_module.less
index 9877f6bbcea23..230cce3a9aeff 100644
--- a/app/design/frontend/Magento/luma/Magento_InstantPurchase/web/css/source/_module.less
+++ b/app/design/frontend/Magento/luma/Magento_InstantPurchase/web/css/source/_module.less
@@ -1,16 +1,16 @@
& when (@media-common = true) {
- .box-tocart {
- .action.instant-purchase {
- &:extend(.abs-button-l all);
- &:extend(.abs-button-responsive all);
+ .box-tocart {
+ .action.instant-purchase {
+ &:extend(.abs-button-l all);
+ &:extend(.abs-button-responsive all);
- &:not(:last-child) {
- margin-bottom: 15px;
- }
+ &:not(:last-child) {
+ margin-bottom: 15px;
+ }
- vertical-align: top;
+ vertical-align: top;
+ }
}
- }
}
//
@@ -18,11 +18,11 @@
// _____________________________________________
.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
- .box-tocart {
- .action.instant-purchase {
- margin-bottom: 0;
- margin-right: 1%;
- width: 49%;
+ .box-tocart {
+ .action.instant-purchase {
+ margin-bottom: 0;
+ margin-right: 1%;
+ width: 49%;
+ }
}
- }
}
diff --git a/app/design/frontend/Magento/luma/Magento_Multishipping/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Multishipping/web/css/source/_module.less
index 03ff1fb09a3e4..4b5cd30a4a8ee 100644
--- a/app/design/frontend/Magento/luma/Magento_Multishipping/web/css/source/_module.less
+++ b/app/design/frontend/Magento/luma/Magento_Multishipping/web/css/source/_module.less
@@ -8,285 +8,290 @@
// _____________________________________________
& when (@media-common = true) {
- .multicheckout {
- &.results, &.success {
- h3 {
- font-size: 1.6rem;
- margin-bottom: @indent__base;
- margin-top: @indent__l;
- a {
- color: @text__color;
- &:hover {
- text-decoration: none;
- }
- }
- }
-
- ul.orders-list {
- list-style: none;
- padding-left: 0;
- }
-
- .orders-list {
- margin-top: @indent__m;
- padding-left: @indent__base - 4px;
-
- .shipping-list {
- .shipping-item {
- margin-left:84px;
- }
- .shipping-label {
- font-weight: @font-weight__bold;
- margin-right: @indent__s;
- }
- .shipping-address {
- font-weight: @font-weight__regular;
- }
- .error-block {
- color: @color-red10;
- .error-label {
- font-weight: @font-weight__bold;
- margin-right: @indent__s;
+ .multicheckout {
+ &.results, &.success {
+ h3 {
+ font-size: 1.6rem;
+ margin-bottom: @indent__base;
+ margin-top: @indent__l;
+ a {
+ color: @text__color;
+ &:hover {
+ text-decoration: none;
+ }
}
- .error-description {
- font-weight: @font-weight__regular;
+ }
+
+ ul.orders-list {
+ list-style: none;
+ padding-left: 0;
+ }
+
+ .orders-list {
+ margin-top: @indent__m;
+ padding-left: @indent__base - 4px;
+
+ .shipping-list {
+ .shipping-item {
+ margin-left:84px;
+ }
+
+ .shipping-label {
+ font-weight: @font-weight__bold;
+ margin-right: @indent__s;
+ }
+
+ .shipping-address {
+ font-weight: @font-weight__regular;
+ }
+
+ .error-block {
+ color: @color-red10;
+
+ .error-label {
+ font-weight: @font-weight__bold;
+ margin-right: @indent__s;
+ }
+
+ .error-description {
+ font-weight: @font-weight__regular;
+ }
+ }
}
- }
}
- }
- .orders-succeed {
- .orders-list {
- margin-top: 0;
+ .orders-succeed {
+ .orders-list {
+ margin-top: 0;
+
+ .shipping-list {
+ .order-id {
+ float:left;
+ }
+ .shipping-item {
+ margin-left:100px;
+ }
+ }
+ }
+ }
+ }
- .shipping-list {
- .order-id {
- float:left;
- }
- .shipping-item {
- margin-left:100px;
- }
+ .title {
+ margin-bottom: @indent__l;
+
+ strong {
+ font-weight: @font-weight__regular;
}
- }
}
- }
- .title {
- margin-bottom: @indent__l;
+ .table-wrapper {
+ margin-bottom: 0;
- strong {
- font-weight: @font-weight__regular;
- }
- }
+ .action.delete {
+ display: inline-block;
+ }
+
+ .col {
+ .qty {
+ display: inline-block;
+
+ .input-text {
+ &:extend(.abs-input-qty all);
+ }
+ }
- .table-wrapper {
- margin-bottom: 0;
+ .label {
+ &:extend(.abs-visually-hidden all);
+ }
- .action.delete {
- display: inline-block;
- }
+ &.item {
+ .action.edit {
+ font-weight: @font-weight__regular;
+ margin-left: @indent__s;
+ }
+ }
+ }
- .col {
- .qty {
- display: inline-block;
+ .cart-price {
+ &:extend(.abs-checkout-cart-price all);
+ }
- .input-text {
- &:extend(.abs-input-qty all);
- }
+ .product-item-name {
+ &:extend(.abs-checkout-product-name all);
+ }
}
- .label {
- &:extend(.abs-visually-hidden all);
+ &:not(.address) {
+ .table-wrapper {
+ .product-item-name {
+ margin: 0;
+ }
+ }
}
- &.item {
- .action.edit {
- font-weight: @font-weight__regular;
- margin-left: @indent__s;
- }
+ > .actions-toolbar {
+ margin-top: @indent__xl;
}
- }
- .cart-price {
- &:extend(.abs-checkout-cart-price all);
- }
+ .actions-toolbar {
+ > .secondary {
+ display: block;
- .product-item-name {
- &:extend(.abs-checkout-product-name all);
- }
- }
+ .action {
+ margin-bottom: @indent__m;
- &:not(.address) {
- .table-wrapper {
- .product-item-name {
- margin: 0;
- }
- }
- }
+ &.back {
+ display: block;
+ margin-left: 0;
+ }
+ }
+ }
- > .actions-toolbar {
- margin-top: @indent__xl;
- }
+ > .primary {
+ margin-right: @indent__s;
+ }
+ }
- .actions-toolbar {
- > .secondary {
- display: block;
+ .action.primary {
+ &:extend(.abs-button-l all);
+ }
- .action {
- margin-bottom: @indent__m;
+ .item-options {
+ margin: @indent__s 0 0;
- &.back {
- display: block;
- margin-left: 0;
- }
+ &:extend(.abs-product-options-list all);
+ &:extend(.abs-add-clearfix all);
}
- }
- > .primary {
- margin-right: @indent__s;
- }
- }
+ &:extend(.abs-account-blocks all);
- .action.primary {
- &:extend(.abs-button-l all);
- }
+ .block {
+ &:extend(.abs-add-clearfix all);
- .item-options {
- margin: @indent__s 0 0;
-
- &:extend(.abs-product-options-list all);
- &:extend(.abs-add-clearfix all);
- }
+ .methods-shipping {
+ .item-content {
+ .fieldset {
+ > .legend {
+ &:extend(.abs-visually-hidden all);
+ }
- &:extend(.abs-account-blocks all);
+ > .legend + br {
+ &:extend(.abs-no-display all);
+ }
- .block {
- &:extend(.abs-add-clearfix all);
+ > .field {
+ &:before {
+ display: none;
+ }
- .methods-shipping {
- .item-content {
- .fieldset {
- > .legend {
- &:extend(.abs-visually-hidden all);
+ .control {
+ display: inline-block;
+ }
+ }
+ }
+ }
}
+ }
- > .legend + br {
- &:extend(.abs-no-display all);
- }
+ .block-title,
+ .block-content .title {
+ &:extend(.abs-account-title all);
+ border-bottom: @border-width__base solid @border-color__base;
+ padding-bottom: @indent__s;
- > .field {
- &:before {
- display: none;
- }
+ strong {
+ font-weight: @font-weight__regular;
- .control {
- display: inline-block;
- }
+ span {
+ .lib-css(color, @primary__color__light);
+ }
}
- }
}
- }
- }
-
- .block-title,
- .block-content .title {
- &:extend(.abs-account-title all);
- border-bottom: @border-width__base solid @border-color__base;
- padding-bottom: @indent__s;
-
- strong {
- font-weight: @font-weight__regular;
- span {
- .lib-css(color, @primary__color__light);
+ .block-content {
+ &:extend(.abs-add-clearfix all);
+ .title {
+ border-bottom: none;
+ padding-bottom: 0;
+ }
}
- }
- }
- .block-content {
- &:extend(.abs-add-clearfix all);
- .title {
- border-bottom: none;
- padding-bottom: 0;
- }
- }
+ &.order-review {
+ .block-title > strong {
+ .lib-font-size(24);
+ }
- &.order-review {
- .block-title > strong {
- .lib-font-size(24);
- }
+ .block-shipping {
+ .block-content:not(:last-child) {
+ margin-bottom: @indent__xl;
+ }
+ }
- .block-shipping {
- .block-content:not(:last-child) {
- margin-bottom: @indent__xl;
+ .error-description {
+ color: @color-red10;
+ font-weight: @font-weight__regular;
+ margin-bottom: @indent__s;
+ margin-top: -@indent__s;
+ }
}
- }
- .error-description {
- color: @color-red10;
- font-weight: @font-weight__regular;
- margin-bottom: @indent__s;
- margin-top: -@indent__s;
- }
- }
-
- .box-title {
- span {
- margin-right: @indent__s;
- }
+ .box-title {
+ span {
+ margin-right: @indent__s;
+ }
- > .action {
- margin: 0;
- }
- }
+ > .action {
+ margin: 0;
+ }
+ }
- .box-shipping-method {
- .price {
- font-weight: @font-weight__bold;
- }
- }
+ .box-shipping-method {
+ .price {
+ font-weight: @font-weight__bold;
+ }
+ }
- .box-billing-method {
- .fieldset {
- margin: 0;
+ .box-billing-method {
+ .fieldset {
+ margin: 0;
- .legend.box-title {
- margin: 0 0 @indent__xs;
+ .legend.box-title {
+ margin: 0 0 @indent__xs;
+ }
+ }
}
- }
- }
- .hidden {
- &:extend(.abs-no-display all);
- }
+ .hidden {
+ &:extend(.abs-no-display all);
+ }
- .checkout-review .grand.totals {
- .lib-font-size(@font-size__xl);
- margin-bottom: @indent__xl;
+ .checkout-review .grand.totals {
+ .lib-font-size(@font-size__xl);
+ margin-bottom: @indent__xl;
- .mark {
- font-weight: @font-weight__regular;
- }
+ .mark {
+ font-weight: @font-weight__regular;
+ }
+ }
}
- }
- [class^='multishipping-'] {
- .nav-sections,
- .nav-toggle {
- &:extend(.abs-no-display all);
- }
+ [class^='multishipping-'] {
+ .nav-sections,
+ .nav-toggle {
+ &:extend(.abs-no-display all);
+ }
- .logo {
- margin-left: 0;
+ .logo {
+ margin-left: 0;
+ }
}
- }
- .multishipping-checkout-success {
- .nav-sections {
- display: block;
+ .multishipping-checkout-success {
+ .nav-sections {
+ display: block;
+ }
}
- }
}
//
@@ -294,200 +299,200 @@
// _____________________________________________
.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) {
- .multicheckout {
- .data.table {
- .address {
- &:before {
- margin-bottom: @indent__xs;
+ .multicheckout {
+ .data.table {
+ .address {
+ &:before {
+ margin-bottom: @indent__xs;
+ }
+ }
}
- }
- }
-
- .product-item-name,
- .price-including-tax,
- .price-excluding-tax {
- display: inline-block;
- }
- .block-content .box {
- &:not(:last-child) {
- margin-bottom: @indent__xl;
- }
+ .product-item-name,
+ .price-including-tax,
+ .price-excluding-tax {
+ display: inline-block;
+ }
- &:last-child {
- margin-bottom: 0;
- }
- }
+ .block-content .box {
+ &:not(:last-child) {
+ margin-bottom: @indent__xl;
+ }
- &.order-review {
- .box-items {
- .data.table {
- thead {
- display: block;
+ &:last-child {
+ margin-bottom: 0;
+ }
+ }
- tr {
- display: block;
+ &.order-review {
+ .box-items {
+ .data.table {
+ thead {
+ display: block;
+
+ tr {
+ display: block;
+ }
+
+ .col.item {
+ display: block;
+ padding: 0;
+ }
+ }
+ }
}
- .col.item {
- display: block;
- padding: 0;
+ .data.table {
+ &:extend(.abs-checkout-order-review all);
}
- }
}
- }
-
- .data.table {
- &:extend(.abs-checkout-order-review all);
- }
- }
- .actions-toolbar {
- .action {
- margin-bottom: @indent__m;
- }
+ .actions-toolbar {
+ .action {
+ margin-bottom: @indent__m;
+ }
- > .primary {
- margin-bottom: @indent__m;
- margin-right: 0;
- }
+ > .primary {
+ margin-bottom: @indent__m;
+ margin-right: 0;
+ }
+ }
}
- }
}
.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__s) {
- .multicheckout {
- .actions-toolbar {
- .column:not(.sidebar-main) & {
- &:extend(.abs-reset-left-margin-desktop-s all);
- }
+ .multicheckout {
+ .actions-toolbar {
+ .column:not(.sidebar-main) & {
+ &:extend(.abs-reset-left-margin-desktop-s all);
+ }
- .secondary {
- float: none;
- margin-top: 11px;
- text-align: right;
+ .secondary {
+ float: none;
+ margin-top: 11px;
+ text-align: right;
- .action {
- margin-left: @indent__s;
+ .action {
+ margin-left: @indent__s;
- &.back {
- display: block;
- float: left;
- }
+ &.back {
+ display: block;
+ float: left;
+ }
+ }
+ }
}
- }
- }
-
- .item-options {
- margin: @indent__base 0 0;
- }
-
- .block-content .box {
- margin-bottom: 0;
- }
- .block-shipping {
- .box {
- &:extend(.abs-add-box-sizing-desktop-s all);
- float: left;
- width: 25%;
- }
+ .item-options {
+ margin: @indent__base 0 0;
+ }
- .box-shipping-method {
- padding-left: @indent__m;
- padding-right: @indent__m;
- width: 50%;
+ .block-content .box {
+ margin-bottom: 0;
+ }
- .fieldset {
- .legend {
- &:extend(.abs-reset-left-margin-desktop-s all);
- }
+ .block-shipping {
+ .box {
+ &:extend(.abs-add-box-sizing-desktop-s all);
+ float: left;
+ width: 25%;
+ }
- .field {
- &:before {
- display: none;
+ .box-shipping-method {
+ padding-left: @indent__m;
+ padding-right: @indent__m;
+ width: 50%;
+
+ .fieldset {
+ .legend {
+ &:extend(.abs-reset-left-margin-desktop-s all);
+ }
+
+ .field {
+ &:before {
+ display: none;
+ }
+ }
+ }
}
- }
}
- }
- }
- .block-billing {
- &:extend(.abs-add-clearfix-desktop-s all);
- .box-billing-address {
- &:extend(.abs-add-box-sizing-desktop-s all);
- float: left;
- width: 25%;
- }
-
- .box-billing-method {
- &:extend(.abs-add-box-sizing-desktop-s all);
- float: left;
- padding-left: @indent__m;
- width: 50%;
- }
- }
+ .block-billing {
+ &:extend(.abs-add-clearfix-desktop-s all);
+ .box-billing-address {
+ &:extend(.abs-add-box-sizing-desktop-s all);
+ float: left;
+ width: 25%;
+ }
- &.form.address {
- .table-wrapper {
- .applicable {
- margin: 7px 0 0;
+ .box-billing-method {
+ &:extend(.abs-add-box-sizing-desktop-s all);
+ float: left;
+ padding-left: @indent__m;
+ width: 50%;
+ }
}
- }
- }
- &.order-review {
- .box-items {
- clear: left;
- float: none;
- padding-top: @indent__xl;
- width: auto;
- }
-
- .col.item {
- width: 75%;
- }
- }
+ &.form.address {
+ .table-wrapper {
+ .applicable {
+ margin: 7px 0 0;
+ }
+ }
+ }
- // Payment methods
- .methods-payment {
- .item-content > .fieldset {
- width: auto;
+ &.order-review {
+ .box-items {
+ clear: left;
+ float: none;
+ padding-top: @indent__xl;
+ width: auto;
+ }
- .field {
- &.cvv {
- display: inline-block;
- width: auto;
- }
+ .col.item {
+ width: 75%;
+ }
}
- }
- .fieldset > .field:not(.choice) {
- > .label {
- float: none;
- margin-bottom: 8px;
- text-align: left;
- width: auto;
- }
+ // Payment methods
+ .methods-payment {
+ .item-content > .fieldset {
+ width: auto;
+
+ .field {
+ &.cvv {
+ display: inline-block;
+ width: auto;
+ }
+ }
+ }
+
+ .fieldset > .field:not(.choice) {
+ > .label {
+ float: none;
+ margin-bottom: 8px;
+ text-align: left;
+ width: auto;
+ }
- &:not(.cvv) {
- .control {
- width: 100%;
- }
+ &:not(.cvv) {
+ .control {
+ width: 100%;
+ }
+ }
+ }
}
- }
}
- }
}
.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) {
- .multishipping-checkout-success {
- .nav-toggle {
- display: block;
- }
+ .multishipping-checkout-success {
+ .nav-toggle {
+ display: block;
+ }
- .logo {
- margin-left: @indent__xl;
+ .logo {
+ margin-left: @indent__xl;
+ }
}
- }
}
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php
index fdc85941b32e9..4261873cc8e6e 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php
@@ -5,6 +5,8 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product;
+use Magento\Framework\Exception\LocalizedException;
+
/**
* @magentoAppArea adminhtml
* @magentoDbIsolation enabled
@@ -224,6 +226,109 @@ public function testSaveActionCleanAttributeLabelCache()
$this->assertEquals('new string translation', $this->_translate('string to translate'));
}
+ /**
+ * Get attribute data preset.
+ *
+ * @return array
+ */
+ private function getLargeOptionsSetAttributeData()
+ {
+ return [
+ 'frontend_label' => [
+ 0 => 'testdrop1',
+ 1 => '',
+ 2 => '',
+ ],
+ 'frontend_input' => 'select',
+ 'is_required' => '0',
+ 'update_product_preview_image' => '0',
+ 'use_product_image_for_swatch' => '0',
+ 'visual_swatch_validation' => '',
+ 'visual_swatch_validation_unique' => '',
+ 'text_swatch_validation' => '',
+ 'text_swatch_validation_unique' => '',
+ 'attribute_code' => 'test_many_options',
+ 'is_global' => '0',
+ 'default_value_text' => '',
+ 'default_value_yesno' => '0',
+ 'default_value_date' => '',
+ 'default_value_textarea' => '',
+ 'is_unique' => '0',
+ 'is_used_in_grid' => '1',
+ 'is_visible_in_grid' => '1',
+ 'is_filterable_in_grid' => '1',
+ 'is_searchable' => '0',
+ 'is_comparable' => '0',
+ 'is_filterable' => '0',
+ 'is_filterable_in_search' => '0',
+ 'is_used_for_promo_rules' => '0',
+ 'is_html_allowed_on_front' => '1',
+ 'is_visible_on_front' => '0',
+ 'used_in_product_listing' => '0',
+ 'used_for_sort_by' => '0',
+ 'swatch_input_type' => 'dropdown',
+ ];
+ }
+
+ /**
+ * Test attribute saving with large amount of options exceeding maximum allowed by max_input_vars limit.
+ * @return void
+ */
+ public function testLargeOptionsDataSet()
+ {
+ $maxInputVars = ini_get('max_input_vars');
+ // Each option is at least 4 variables array (order, admin value, first store view value, delete flag).
+ // Set options count to exceed max_input_vars by 100 options (400 variables).
+ $optionsCount = floor($maxInputVars / 4) + 100;
+ $attributeData = $this->getLargeOptionsSetAttributeData();
+ $optionsData = [];
+ $expectedOptionsLabels = [];
+ for ($i = 0; $i < $optionsCount; $i++) {
+ $order = $i + 1;
+ $expectedOptionLabelOnStoreView = "value_{$i}_store_1";
+ $expectedOptionsLabels[$i+1] = $expectedOptionLabelOnStoreView;
+ $optionsData []= "option[order][option_{$i}]={$order}";
+ $optionsData []= "option[value][option_{$i}][0]=value_{$i}_admin";
+ $optionsData []= "option[value][option_{$i}][1]={$expectedOptionLabelOnStoreView}";
+ $optionsData []= "option[delete][option_{$i}=";
+ }
+ $attributeData['serialized_options'] = json_encode($optionsData);
+ $this->getRequest()->setPostValue($attributeData);
+ $this->dispatch('backend/catalog/product_attribute/save');
+ $entityTypeId = $this->_objectManager->create(
+ \Magento\Eav\Model\Entity::class
+ )->setType(
+ \Magento\Catalog\Model\Product::ENTITY
+ )->getTypeId();
+
+ /** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */
+ $attribute = $this->_objectManager->create(
+ \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class
+ )->setEntityTypeId(
+ $entityTypeId
+ );
+ try {
+ $attribute->loadByCode($entityTypeId, 'test_many_options');
+ $options = $attribute->getOptions();
+ // assert that all options are saved without truncation
+ $this->assertEquals(
+ $optionsCount + 1,
+ count($options),
+ 'Expected options count does not match (regarding first empty option for non-required attribute)'
+ );
+
+ foreach ($expectedOptionsLabels as $optionOrderNum => $label) {
+ $this->assertEquals(
+ $label,
+ $options[$optionOrderNum]->getLabel(),
+ "Label for option #{$optionOrderNum} does not match expected."
+ );
+ }
+ } catch (LocalizedException $e) {
+ $this->fail('Test failed with exception on attribute model load: ' . $e);
+ }
+ }
+
/**
* Return translation for a string literal belonging to backend area
*
diff --git a/dev/tests/integration/testsuite/Magento/Swatches/Controller/Adminhtml/Product/AttributeTest.php b/dev/tests/integration/testsuite/Magento/Swatches/Controller/Adminhtml/Product/AttributeTest.php
new file mode 100644
index 0000000000000..969d9530ae542
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Swatches/Controller/Adminhtml/Product/AttributeTest.php
@@ -0,0 +1,213 @@
+getRandomColor()}";
+ $optionsData []= "optionvisual[value][option_{$i}][0]=value_{$i}_admin";
+ $optionsData []= "optionvisual[value][option_{$i}][1]={$expectedOptionLabelOnStoreView}";
+ $optionsData []= "optionvisual[delete][option_{$i}]=";
+ }
+ $optionsData []= "visual_swatch_validation=";
+ $optionsData []= "visual_swatch_validation_unique=";
+ return [
+ 'attribute_data' => array_merge_recursive(
+ [
+ 'serialized_swatch_values' => json_encode($optionsData),
+ ],
+ $this->getAttributePreset(),
+ [
+ 'frontend_input' => 'swatch_visual'
+ ]
+ ),
+ 'expected_options_count' => $optionsCount + 1,
+ 'expected_store_labels' => $expectedOptionsLabels
+ ];
+ }
+
+ /**
+ * Get text swatches data set.
+ *
+ * @param int $optionsCount
+ * @return array
+ */
+ private function getSwatchTextDataSet(int $optionsCount) : array
+ {
+ $optionsData = [];
+ $expectedOptionsLabels = [];
+ for ($i = 0; $i < $optionsCount; $i++) {
+ $order = $i + 1;
+ $expectedOptionLabelOnStoreView = "value_{$i}_store_1";
+ $expectedOptionsLabels[$i+1] = $expectedOptionLabelOnStoreView;
+ $optionsData []= "optiontext[order][option_{$i}]={$order}";
+ $optionsData []= "defaulttext[]=option_{$i}";
+ $optionsData []= "swatchtext[value][option_{$i}]=x{$i}";
+ $optionsData []= "optiontext[value][option_{$i}][0]=value_{$i}_admin";
+ $optionsData []= "optiontext[value][option_{$i}][1]={$expectedOptionLabelOnStoreView}";
+ $optionsData []= "optiontext[delete][option_{$i}]=";
+ }
+ $optionsData []= "text_swatch_validation=";
+ $optionsData []= "text_swatch_validation_unique=";
+ return [
+ 'attribute_data' => array_merge_recursive(
+ [
+ 'serialized_swatch_values' => json_encode($optionsData),
+ ],
+ $this->getAttributePreset(),
+ [
+ 'frontend_input' => 'swatch_text'
+ ]
+ ),
+ 'expected_options_count' => $optionsCount + 1,
+ 'expected_store_labels' => $expectedOptionsLabels
+ ];
+ }
+
+ /**
+ * Get data preset for new attribute.
+ *
+ * @return array
+ */
+ private function getAttributePreset() : array
+ {
+ return [
+ 'serialized_options' => '[]',
+ 'form_key' => 'XxtpPYjm2YPYUlAt',
+ 'frontend_label' => [
+ 0 => 'asdasd',
+ 1 => '',
+ 2 => '',
+ ],
+ 'is_required' => '0',
+ 'update_product_preview_image' => '0',
+ 'use_product_image_for_swatch' => '0',
+ 'is_global' => '0',
+ 'default_value_text' => '512',
+ 'default_value_yesno' => '1',
+ 'default_value_date' => '1/1/70',
+ 'default_value_textarea' => '512',
+ 'is_unique' => '0',
+ 'is_used_in_grid' => '1',
+ 'is_visible_in_grid' => '1',
+ 'is_filterable_in_grid' => '1',
+ 'is_searchable' => '0',
+ 'is_comparable' => '0',
+ 'is_filterable' => '0',
+ 'is_filterable_in_search' => '0',
+ 'position' => '0',
+ 'is_used_for_promo_rules' => '0',
+ 'is_html_allowed_on_front' => '1',
+ 'is_visible_on_front' => '0',
+ 'used_in_product_listing' => '0',
+ 'used_for_sort_by' => '0',
+ 'attribute_code' => 'test_many_swatches',
+ ];
+ }
+
+ /**
+ * Data provider for large swatches amount test.
+ *
+ * @return array
+ */
+ public function getLargeSwatchesAmountAttributeData() : array
+ {
+ $maxInputVars = ini_get('max_input_vars');
+ // Each option is at least 7 variables array for a visual swatch.
+ // Set options count to exceed max_input_vars by 20 options (140 variables).
+ $swatchVisualOptionsCount = (int)floor($maxInputVars / 7) + 20;
+ $swatchTextOptionsCount = (int)floor($maxInputVars / 4) + 80;
+ return [
+ 'visual swatches' => $this->getSwatchVisualDataSet($swatchVisualOptionsCount),
+ 'text swatches' => $this->getSwatchTextDataSet($swatchTextOptionsCount)
+ ];
+ }
+
+ /**
+ * Test attribute saving with large amount of options exceeding maximum allowed by max_input_vars limit.
+ * @dataProvider getLargeSwatchesAmountAttributeData()
+ * @param array $attributeData
+ * @param int $expectedOptionsCount
+ * @param array $expectedLabels
+ * @return void
+ */
+ public function testLargeOptionsDataSet(
+ array $attributeData,
+ int $expectedOptionsCount,
+ array $expectedLabels
+ ) : void {
+ $this->getRequest()->setPostValue($attributeData);
+ $this->dispatch('backend/catalog/product_attribute/save');
+ $entityTypeId = $this->_objectManager->create(
+ \Magento\Eav\Model\Entity::class
+ )->setType(
+ \Magento\Catalog\Model\Product::ENTITY
+ )->getTypeId();
+
+ /** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */
+ $attribute = $this->_objectManager->create(
+ \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class
+ )->setEntityTypeId(
+ $entityTypeId
+ );
+ try {
+ $attribute->loadByCode($entityTypeId, 'test_many_swatches');
+ $options = $attribute->getOptions();
+ // assert that all options are saved without truncation
+ $this->assertEquals(
+ $expectedOptionsCount,
+ count($options),
+ 'Expected options count does not match (regarding first empty option for non-required attribute)'
+ );
+
+ foreach ($expectedLabels as $optionOrderNum => $label) {
+ $this->assertEquals(
+ $label,
+ $options[$optionOrderNum]->getLabel(),
+ "Label for option #{$optionOrderNum} does not match expected."
+ );
+ }
+ } catch (LocalizedException $e) {
+ $this->fail('Test failed with exception on attribute model load: ' . $e);
+ }
+ }
+}
diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/HhvmCompatibilityTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/HhvmCompatibilityTest.php
index e33b771b3c645..c552e0daa97df 100644
--- a/dev/tests/static/testsuite/Magento/Test/Integrity/HhvmCompatibilityTest.php
+++ b/dev/tests/static/testsuite/Magento/Test/Integrity/HhvmCompatibilityTest.php
@@ -47,6 +47,24 @@ class HhvmCompatibilityTest extends \PHPUnit\Framework\TestCase
'serialize_precision',
];
+ /**
+ * Whitelist of variables allowed in files.
+ *
+ * @var array
+ */
+ private $whitelistVarsInFiles = [
+ 'max_input_vars' => [
+ 'integration/testsuite/Magento/Swatches/Controller/Adminhtml/Product/AttributeTest.php',
+ 'integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php',
+ ]
+ ];
+
+ /**
+ * Test allowed directives.
+ *
+ * @SuppressWarnings(PHPMD.NPathComplexity)
+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+ */
public function testAllowedIniGetSetDirectives()
{
$deniedDirectives = [];
@@ -55,7 +73,19 @@ public function testAllowedIniGetSetDirectives()
if ($fileDirectives) {
$fileDeniedDirectives = array_diff($fileDirectives, $this->allowedDirectives);
if ($fileDeniedDirectives) {
- $deniedDirectives[$file] = array_unique($fileDeniedDirectives);
+ $deniedDirectivesInFile = array_unique($fileDeniedDirectives);
+ foreach ($deniedDirectivesInFile as $key => $deniedDirective) {
+ if (isset($this->whitelistVarsInFiles[$deniedDirective])) {
+ foreach ($this->whitelistVarsInFiles[$deniedDirective] as $whitelistFile) {
+ if (strpos($file, $whitelistFile) !== false) {
+ unset($deniedDirectivesInFile[$key]);
+ }
+ }
+ }
+ }
+ if ($deniedDirectivesInFile) {
+ $deniedDirectives[$file] = $deniedDirectivesInFile;
+ }
}
}
}
diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Xml/SchemaTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/Xml/SchemaTest.php
index 8048925a4e542..5877ee5cbcc48 100644
--- a/dev/tests/static/testsuite/Magento/Test/Integrity/Xml/SchemaTest.php
+++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Xml/SchemaTest.php
@@ -106,7 +106,9 @@ private function _filterSpecialCases(&$files)
'#etc/countries.xml$#',
'#conf/schema.xml$#',
'#layout/swagger_index_index.xml$#',
- '#Doc/etc/doc/vars.xml$#'
+ '#Doc/etc/doc/vars.xml$#',
+ '#phpunit.xml$#',
+ '#etc/db_schema.xml$#'
];
foreach ($list as $pattern) {
foreach ($files as $key => $value) {