Files in csv files. See here and here.
Some translations are loaded over Knockout (Something like <span data-bind="i18n: 'Billing address'"></span>
).
These are retrieved from a js-translation.json
which is generated based on the csv.
To generate it, run
find pub/static -name js-translation.json -exec rm {} \;
find var/view_preprocessed -name js-translation.json -exec rm {} \;
bin/magento setup:static-content:deploy -f # Yes, even in developer mode...
If this doesn't work, try clearing caches (bin/magento cache:clean && bin/magento cache:flush
) until it works.
Eventually, it will.
Put this in <vendor>/<module>/etc/frontend/events.xml
:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="layout_load_before">
<observer name="remove_filter_block" instance="<vendor>\<module>\Observer\RemoveFilterBlock"/>
</event>
</config>
In <vendor>\<module>\Observer\RemoveFilterBlock.php
:
<?php
namespace <vendor>\<module>\Observer;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
class RemoveFilterBlock implements ObserverInterface
{
public function execute(Observer $observer)
{
/** @var \Magento\Framework\View\Layout $layout */
$layout = $observer->getLayout();
$layout->unsetElement('catalog.leftnav');
}
}
In etc/adminhtml/system.xml
:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
<system>
<tab id="sales" translate="label" sortOrder="10">
<label>Sales</label>
</tab>
<section id="checkout" translate="label" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
<class>separator-top</class>
<label>Checkout</label>
<tab>sales</tab>
<group id="general" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Some multiselect config option</label>
<field id="enable" translate="label" type="multiselect" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
<label>This is the lable</label>
<source_model><vendor>\<PluginName>\Model\Config\Source\Option</source_model>
<config_path><vendor>/<PluginName>/optionName</config_path>
</field>
</group>
</section>
</system>
</config>
Hint: You can mark options with canRestore="1"
to make it possible to reset them to their default values afterwards.
Hint 2: You can add a <comment>Lorem Ipsum</comment>
in the <field>
node which will show a helper text below the input field.
https://magento.stackexchange.com/q/239027/70510
Everything set here will be saved as <section id>/<group id>/<field id>
.
The options are defined in <vendor>\<PluginName>\Model\Config\Source\Option
:
namespace <vendor>\<PluginName>\Model\Config\Source;
use \Magento\Framework\Option\ArrayInterface;
class Option implements ArrayInterface
{
public function toOptionArray()
{
return [
['value' => 1, 'label' => 'First option'],
['value' => 2, 'label' => 'Second option'],
['value' => 3, 'label' => 'Third option'],
['value' => 4, 'label' => 'Fourth option'],
];
}
}
You can then get the configured options wherever you want like so (You'll need to inject \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
before):
$this->_scopeConfig->getValue('<vendor>/<PluginName>/optionName', Magento\Store\Model\ScopeInterface::SCOPE_STORE);
When your config form is a multiselect, the result will be a comma-seperated string.
$config = explode(',', $this->_scopeConfig->getValue('<vendor>/<PluginName>/optionName', Magento\Store\Model\ScopeInterface::SCOPE_STORE));
You can also define default values in etc/config.xml
:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
<default>
<<vendor>>
<<PluginName>>
<optionName>default_value</optionName>
</<PluginName>>
</<vendor>>
</default>
</config>
More: https://inviqa.com/blog/how-use-system-configuration-and-helpers-magento-2
Injecting Priduct
does not work. Instead, you need to inject \Magento\Framework\Registry
and then get the current product with
$this->_registry->registry('current_product')
You can create an observer to do this:
public function execute(\Magento\Framework\Event\Observer $observer)
{
if($this->shouldHaveSomething()) {
$layoutUpdate = $observer->getData('layout')->getUpdate();
$layoutUpdate->addHandle('catalog_product_view_extra_xml');
}
}
This will add catalog_product_view_extra_xml
from yourPlugin/view/frontend/catalog_product_view_extra_xml.xml
to the overall layout. With this xml you can then customize the page as you normally would.
Either with xml:
<referenceBlock name="page.main.title">
<action method="setPageTitle">
<argument translate="true" name="title" xsi:type="string">Recipe</argument>
</action>
</referenceBlock>
Or from a controller:
public function execute() {
$resultRedirect = $this->resultPageFactory->create();
$resultRedirect->getConfig()->getTitle()->set(__($this->helper->getPageTitle()));
}
The controller will always be preferred over xml layout changes !
Create a block class which "proxies" the thing you want:
use Magento\Framework\View\Element\Template;
class Timezone extends \Magento\Framework\View\Element\Template
{
/**
* @var \Magento\Framework\Stdlib\DateTime\Timezone
*/
private $_timezone;
/**
* Timezone constructor.
*
* @param Template\Context $context
* @param \Magento\Framework\Stdlib\DateTime\Timezone $_timezone
* @param array $data
*/
public function __construct(
Template\Context $context,
\Magento\Framework\Stdlib\DateTime\Timezone $_timezone,
array $data = []
) {
parent::__construct($context, $data);
$this->_timezone = $_timezone;
}
/**
* @return string
*/
public function getTimezone():string
{
return $this->_timezone->getConfigTimezone();
}
}
And then set that as your block class:
<block name="footer.timezone" after="footer_imprint_privacy" template="Vendor::timezone.phtml"
class="Vendor\Stuff\Block\Timezone">
</block>
https://devdocs.magento.com/guides/v2.3/extension-dev-guide/view-models.html
<?php
$block = $this->getLayout()->createBlock('Magento\Cms\Block\Block')->setBlockId('block_id');
?>
<?php
if ($block):
?>
<div class="top-header">
<?php
echo $block->toHtml();
?>
</div>
<?php
endif;
https://gist.github.com/matheusgontijo/b2722a6322283e84006367d2849696ab
var currentUiComponents = {};
requirejs('uiRegistry').filter(function(item){
currentUiComponents[item.name] = item;
});
console.log(currentUiComponents);
https://devdocs.magento.com/guides/v2.3/frontend-dev-guide/templates/template-email.html
https://devdocs.magento.com/guides/v2.3/frontend-dev-guide/css-guide/css_quick_guide_approach.html
<block
name="top.header.text"
ifconfig="imi_topheader/general/enable"
/>
class CustomClass extends Template
{
/**
* @return string
*/
public function customMethod(): string
{
return 'Something';
}
}
There's a lot of guides suggesting addAttributeToSelect
and addAttributeToFilter
. However, this does not work for simple models who don't have attributes, but only fields. For these, the methods are called addFieldToSelect
and addFieltToFiler
respectively. Other than the different name all work the same way.
For Example:
/** @var Collection */
protected $modelCollectionFactory;
public function __construct(CollectionFactory $contactsFactory)
{
$this->modelCollectionFactory = $contactsFactory;
}
private function getABunchOfData(): Collection
{
return $this->modelCollectionFactory->create()
->addFieldToSelect(['id'])
->addFieldToFilter(
'created',
['lteq' => (new \DateTime())->modify('-3 month')->format('Y-m-d H:i:s')]
);
}
Run
bin/magento queue:consumers:start order.placed --single-thread --max-messages=1 -vvv
to process one queued event and then use xdebug.remote_autostart=1
to debug into the consumer
To trigger a queued message again, set the status of the message in queue_message_status
to 2
(= New) and remove the lock entry for the same message in queue_lock
. Then run the consumer again (as above).
If you put this in an email template:
{{ var order.increment_id}}
The email gets sent with an absolutely nonsense error message which does not tell you at all where the actual issue is.
However, if you send it like this:
{{var order.increment_id}}
it works without issues.
Devdocs: https://devdocs.magento.com/guides/v2.3/extension-dev-guide/declarative-schema/data-patches.html
Remember, when adding a new attribute, you have to also declare it in db_schema.xml
and db_schema_whitelist.json
$this->eavSetup->addAttribute(
Product::ENTITY,
self::ATTRIBUTE_CODE,
[
'type' => 'int',
'backend' => '',
'frontend' => '',
'label' => 'Verpackungseinheit',
'input' => 'text',
'class' => '',
'source' => '',
'global' => ScopedAttributeInterface::SCOPE_GLOBAL,
'visible' => true,
'required' => false,
'user_defined' => false,
'default' => '',
'searchable' => false,
'filterable' => false,
'comparable' => false,
'visible_on_front' => true,
'used_in_product_listing' => true,
'unique' => false,
'apply_to' => '',
]
);
// Add the new attribute to all attribute sets
$searchCriteria = $this->searchCriteriaBuilder->create();
$attributeSets = $this->attributeSetRepository->getList($searchCriteria)->getItems();
foreach ($attributeSets as $attributeSet) {
$this->attributeManagement->assign(
$attributeSet->getId(),
$attributeSet->getDefaultGroupId(),
self::ATTRIBUTE_CODE,
$attributeSet->getCollection()->count() * 10
);
}
n98-magerun2 config:store:set dev/js/merge_files 0
n98-magerun2 config:store:set dev/js/enable_js_bundling 0
n98-magerun2 config:store:set dev/js/minify_files 0
n98-magerun2 config:store:set dev/css/merge_css_files 0
n98-magerun2 config:store:set dev/css/minify_files 0
bin/magento setup:static-content:deploy
- https://www.integer-net.com/integration-tests-with-magento-2/
- http://vinaikopp.com/2016/04/18/07_the_action_controller_integration_test_kata/
Events: https://devdocs.magento.com/guides/v2.4/extension-dev-guide/events-and-observers.html
Custom logger: https://magento.stackexchange.com/a/75954/77979
Custom CLI Commands: https://devdocs.magento.com/guides/v2.4/extension-dev-guide/cli-cmds/cli-howto.html
Plugins (Interceptors): https://devdocs.magento.com/guides/v2.4/extension-dev-guide/plugins.html
JSON Serializing:https://devdocs.magento.com/guides/v2.4/extension-dev-guide/framework/serializer.html
Widgets: https://www.toptal.com/magento/custom-widgets-in-magento-2
Adding Recaptcha to a form: https://magento.stackexchange.com/a/305471/77979