Requirements

The product page needs to include variation fields. The product and variation fields can be mixed / interleaved, there is no clear boundary between them.
Changing the variation on the add to cart form should replace the previously rendered variation fields.

There are two different roles customizing product display:

1) Themer
Uses twig to create a layout by hand.
Needs access to the individual product and variation fields in the twig file.

2) Site builder
Uses Display Suite or Panels to add fields to a premade layout (provided by layout_plugin).
Needs access to the variation fields in the relevant UI.

Commerce 1.x

Field injection was implemented via hook_field_extra_fields, giving a node the commerce_product fields. Any field marked as "Visible" would be injected.

While it provided a solution, it was often confusing and difficult:

  1. Controlling the theming seemed difficult
  2. The formatter and other settings for commerce_product fields had to be selected on the Manage display screen for products, resulting in back & forth between two different Manage display screens, both with their own weights

Proposed resolution: Themer

We start here.

1) Create a service that returns variation fields that are candidates for injection.
From base fields this includes only 'sku' and 'title' . From configurable fields this includes all non-attribute fields. We don't need attribute fields cause they're already managed by the attribute selection widget.

2) Add a method to ProductInterface for fetching the default variation
This is currently implicit (we get delta 0), so let's make it explicit.

3) Add an "Inject product variation fields into the rendered product" to the product type.

4) In a template preprocess function, load the product type, check the setting, if TRUE get the fields for injection.
Then load the default variation and render the fields.
This field rendering probably belongs in the same service that gets the candidate fields.
Behind the scenes, each field is rendered via $view_builder->viewField($entity->{$field_name}, $product_view_mode).
The fields are then passed to Twig for rendering, keyed by 'variation_'. For example 'variation_sku'. The twig template should document this.

5) Ensure that rendered fields have a class we can target on ajax. See quickedit_preprocess_field() for an example.

6) On #ajax get the new variation, rerender the fields, return the ajax commands that replace the previous fields.

That's it. The themer gets full control, needs to use two different manage field screens for configuring settings (just like in 1.x).

Proposed resolution: Site builder

This requires that we first implement the themer solution, cause the #1, #2, #5 and #6 parts are the same.

The site builder turns off field injection on the product type, then uses DS or Panels.

Panels doesn't support relationships yet. Once it does, the user will be able to add a variation relationship, add the individual fields, configure the formatter and other settings. We just need to ensure that the relationship is there.

For DS we implement a derivative DsField plugin that provides a plugin definition for each field injection candidate, then renders and returns it. Since DsField plugins can have settings, we can ask for the formatter and settings here, and pass them along to $view_builder->viewField() instead of the view display id.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

mglaman created an issue. See original summary.

mglaman’s picture

Issue summary: View changes

blank

mglaman’s picture

The problem with not using hook_field_extra_fields is that site builders / themers cannot easily control how variant field information is rendered in context to the product's information.

mglaman’s picture

Status: Active » Needs work
FileSize
2.4 KB

Here's a beginning for a direct port of 1.x functionality. All available fields on the product variation bundle are added as extra fields. Items configured on the product display are then checked against the variation's display and then rendered.

An enhancement would be to only inject fields marked visible on the view display, not all field definitions available.

mglaman’s picture

From the change record Introduced EntityViewDisplay config entities, it says that hook_field_extra_fields_display_alter has been replaced by hook_entity_view_display_alter(). However the D7 hook would run on the admin form. Now, however, it only runs on view. The exact functionality port from 1.x will be missing this, pushing the idea of injecting fields directly from what has been configured on the default display mode, not all available fields on the variation bundle.

mglaman’s picture

Updated patch which includes a test. The injection attempts to match the display modes. Example: if you have a Catalog view mode for your product, it will try to use that same view mode on the variation.

Next steps are implementing a behavior and method to replace fields on AJAX calls. In 1.x this was controlled by the add to cart form. In 2.x I think it would be beneficial if comemrce_product provided a JavaScript function that consumed the product ID, variation ID, and view mode. A callback would then return the AJAX commands to replace injected fields.

This way it could be re-used in other areas beyond the add to cart form. For example, browsing a catalog and clicking on swatch colors. A site developer could implement this JavaScript call to change the pictures of the product on the catalog.

bojanz’s picture

Issue summary: View changes

Updating with latest research done by mglaman and me for Bluespark.

I should add that the point of the proposed architecture is to avoid the complexity of implementing settings for injected fields ourselves, offloading that part to DS / Panels instead. DS especially is in good shape and worth a recommendation.

bojanz’s picture

Issue summary: View changes
mglaman’s picture

Issue summary: View changes
Status: Needs work » Needs review
FileSize
32.29 KB
37.69 KB

Attaching patch, here is PR:

And a fancy gif: https://github.com/drupalcommerce/commerce/pull/377

agoradesign’s picture

found a typo!

+entity.commerce_product_varition.ajax_render:

"varition"

mglaman’s picture

Per #10: removed that controller and route. Wasn't used, was a generic idea to implement a way to render fields via a JavaScript command. Could easily be added later.

Added a method to the service which adds the AJAX request commands and creates the hook_commerce_product_variation_field_injection() hook, allowing modules to control the commands sent whenever injected fields are refreshed.

bojanz’s picture

Status: Needs review » Needs work

Work continues in the PR.

bojanz’s picture

agoradesign’s picture

How's the progress here? The PR was already quite well last week, only a few minor improvements to do... When can we expect the final version?

  • bojanz committed 6f4ee9b on 8.x-2.x authored by mglaman
    Issue #2716417 by mglaman, bojanz: Allow rendering of variation fields...
bojanz’s picture

Status: Needs work » Fixed

Committed.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

maxplus’s picture

Thanks!

great, I can now just add {{ product.variation_price }} to my commerce-product--teaser.html.twig template file.

Very handy to place product variation fields on the exact desired position inside my product template.

This is now possible inside your commerce-product--display.html.twig:

<article{{ attributes }}>
    {{ product.field_photo }}
    {{ product.title }}
    {{ product.variation_price }}
</article>

Make sure:
- you have "Inject product variation fields into the rendered product." enabled on your product type
- you have a display name that exists both on your product entity and your product variation entity, those are the places where you set your field formatters

Anybody’s picture

Seems like this should not have been introduced globally, but per view-mode. Here's the follow-up: #2910246: Option to choose view mode for injected product variation in views

AlfTheCat’s picture

Also, the "Proposed resolution: Site builder" seems to be open still, variation fields are not available still on product view modes.

bojanz’s picture

Layout Builder integration was done to solve the site builder use case.

So those are the two theming options. Twig or Layout Builder. Full control just via the "manage fields" screen will never be possible.

AlfTheCat’s picture

Hi Bojanz, thanks that is very helpful to know.