Remove postal code required

We will begin with a research that will lead to a simple solution without any modifications in a code. If you don't have time to read the full answer, scroll down to the latest paragraphs with the answer.

The magento/module-ui/view/base/web/js/form/element/post-code.js element has built-in validation right in the code:

<script>
    /**
     * @param {String} value
     */
    update: function (value) {
        var country = registry.get(this.parentName + '.' + 'country_id'),
            options = country.indexedOptions,
            option;

        if (!value) {
            return;
        }

        option = options[value];

        if (option['is_zipcode_optional']) {
            this.error(false);
            this.validation = _.omit(this.validation, 'required-entry');
        } else {
            this.validation['required-entry'] = true;
        }

        this.required(!option['is_zipcode_optional']);
    }
</script>

That's why it is enabled all the time. The fastest solution is to rewrite this element and add your own code that will be inherited from the default. You can do this in the following way:

The element itself for the post code is declared here:

magento/module-checkout/view/frontend/layout/checkout_index_index.xml

and has the following view:

<item name="postcode" xsi:type="array">
    <!-- post-code field has custom UI component -->
    <item name="component" xsi:type="string">Magento_Ui/js/form/element/post-code</item>
    <item name="validation" xsi:type="array">
        <item name="required-entry" xsi:type="string">true</item>
    </item>
</item>

It is located in the <item name="shipping-address-fieldset" xsi:type="array"> container.

To replace this element you will need your own module that will include a form update and a js element. This is the Vendor_Rules module in the example.

Create a file:

app/code/Vendor/Rules/view/frontend/requirejs-config.js`

var config = {
    map: {
        '*': {
            "Magento_Ui/js/form/element/post-code": 'Vendor_Rules/js/form/element/post-code'
        }
    }
};

It should replace the default post-code element on the front-end.

app/code/Vendor/Rules/view/frontend/web/js/form/element/post-code.js

define([
    'underscore',
    'uiRegistry',
    'Magento_Ui/js/form/element/abstract'
], function (_, registry, Abstract) {
    'use strict';

    return Abstract.extend({
        defaults: {
            imports: {
                update: '${ $.parentName }.country_id:value'
            }
        },

        /**
         * @param {String} value
         */
        update: function (value) {
            var country = registry.get(this.parentName + '.' + 'country_id'),
                options = country.indexedOptions,
                option;

            if (!value) {
                return;
            }

            option = options[value];

            this.error(false);
            this.validation = _.omit(this.validation, 'required-entry');

            this.required(false);
        }
    });
});

This is almost the exact copy of the default element, excluding a zip validation for countries where it is not optional. Ino other words, it is required from Magento point of view.

When done, run an update:

bin/magento setup:upgrade
bin/magento setup:static-content:deploy

Refresh a cache and check the result. It will look the following way in our case:

A new address form without required a zip code: enter image description here

A new address saving without a zip code: enter image description here

The last step at the Checkout: enter image description here

And an error in the place order without a zip code: enter image description here

As you can see, there is a validation of a zip code at the back-end. We should come over it.

A validation is located in the customer address model \Magento\Customer\Model\Address\AbstractAddress, validate method:

    $_havingOptionalZip = $this->_directoryData->getCountriesWithOptionalZip();
    if (!in_array(
        $this->getCountryId(),
        $_havingOptionalZip
    ) && !\Zend_Validate::is(
        $this->getPostcode(),
        'NotEmpty'
    )
    ) {
        $errors[] = __('Please enter the zip/postal code.');
    }

The first solution is to add a zip code for all countries as optional. Let's check the getCountriesWithOptionalZip method:

/**
 * Return ISO2 country codes, which have optional Zip/Postal pre-configured
 *
 * @param bool $asJson
 * @return array|string
 */
public function getCountriesWithOptionalZip($asJson = false)
{
    if (null === $this->_optZipCountries) {
        $value = trim(
            $this->scopeConfig->getValue(
                self::OPTIONAL_ZIP_COUNTRIES_CONFIG_PATH,
                ScopeInterface::SCOPE_STORE
            )
        );
        $this->_optZipCountries = preg_split('/\,/', $value, 0, PREG_SPLIT_NO_EMPTY);
    }
    if ($asJson) {
        return $this->jsonHelper->jsonEncode($this->_optZipCountries);
    }
    return $this->_optZipCountries;
}

As you can see from the country code, the countries with the optional zip code are taken from the _optZipCountries attribute that is filled in with data in the following way:

$this->scopeConfig->getValue(
    self::OPTIONAL_ZIP_COUNTRIES_CONFIG_PATH,
    ScopeInterface::SCOPE_STORE
)

Values are stored in the system settings general/country/optional_zip_countries:

enter image description here

Finally, a simple solution:

You don't need to modify a code. You should only select all countries as countries with an optional zip code. After that a validation for them will be disabled!

Select all countries in the multiselect and save changes for the selected store. Then, disable our module and check the checkout:

A new address in the checkout: enter image description here

The last step at the checkout: enter image description here

An order placed has been placed successfully without a zip code: enter image description here

In the admin panel: enter image description here

Everything works correctly!

We provided the full research because it may help someone else.

UPDATE (11.01.16)

Sorry, we have misunderstood your question. Then, you need to use our first recommendation and slightly correct a code for the 'Magento_Ui/js/form/element/post-code.js' element. Perform the same actions, as described above but use the following code instead:

return Abstract.extend({
    defaults: {
        imports: {
            update: '${ $.parentName }.country_id:value'
        }
    },

    /**
     * @param {String} value
     */
    update: function (value) {
        var country = registry.get(this.parentName + '.' + 'country_id'),
            options = country.indexedOptions,
            option;

        if (!value) {
            return;
        }

        option = options[value];

        if (option['is_zipcode_optional']) {
            this.error(false);
            this.validation = _.omit(this.validation, 'required-entry');
        } else {
            this.validation['required-entry'] = true;
        }
    }
});

We removed the this.required(!option['is_zipcode_optional']); line because it has activated the validation mechanism and caused the red frame to appear. Without this line everything should work smooth and the red frame won't appear.