Introduction
Paragraph Group can and should be an important contrib module for Drupal, particularly for the many Drupal sites now using the very popular Paragraphs module
Paragraph Group tidies up Drupal content editing pages, and so dramatically improves the user and editor experience when authoring content.
The module offers a new Accordion based widget for Paragraphs, facilitating better nesting and navigation for Paragraphs on edit pages. And it puts all fields into Field Groups. These two improvements convert busy or even messy edit pages into tidy, organized, navigable, well grouped field sets:
Relationship to other Contributed Modules
The content editing experience is still somewhat neglected in the Drupal ecosystem, so I feel that Paragraph Group is actually a vital Drupal contribution. Other modules in the Paragraphs ecosystem add great functionality like modal windows etc, but don't address fundamental Paragraphs complexity issues. And broader front end in-place editing and layout tools are great, but Paragraph Group strengthens the essential content architecture, coherence and control foundation that is necessary for those tools within the Admin Theme level.
Code and Security Concerns
I have taken every step to ensure my code is compliant with all relevant Drupal and industry standards, following the Drupal security application checklist carefully. The code is fully object oriented; all include or require statements have been replaced with Services accessed through dependency injection; the code is fully formatted using PHPCS; and the code is also fully reviewed with Claude Code.
I've also recently added complete PHPDoc and JSDoc notes to all my code functions to ensure maximum transparency and readability of code for any reviewer. So hopefully I've made this job as easy as possible for you!
All git commits, branches and work on this project is mine. So please see my project page for more info at:
P.S. As a Drupal Developer and enthusiast since the Drupal 6 days in 2008, I have also examined some other modules in this queue, with some AI assistance. It can potentially be difficult for developers currently without security advisory approval like myself, to be forthright in reviews around security concerns, but please let me know if I can help out there as well. Please also feel free to raise any issues of concern for this module too, and I'll do my best to address them asap.
Comments
Comment #2
vishal.kadamComment #3
avpadernoThank you for applying!
Please read Review process for security advisory coverage: What to expect for more details and Security advisory coverage application checklist to understand what reviewers look for. Tips for ensuring a smooth review gives some hints for a smoother review.
The important notes are the following.
To the reviewers
Please read How to review security advisory coverage applications, Application workflow, What to cover in an application review, and Tools to use for reviews.
The important notes are the following.
For new reviewers, I would also suggest to first read In which way the issue queue for coverage applications is different from other project queues.
Comment #4
vishal.kadam1. FILE: paragraph_group.libraries.yml
VERSION is only used by Drupal core modules. Contributed modules should use a literal string that does not change with the Drupal core version a site is using.
2. FILE: paragraph_group.module
The usual description for a .module file is “Hook implementations for the [module name] module”, where [module name] is the module name given in the .info.yml file.
The description for this hook should also say for which form that hook is implemented, either by indicating that with the name of the class that implements the form (namespace included) or the form ID (which is usually indicated by
getFormId()).3. FILE: src/Form/ParagroupConfigForm.php
FILE: src/Paragroup/ParagroupBatch.php
FILE: src/Paragroup/ParagroupFormData.php
The documentation comment for constructors is not mandatory anymore, If it is given, the description must be “Constructs a new [class name] object”, where [class name] includes the class namespace.
Comment #5
daniel.rosenkranz commentedThanks for your replies everyone. The fixes mentioned by @vishal.kadam should be fine, but I'm also setting up Gitlab CI as well as advised by @avpaderno. So I'll let you know when I've completed all the resulting fixes asap.
Comment #6
daniel.rosenkranz commentedHi all,
I have now:
So please let me know any further issues, and I'll do my best to address them asap. Appreciate your help.
Comment #7
avpadernosrc/Form/ParagroupConfigForm.php
ConfigFormBase::__construct()needs to be called. Since its parameters changed in Drupal 10.2, the project cannot be compatible with all the Drupal 10 releases and Drupal 11; it needs to require at least Drupal 10.2.With Drupal 10 and Drupal 11, there is no longer need to use
#default_valuefor each form element, when the parent class isConfigFormBase: It is sufficient to use#config_target, as in the following code.Using that code, it is no longer needed to save the configuration values in the form submission handler: The parent class will take care of that.
Truly, given the code used by that class,
ConfigFormBaseis not the appropriate parent class. Form classes do not need to have a parent class; they just need to implementFormInterface.The short description is wrong, but it is also not necessary, since for methods defined in a parent class, a trait, or an interface, the documentation comment is just
@{inheritdoc}.Dependencies needs to be injected via
create().Classes that implements
ContainerInjectionInterfaceuse $this->t(), nott()(which requires them to useStringTranslationTrait.src/Paragroup/ParagroupBatch.php
'out of'is not translated int('@result @section_type @action.', $msg_params);. What the translators can do with @result @section_type @action. is changing the order of the placeholders to the correct order for their languange, and replacing the character at the end of the sentence with the right character in their language. (For example, Japanese uses 。.)src/Paragroup/ParagroupFormData.php
That is a property already defined by
StringTranslationTrait.It is correct to initialize that property, but there is
StringTranslationTrait::setStringTranslation()The correct placeholder for URLs is :variable as shown in the documentation for
FormattableMarkup::placeholderFormat()and must always be wrapped in quotes. That is the placeholder used also by Drupal core code for URLs that take to drupal.org.paragraph_group.module
For a new module that aims to be compatible with Drupal 10 and Drupal 11, I would rather implement hooks as class methods as described in Support for object oriented hook implementations using autowired services.
Comment #8
daniel.rosenkranz commentedThank you for your feedback @avpaderno. Just to let you know that I’m currently working on some refactorings based on your recommendations, which should be complete by early next week.
Comment #9
daniel.rosenkranz commentedThank you avpaderno for your detailed initial code review. Please see the current commit at https://git.drupalcode.org/project/paragraph_group
I have tried to address your feedback through a comprehensive three-phase approach to ensure the highest possible code quality and security standards in my implementation.
1. Direct Issue Resolution: I have systematically addressed each explicit issue raised in your review, implementing proper dependency injection, modern config targets, constructor patterns, translation improvements, and particularly object-oriented hook implementations. I have now also been able to delete the paragraph_group.module file. So these changes ensure consistent adherence to current Drupal coding standards throughout the identified areas.
2. Systematic Extrapolation: Taking your note that the review points were just a start, I conducted comprehensive dependency injection refactoring across the entire codebase. This eliminated all static \Drupal::service() calls, converted utility classes to proper services, and applied security best practices systematically beyond the explicitly mentioned areas.
3. Comprehensive Quality Assurance: I have also now achieved 100% compliance with all Gitlab-CI test suites at git.drupalcode.org, including PHPStan static analysis, ESLint JavaScript standards, spell checking, and code formatting. This demonstrates proactive security awareness extending well beyond the minimum PHPCS requirements mentioned in the application process.
So I feel that these changes collectively demonstrate my commitment to exceptional code quality, security best practices, and modern Drupal architecture. And while I'm obviously keen to meet requirements as soon as possible, I remain ready to implement further fixes from further reviews as needed. So I look forward to more feedback.
Comment #10
bbu23Comment #11
bbu23Hi! I didn't manage to do a full review, but below you have a brief one. This should give an idea:
- There is no dev release. While not mandatory, it's a highly encouraged practice in the Drupal community.
- I can still see some PHPCS warnings when using the "DrupalPractice" standard:
- Kindly review the README file format, including first line, links, sections, headings etc. More in README.md template
- Object oriented hooks are not supported in Drupal 10 unless they're called from the module file. Your module supports both Drupal 10 and 11, therefore you need to add backwards compatibility as described in the article linked in comment #7. In its current form, the module hooks are not invoked at all in Drupal 10.
- Also, you don't have many hooks, but there are 2 service parameters that can tell Drupal 11 to stop procedural hook scan and these are purely optional: Improve performance by preventing unnecessary scanning of procedural hooks and hooks_converted parameter and StopProceduralHookScan attributes have been renamed.. Example if you wish to add them:
- The error message passed to the
addErrormethod is not translatable insrc/Hook/ParagroupHooks.phpline 128.- The
createmethod should returnnew static()instead ofnew self()in src/Form/ParagroupConfigForm.php-
src/Hook/ParagroupHooks.php: The$helperand$field_group_managerarguments are missing their type causing the autowire service to fail. Also, the@var \Drupal\paragraph_group\Paragroup\ParagroupHelperclass doesn't seem to exist anymore (line 31).- The
validateFormis a method that returnsvoid. In thesrc/Form/ParagroupConfigForm.phpreturning a void function result is incorrect.- There is no entity type that has the
paragraph_typeID:$this->entityTypeManager->getStorage('paragraph_type')->loadMultiple();insrc/Paragroup/ParagroupFormData.phpActually, in its current state, the module throws fatal errors in both Drupal 10 and 11, it is unusable. Please ensure that the module is running smoothly with Drupal Core ^10.2 || 11 as described in the info file, and carefully test every aspect of it and/or provide tests to ensure quality and stability.
Comment #12
bbu23Comment #13
daniel.rosenkranz commentedHi bbu23,
Thank you for your detailed review, and apologies for leaving some errors you mentioned unaddressed previously. I have now fixed a disconcerting oversight in my workflow which did cause some of these issues to elude me before, under time pressures I am under in other domains. So regarding your review, I have now:
- Fixed all issues that were causing any WSODs in Drupal 10 and 11. Paragraph Group 3.0.x development branch has now been significantly more thoroughly tested in both versions. The current commit / dev release should now be without these errors, *as well as also passing all Gitlab-CI tests*. The current public 3.0.3 release also remains stable to the best of my knowledge, and is without issue queue notifications thus far after nearly 3 months in production. (I will of course be happy to fix any issues as part of the next public release to emerge from these reviews.)
- Fixed PHPCS issues with DrupalPractice rules in addition to standard Drupal rules, so there are no issues with either now. I have now enabled DrupalPractice rules alongside Drupal rules as a permanent part of my PHPCS workflow.
- Updated my README.md file to match the README.md standard template.
- Restored my paragraph_group.module file which invokes src/Hook/ParagroupHooks.php, and is now compatible with Drupal 10 and 11.
- Per the above point, have also implemented the `hooks_converted` and `skip_procedural_hook_scan` in my paragraph_group.services.yml file to ensure redirection to the relevant old or new hooks system depending on Drupal version.
- Fixed the `$error_msg` variable in the `form_system_themes_admin_form_alter` hook in src/Hook/ParagroupHooks.php so it is now translatable.
- Fixed the `create` method in src/Form/ParagroupConfigForm.php so it returns `new static()` instead of `new self()`.
- Added the relevant type information to the `$helper` and `$field_group_manager` arguments of the constructor in `src/Hook/ParagroupHooks.php`. And set the classname of the helper class correctly to `ParagroupHelperService` instead of ParagroupHelper.
- Removed the return value from the `validateForm` function in src/Form/ParagroupConfigForm.php so that it returns void.
- Fixed the `getParagraphTypes` function in src/Paragroup/ParagroupFormData.php so that it searches for the correct 'paragraphs_type' entity type, instead of 'paragraph_type'.
I have also now released a dev release as suggested, so that reviewers can try it out more easily if needed. As mentioned previously, this release is now better tested across all facets with Drupal 10 and 11. See the dev release at https://www.drupal.org/project/paragraph_group/releases/3.0.x-dev, and also codebase progress and gitlab-ci tests at https://git.drupalcode.org/project/paragraph_group.
Given the still somewhat neglected state of Drupal's admin theme editing within the Paragraphs ecosystem, I remain committed to continually improving Paragraph Group and obtaining it's security approval. I believe that by improving Drupal's content editing and strengthening the usability of recursive Paragraphs, Paragraph Group significantly improves Drupal as a Digital Public Good.
So I continue to welcome all reviews, and will continue to fix all relevant issues raised here.
Comment #14
daniel.rosenkranz commentedHi all,
Noting that this module is still awaiting review since my last post, I have now made some additional improvements to Paragraph Group on a new 3.1.x branch at https://git.drupalcode.org/project/paragraph_group/-/commits/3.1.x?ref_t.... There is also a dev release for this at https://www.drupal.org/project/paragraph_group/releases/3.1.x-dev.
The current 3.0.x branch submitted for security review here remains in place as it was when I submitted my last update above. It still meets all review requests made so far, to the best of my knowledge.
But the new 3.1.x branch indicates the direction I'm hoping to take Paragraph Group module in here. Essentially, what I have done in this new branch is migrate my Javascript implementations to a strict Typescript implementation, and also raise my PHP code level so that it now passes PHPStan Level 10 tests wherever current Drupal core functionality permits this, whilst placing the few Drupal core related issues into a phpstan-baseline.neon file.
As mentioned, this is an experimental branch for now, with 3.0.x remaining definitive for this current security review. It's a significant step which the Drupal Security Advisory community here may find slightly premature, given Drupal core's current lower PHPStan level. So it remains in the separate experimental 3.1.x branch for now.
Nevertheless hopefully this new 3.1.x branch demonstrates my continuing commitment to maintaining Paragraph Group module at the highest possible levels of security and robustness going forward.
Comment #15
vishal.kadamI am changing priority as per Issue priorities.
Comment #16
avpadernosrc/Form/ParagroupConfigForm.php
Since the class is doing more than showing a setting form and saving the submitted values, its parent class should not be
ConfigFormBase.Strings visible in the user interface need to be translatable.
src/Paragroup/ParagroupFieldGroupManager.php
The long description is added when it says something the short description did not say; it also follow the short description, which means it comes before any documentation tag.
New modules, which are compatible with Drupal 10 and higher versions are expected to include type declarations in property definitions, and use property promotion.
Comment #17
daniel.rosenkranz commentedHi avpaderno,
I have now implemented and tested all the fixes you suggested in your comment above in the 2 most recent commits on branch `3.0.x`. The current commit passes all the Gitlab CI tests including PHPCS and PHPStan, as shown by the green tick for the current commit at https://git.drupalcode.org/project/paragraph_group.
Per your comment above, these fixes include:
1. Moving the ParagroupConfigForm class (in src/Form/ParagroupConfigForm.php) from ConfigFormBase to FormBase as its base class.
2. Making remaining untranslated user-visible strings translatable.
3. Ensuring all class-level doc blocks only contain a long description when it says something the heading doesn't, and comes before any further metadata, thus adhering to relevant Drupal and PHPDoc standards.
4. All classes in the module now use concise property promotion syntax (in the class constructors) with fully typed properties.
I appreciate your feedback in this process and look forward to improving and securing the module further.
Comment #18
daniel.rosenkranz commentedComment #19
vishal.kadamI am changing priority as per Issue priorities.
Comment #20
avpadernoThank you for your contribution and for your patience with the review process!
I am going to update your account so you can opt into security advisory coverage any project you create, including the projects you already created.
These are some recommended readings to help you with maintainership:
You can find more contributors chatting on Slack or IRC in #drupal-contribute. So, come hang out and stay involved!
Anyone is welcome to participate in the review process. Please consider reviewing other projects that are pending review. I encourage you to learn more about that process and join the group of reviewers.
I thank also all the reviewers for helping with these applications.
Comment #21
avpadernoComment #23
daniel.rosenkranz commentedHi all,
Thanks to everyone who contributed to this review process, including avpaderno, bbu23 and vishal.kadam. I have acknowledged everyone on the contribution record page.
Please let me know any further requests or issues, and I remain alert to the prompt resolution of all Security Advisory requests. I have also carefully read and noted the readings mentioned above by avpaderno.
So I look forward to stewarding the module responsibly and responsively in collaboration with the community as Drupal continues evolving, particularly as Drupal CMS 2.0, Drupal Canvas / Experience Builder, and Drupal 12 are rolled out in the months and years to come.
In that context, I'm sure Paragraph Group module can both contribute and adapt to these new and exciting developments!