Magento 2.1.7 add CMS page multiselect to CMS page
-
12-12-2020 - |
题
I'm new to Magento 2 and I'm trying to add a multiselect of all (for now) CMS pages to the CMS pages in Magento 2. What I mean by this is that when creating/editing a CMS page, there should be an extra field with all (other) CMS pages from which you can select multiple (or just one or none at all), just like you have a multiselect for the Store View field. I have got it to work to render the multiselect and you can select multiple, but upon saving it shows a message that "something" went wrong. Example of the fields:
I've also created an upgrade script which has successfully created an extra field in the cms_page table. I can still save pages, but only when I don't select any CMS pages.
Here's my //view/adminhtml/ui_component/cms_page_form.xml
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<fieldset name="search_engine_optimisation">
<field name="redirect_to">
<argument name="data" xsi:type="array">
<item name="options" xsi:type="object">Magento\Cms\Model\Config\Source\Page</item>
<item name="config" xsi:type="array">
<item name="dataType" xsi:type="string">int</item>
<item name="label" xsi:type="string" translate="true">Redirect to pages</item>
<item name="formElement" xsi:type="string">multiselect</item>
<item name="source" xsi:type="string">page</item>
<item name="dataScope" xsi:type="string">redirect_to</item>
<item name="default" xsi:type="string">0</item>
<item name="validation" xsi:type="array">
<item name="required-entry" xsi:type="boolean">false</item>
</item>
</item>
</argument>
</field>
</fieldset>
</form>
What am I missing or doing wrong? For some reason, I've gotten it to work but it would only save one, never multiple, but I can't seem to reproduce that anymore.
What I'd like to achieve is for it to save all selected options as a JSON encoded string with the store id as key and the URL as value. How would I go about doing this?
Any help is much appreciated.
解决方案
First of all you need to change option class for your requirement. So make following way.
Change <item name="options" xsi:type="object">Magento\Cms\Model\Config\Source\Page</item>
to
<item name="options" xsi:type="object">VendorName\ModuleName\Model\Config\Source\Page</item>
namespace VendorName\ModuleName\Model\Config\Source;
class Page extends \Magento\Cms\Model\Config\Source\Page
{
/**
* To option array
*
* @return array
*/
public function toOptionArray()
{
if (!$this->options) {
$emptyOption[] = [
'value' => 'all',
'label' => 'All'
];
$this->options = $this->collectionFactory->create()->toOptionIdArray();
$this->options = array_merge($emptyOption, $this->options);
}
return $this->options;
}
}
Now you can able to see 'All' option inside multiselect element.
For save:
Create a plugin for this: VendorName/ModuleName/etc/adminhtml/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Cms\Controller\Adminhtml\Page\PostDataProcessor">
<plugin name="PostDataProcessor_Save" type="VendorName\ModuleName\Plugin\Controller\Adminhtml\Page\PostDataProcessor" sortOrder="1"/>
</type>
<type name="Magento\Cms\Model\Page\DataProvider">
<plugin name="DataProvider_Load" type="VendorName\ModuleName\Plugin\Model\Page\DataProvider" sortOrder="1"/>
</type>
</config>
VendorName/ModuleName/Plugin/Controller/Adminhtml/Page/PostDataProcessor.php
namespace VendorName\ModuleName\Plugin\Controller\Adminhtml\Page;
class PostDataProcessor
{
public function aroundFilter(
\Magento\Cms\Controller\Adminhtml\Page\PostDataProcessor $subject,
\Closure $proceed,
$data
) {
if(isset($data['redirect_to']) && ($data['redirect_to'])) {
$data['redirect_to'] = json_encode($data['redirect_to']);
}
return $proceed($data);
}
}
For edit:
VendorName/ModuleName/Plugin/Model/Page/DataProvider.php
namespace VendorName\ModuleName\Plugin\Model\Page;
class DataProvider
{
/**
* Get data
*
* @return array
*/
public function afterGetData(
\Magento\Cms\Model\Page\DataProvider $subject,
$result
) {
if (is_array($result)) {
foreach ($result as &$item) {
if(isset($item['redirect_to']) && ($item['redirect_to'])) {
$item['redirect_to'] = json_decode($item['redirect_to']);
}
}
}
return $result;
}
}