Layout Paragraphs Builder ignores configuration in fields that are configured to allow only one Paragraph item. Even though a field is set up to only allow one Paragraph item, editors can still use the duplicate / move features within Layout Paragraphs Builder.

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

philip_stier created an issue. See original summary.

hudri’s picture

By design Layout Paragraphs can not work reasonable with single cardinality field storage:

In order to use Layout Paragraphs, you must have a cardinality of at least 2, one layout paragraph storing the layout behavior, and one content paragraph storing the actual content.

In general, I believe the combined usage of limited field storage cardinality and Layout paragraphs doesn't make sense. When using layout discovery, the sensible amount of children is tied to the number of regions defined in your layout file, and not by the field cardinality setting.

I can see the need to limit the type or number of content paragraphs per layout and/or region, but this limitation can not be done with field storage cardinality. There is a Layout paragraphs restriction module, but this was for version 1 and for limiting by type, not by count. I currently don't know of any module compatible with v2.

If you have the requirement to limit allowed paragraphs with the field storage setting, do not use Layout Paragraphs, they contradict each other by concept.

I think we should add something like "Set the cardinality to unlimited in the field storage setting" in the "Getting started" section of the module page.

justin2pin’s picture

@philip_stier - good catch, this needs to be fixed. I agree with @hudri that the use-case is rare, but field widgets do need to respect cardinality settings regardless. We need to prevent users from adding more paragraphs to a given reference field than is allowed by the cardinality limit set by the site owner.

justin2pin’s picture

Issue tags: +Needs tests

  • justin2pin committed bfa7269 on 2.0.x
    Issue #3260905: Layout Paragraphs Does Not Respect Cardinality
    
justin2pin’s picture

Status: Active » Fixed
Issue tags: -Needs tests

Status: Fixed » Closed (fixed)

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

pookmish’s picture

Something about the commit in this issue broke the functionality to edit a paragraph within a layout. At this moment I'm not sure what about it broke, but I used git bisect to identify the commit in this issue.

before, I would be able to hover over a paragraph and I would see the ability to edit the paragraph. Now hovering doesn't display anything. I didn't find an existing issue, so I thought I'd start here.

justin2pin’s picture

Thanks @pookmish - Can you list the steps needed to reproduce this? Do your paragraph templates override or change the ID attribute? This commit slightly changed the way controls are stored in JS and attached to paragraphs. The IDs on paragraph containers are now used to correctly match and render the appropriate controls (edit/delete/etc.) for each paragraph using JS.

pookmish’s picture

Re-tracing my code, I remember I had to do some special work to get the UI functionality working correctly when using UI Patterns module displays on the paragraphs. I noticed that when using a regular paragraph display settings the hover effects work as expected. But when using a paragraph that is configured to use a custom pattern template from UI Patterns, the hover affect breaks.

I'll start by tracing through the special work around I did to see what might be different compared to the previous version.

Is this line the one you are referring to about the ID attribute?

pookmish’s picture

I found the issue that was happening. At some point, the id attribute was being changed through the rendering process. If the paragraph was for example 35, the id should be 35. But then through some part of rendering the various layers, it got changed to 35--2 which obviously broke the hover functionality.

Thanks for the help.

Just in case anyone runs into a similar issue.
Here's the snippet of code I use to make UI patterns & the DS module work with LB in the edit screen.

use Drupal\Core\Template\Attribute;

/**
 * Implements hook_theme().
 */
function hook_helper_theme($existing, $type, $theme, $path) {
  // Duplicate the patterns_use_wrapper theme so we can modify it to work with
  // layout paragraphs.
  return ['patterns_use_wrapper_admin' => ['variables' => ['use' => NULL]]];
}

/**
 * Implements hook_theme_suggestions_alter().
 */
function hook_helper_theme_suggestions_alter(array &$suggestions, array $variables, $hook) {
  if (
    strpos($hook, 'pattern_') === 0 &&
    strpos($hook, 'pattern_view') === FALSE &&
    _hook_helper_is_editing_layout_paragraphs()
  ) {
    // Add the theme suggestion when we're editing layout builder components.
    $suggestions[] = 'patterns_use_wrapper_admin';
  }
}

/**
 * Implements hook_preprocess().
 */
function hook_helper_preprocess(&$variables, $hook) {
  // If not editing LP page, we don't want to do anything.
  if (!_hook_helper_is_editing_layout_paragraphs()) {
    return;
  }

  // Manipulate the render array for the entity view so that we can pick it up
  // in the later hook on the pattern.
  if ($hook == 'ds_entity_view') {
    // Between this hook and the pattern hook, the id attribute changes somehow,
    // so store the attributes into the context so that we can grab them later
    // and apply them to the wrapper.
    $variables['content']['#context']['lpBuilder'] = $variables['attributes'];
    unset($variables['attributes']);
  }

  if (strpos($hook, 'pattern_') === 0 && !empty($variables['context'])) {

    // Grab the layout paragraphs parts from the context that we saved above,
    // and put them into a variable for use in the patterns_use_wrapper_admin
    // template. Also remove the normal attributes to a wrapper so that they
    // don't somehow get passed down into the pattern and cause chaos.
    $variables['wrapper_attributes'] = new Attribute($variables['context']->getProperty('lpBuilder'));
    $variables['attributes'] = new Attribute();
  }
}

/**
 * Is the user currently on editing the layout paragraphs?
 *
 * @return bool
 *   True if the route matches known routes for LP.
 */
function _hook_helper_is_editing_layout_paragraphs() {
  $layout_paragraphs_routes = ['entity.node.edit_form'];
  $route_name = \Drupal::routeMatch()->getRouteName();
  return in_array($route_name, $layout_paragraphs_routes) || strpos($route_name, 'layout_paragraphs.') === 0;
}

With a template patterns-use-wrapper-admin.html.twig containing:

<div{{ wrapper_attributes }}>
  {% include use %}
</div>
justin2pin’s picture

Thanks again @pookmish. I actually wonder if we should make a feature request to NOT use the ID attribute, for this reason. We initially debated using the ID vs a custom data- attribute, and went with the ID just for simplicity. It seems pretty likely that other sites -- like yours -- might change the ID value, breaking the controls.

pookmish’s picture

IMO that would be a good move to make. Something like data-lp-builder-id would be unique enough and since it would be populated by the entity ID there no chance at conflicts with other paragraphs in the widget. Then you could remove the need for Html::getUniqueId() which is also a part of the issue for me.