0

I've created a module to capture and pass submitted custom option selections from a product which I intend to then send via email (for quotes). Everything is working except my attempts to pass the array of custom option information to a layout template.

I parse and append the options to the email parameters in Post.php, and then attempt to pass the options object from the email template to the layout template where I want to iterate over each of the options. However, $block->getOptions() (see below) always returns null.

The $params['options'] is populated correctly, so the issue is just passing the data to the layout template. If I don't try to pass the options to the layout template, it's working fine. It only errors (Error filtering template: Warning: Invalid argument supplied for foreach()) because $options is null.

Am I passing the options data to the template incorrectly?

Post.php

<?php

...

public function execute()
{
    ...

    try {
        ...

        // Send email
        $this->sendEmail($this->validatedParams());

        ...
    }

}

private function sendEmail($post)
{
    $this->mail->send(
        $post['raq_email'],
        ['data' => new DataObject($post)]
    );
}

private function validatedParams()
{
    $request = $this->getRequest();
    $params = $request->getParams();

    ...


    // Parse options to strings
    $options = [];

    ...

    $optionsObj = $this->objectFactory->create();
    $optionsObj->setData($options);
    $params['options'] = $optionsObj;

    return $params;
}

Mail.php

public function send($replyTo, array $variables)
    {
        /** @see \Vendor\Quoteform\Controller\Index\Post::validatedParams() */
        $replyToName = !empty($variables['data']['name']) ? $variables['data']['name'] : null;

        $this->inlineTranslation->suspend();
        try {
            $transport = $this->transportBuilder
                ->setTemplateIdentifier($this->quoteConfig->emailTemplate())
                ->setTemplateOptions(
                    [
                        'area' => Area::AREA_FRONTEND,
                        'store' => $this->storeManager->getStore()->getId()
                    ]
                )
                ->setTemplateVars($variables)
                ->setFrom($this->quoteConfig->emailSender())
                ->addTo($this->quoteConfig->emailRecipient())
                ->setReplyTo($replyTo, $replyToName)
                ->getTransport();

            $transport->sendMessage();
        } finally {
            $this->inlineTranslation->resume();
        }
    }

email_product_custom_options.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd" label="Email Product Custom Options" design_abstraction="custom">
    <body>
        <block class="Magento\Framework\View\Element\Template" name="email_product_custom_options" template="Vendor_Quoteform::email/productCustomOptions.phtml" cacheable="false"/>
    </body>
</page>

email_template.html

{{template config_path="design/email/header_template"}}

<table class="message-details">
  <tr>
    <td>
      <b>{{trans "Name"}}</b>
    </td>
    <td>{{var data.raq_name}}</td>
  </tr>
  <tr>
    <td>
      <b>{{trans "Email"}}</b>
    </td>
    <td>{{var data.raq_email}}</td>
  </tr>
  <tr>
    <td>
      <b>{{trans "Phone"}}</b>
    </td>
    <td>{{var data.raq_telephone}}</td>
  </tr>
</table>

{{layout handle="email_product_custom_options" options=$options area="frontend"}}

{{template config_path="design/email/footer_template"}}

productCustomOptions.phtml

<?php $options = $block->getOptions();?>
<table>
    <?php foreach($options as $k => $v): ?>
    <?php foreach($v as $title => $value): ?>
    <tr>
        <td><?= $title ?></td>
        <td><?= $value ?></td>
    </tr>
    <?php endforeach; ?>
    <?php endforeach; ?>
</table>
1

Difficult to know without seeing your email send logic but typically you need to build objects which you then pass through to email templates.

https://magento.stackexchange.com/a/283338/70343

So I would have thought you would be better passing the block template output as a variable.

  • Added email send logic, setTemplateVars($variables) is where the parameters passed from validatedParameters() are set. If I put {{var data.options}} in the email template, it fails because it's an array, but the data is there. I can't be specific because the options are dynamic, so something like {{ var data.options.foo }} isn't an option, which is why I added the layout template; similar to the way order items are handled in the order emails. – spencerready Aug 15 '19 at 16:00
1

I had a misunderstanding in the structure of the data being passed to the email template. The "data" object was set as the only accessible DataObject in the variables array passed to send(...) in Mail.php.

So I could access the data object like this in the email template: {{layout handle="email_product_custom_options" dataObj=$data area="frontend"}}

...and then get it in the layout: <?php $options = $block->getDataObj();?>

But to simplify things in my layout template, I passed the options in the top-level of the array like so:

private function sendEmail($post)
{
    $this->mail->send(
        $post['raq_email'],
        ['data' => new DataObject($post), 'options' => $post['options']]
    );
}

...which made the original code work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.