Problem/Motivation

Smart Date recurring fields assume their host entity is a top-level, URL-addressable entity such as a node. When a recurring Smart Date field is placed on a Paragraph instead, several things break. The underlying cause is this host-entity assumption, surfacing as multiple distinct bugs (some of which also affect non-Paragraph usage, e.g. the month-limit and data-loss issues).

  • Invalid specifier 'rrule': Saving a recurring field on a Paragraph throws a QueryException because the widget assumes the wrong entity type/bundle.
  • Host entity cannot be found: SmartDateRule::getParentEntity() uses an entityQuery .rrule condition that fails for fields nested in Paragraphs.
  • Configured "Months to Extend" ignored: The Manage Instances page and cron pass a rule object to getMonthsLimit(), which then silently defaults to 12 months instead of honoring the field's configured value.
  • Data loss for long-interval recurrences: When a recurrence's first occurrence is beyond the generation window (common with yearly events), the field is emptied on save, destroying the submitted value.
  • UndefinedLinkTemplateException: After editing/overriding an instance, the controller redirects to $entity->toUrl(); Paragraphs have no canonical link template, so this throws.
  • Runaway instance generation: Applying an override calls getRuleInstances() with no time bound, generating up to the library's virtual limit (hundreds of instances).

Steps to reproduce

  1. Add a Smart Date field to a Paragraph type and enable recurring values.
  2. Add that Paragraph to a content type.
  3. Create content, add the Paragraph, and configure a recurring date.
  4. Save — observe the Invalid specifier 'rrule' error.
  5. With that resolved, open Manage Instances: it shows only 12 months regardless of the "Months to Extend" setting.
  6. Edit/reschedule an instance — observe the UndefinedLinkTemplateException, and note the field regenerates a very large number of instances.

Proposed resolution

Make the recurring logic work for nested/host entities and fix the related generation bugs:

  • Widget save (SmartDateWidgetBase.php): derive the correct entity_type/bundle from the field definition rather than assuming the host entity.
  • Parent lookup (SmartDateRule.php): query the field's table directly to find the entity referencing a rule, with a fallback to the original entityQuery.
  • Month limit (SmartDateRecurTrait.php): resolve the limit from the rule's field configuration when passed a rule object, instead of defaulting to 12.
  • Data loss (smart_date_recur.module): preserve the submitted value when no instances fall within the generation window.
  • Redirect (Instances.php): walk up to a host entity that has a canonical URL, falling back to the instances listing.
  • Override bound (Instances.php): bound unlimited rules by the configured month limit when regenerating instances.

Remaining tasks

  • Maintainer review.
  • Add automated test coverage for Smart Date recurring fields on Paragraph (host) entities.
  • Confirm the direct field-table query approach in getParentEntity() is acceptable, or replace with a more API-driven lookup if preferred.

User interface changes

None intended. The Manage Instances page now correctly reflects the configured "Months to Extend" value instead of always showing 12 months.

API changes

None. Behavior of SmartDateRule::getParentEntity() and getMonthsLimit() is corrected, but method signatures are unchanged.

Data model changes

None. No schema or configuration changes; the fixes prevent invalid/empty field values rather than altering the data model.

CommentFileSizeAuthor
smart_date_recur_paragraph_fix.patch8.51 KBjeff.a

Issue fork smart_date-3606260

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

jeff.a created an issue. See original summary.

mandclu’s picture

Version: 4.2.8 » 4.2.x-dev

@jeff.a could you submit this as a merge request?

kieran.cott made their first commit to this issue’s fork.

kieran.cott’s picture

Thanks @jeff.a - I was also able to reproduce this issue and your patch fixes it for me.

I've applied it as an MR with a couple of tweaks and added some test coverage.

Remaining task:

Confirm the direct field-table query approach in getParentEntity() is acceptable, or replace with a more API-driven lookup if preferred.

I think a more API-driven lookup would be preferable, and structured such that direct field-table querying is still available as a fall-back. I've taken a pass at implementing this on the same MR as a separate commit - interested in your thoughts?

mandclu’s picture

Thank you both for your work here. I have one question, added to the MR.

nitinkumar_7’s picture

Reviewed the @kieran.cott's MR commits. The approach is solid and the fixes are well implemented:

- `getParentEntity()` correctly uses the field API (`getTableMapping()->getFieldTableName()`) with direct DB query as a named fallback.
- `$this->get('limit')` used throughout instead of raw property access.
- Instance limit bounding moved into `getRuleInstances()` - cleaner than doing it in the controller.
- Kernel test coverage added.

Ready to mark RTBC-