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 anentityQuery.rrulecondition 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
- Add a Smart Date field to a Paragraph type and enable recurring values.
- Add that Paragraph to a content type.
- Create content, add the Paragraph, and configure a recurring date.
- Save — observe the
Invalid specifier 'rrule'error. - With that resolved, open Manage Instances: it shows only 12 months regardless of the "Months to Extend" setting.
- 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 correctentity_type/bundlefrom 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 originalentityQuery. - 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.
| Comment | File | Size | Author |
|---|---|---|---|
| smart_date_recur_paragraph_fix.patch | 8.51 KB | jeff.a |
Issue fork smart_date-3606260
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
Comment #2
mandclu commented@jeff.a could you submit this as a merge request?
Comment #5
kieran.cottThanks @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:
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?
Comment #6
mandclu commentedThank you both for your work here. I have one question, added to the MR.
Comment #7
nitinkumar_7 commentedReviewed 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-