Within my project (a database for natural medicine) I have to store a lot of data with use of paragraphs and in some cases nested paragraphs.

It looks like:

Medical drug
- Various fields
- Rev-Reference to Paragraphs-1 (multiple): "Ingredient / substance" (Content Reference Field) | "Amount" (Text Field) | "Remark" (Text Field)

In other cases I use nested paragraphs

Content-Type
- Various fields
- Rev-Reference to Paragraphs-2: Taxonomy Reference Field | Rev-Reference to Paragraphs-3 (which has also Entity Reference Fields and others)

It would facilitate my work a lot If I could import these data from excisting files via csv import.
And I guess the same kind of structure appear in drupal shop applications maybe using the module Field Collections (which has only minor support in Drupal 8)

If it would be helpful for you we can discuss possible options here.

:-) :-)

Issue fork feeds-2978757

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

ksc created an issue. See original summary.

megachriz’s picture

On a site I import paragraphs separately and I currently use custom code to lookup the parent entity that each paragraph belongs to.

To make it work without custom code currently, you have two options:

  1. Import all entities that are using paragraphs first and then export them again, so you can add the entity ID's to the source files that contain paragraphs.
  2. Import paragraphs for each single entity with a separate feed.

Option 1: add entity ID's to the source file containing paragraphs

  1. Import all entities that are using paragraphs first.
  2. Export the ID's for the imported entities (for example with Views data export).
  3. Add the ID's to the source files that contain paragraphs.
  4. Create a feed type and select "Paragraph" as processor (Feeds 8.x-3.0-alpha2 now supports importing paragraphs separately!).
  5. Add a text field to the feed type, call it for example "Entity type".
  6. Add another text field to the feed type, call it for example "Entity field name".
  7. On the mapping page, map "Feed: Entity type" to "Parent type" and "Feed: Entity field name" to "Parent field name".
  8. Make sure you map a source to "Parent ID" as well.
  9. Setup other mappings that you need.
  10. Create a feed and in the "Entity type" textfield type the machine name of the entity type you imported before. For example: "node" or "taxonomy_term" (entity type machine names are in lowercase and will have underscores instead of spaces). In "Entity field name" type the machine name of the paragraph reference field of the entity type you imported before. For example: "field_paragraph".
  11. Import!

Option 2: import paragraphs for each single entity with a separate feed.

  1. Import all entities that are using paragraphs first.
  2. Create a feed type and select "Paragraph" as processor.
  3. Add a text field to the feed type, call it for example "Entity type".
  4. Add another text field to the feed type, call it for example "Entity field name".
  5. Add an entity reference field to the feed type, call it for example "Entity ID".
  6. On the mapping page, map "Feed: Entity type" to "Parent type", "Feed: Entity field name" to "Parent field name" and "Feed: Entity ID" to "Parent ID".
  7. Setup other mappings that you need.
  8. Create a feed and in the "Entity type" textfield, type the machine name of the entity type you imported before. For example: "node" or "taxonomy_term" (entity type machine names are in lowercase and will have underscores instead of spaces). In "Entity field name" type the machine name of the paragraph reference field of the entity type you imported before. For example: "field_paragraph". In the "Entity ID" field, lookup the entity you want to import paragraphs for.
  9. Import!
  10. Repeat steps 7 and 8 for each entity you want to import paragraphs for.

The future: Tamper plugin "Entity finder"

So as you can see, the workarounds for achieving this without custom code are not so pleasant, but it is at least possible. Once Tamper's "Entity finder" plugin is ported, you'll get nicer options for achieving this. In that case you would refer to the entity where the paragraphs belong to with the entity's title and then use that Tamper plugin to look that entity up. See #2976175: D7 EFQ Finder to D8 Entity finder.

Your source would then look like this (for example):

Node title Paragraph title Paragraph body
Lorem Ipsum Paragraph 1 Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
Lorem Ipsum Paragraph 2 Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
Lorem Ipsum Paragraph 3 Nunc eu lectus nisi, sed vestibulum mauris. Sed tincidunt vehicula sem, eu tincidunt massa ultrices vel.
megachriz’s picture

I looked at my custom code again and unfortunately only importing paragraphs separately is not enough. Although you specify on the paragraph to which entity they belong, they won't appear on the entity. I assume because on the entity itself the order of paragraphs need to be determined and that is not something you can specify by just creating a loose paragraph.

I did the following in my code (and ignored the fact that this could make the order of paragraphs random):

/**
 * Implements hook_ENTITY_TYPE_insert() for 'paragraph'.
 */
function ukkbstudy_paragraph_insert(EntityInterface $paragraph) {
  $parent_type = $paragraph->parent_type->value;
  $parent_field_name = $paragraph->parent_field_name->value;
  $parent_id = $paragraph->parent_id->value;

  if ($parent_type == 'commerce_product') {
    $product = \Drupal::entityTypeManager()->getStorage($parent_type)->load($parent_id);
    if ($product) {
      // Check if product already has a reference to this paragraph.
      foreach ($product->{$parent_field_name} as $item) {
        if ($item->target_id == $paragraph->id()) {
          // Paragraph found. Abort.
          return;
        }
      }

      $product->{$parent_field_name}[] = $paragraph;
      $product->save();
    }
  }
}

In my case I only was importing paragraphs for Commerce products, but you can remove the 'if' if you want for all paragraph types making sure that they appear on the entity that they refer to. I constrained it to 'commerce_product' as I know I'm not importing paragraphs for any other entity type so I can save run time by skipping the code execution above in case of saving a paragraph for an other entity type.

ksc’s picture

Thanks a lot for your help, I appreciate your support!!!!

I´m not into php, the time I did programming is more than 25 years ago (fortran, pascal, basic, ...) :-)
I understand a bit of the code but don´t know where to put it.

Yes, it seems that the revision reference field contains the paragraph ID and the paragraph itself stores its own ID and a parent ID. I checked this with a view. "Garbage" paragraphs still have the parent ID.
So all those ids must be valid and set when importing paragraphs.

I just tell you what´s in my head:

It could be solved by "nested" oder by "linked" feeds imports (which I can´t program). Which means that a feed type could consist of more than one entity type (nested) oder that feed types could be linked together first-> second -> third?.

For each item/record of the fetched file it would run through the defined feed steps. In my example:
1. Step: Import of content and its "normal" fields or check if it already exists.
2. Step: Find the next free paragraph ID and set the referenced field value to this ID.
3. Step: Pass the actual paragraph ID to the next step
4. Import the paragraph: set its IDs (own and parent) and store the field values
5. Goto next item/record

I think the import would need to run this way (all steps for each item/record) because during import s.o. could create a paragraph in between, which could mess up the IDs.

I don´t know if it is complicate to program.

But there are some open questions:
1. The only unique property of paragraph-items is their id. So how to update excisting data? Only by knowing their id or by checking all values of all fields within the paragraph.
2. How the UI could look like? Both have to read the same file and need to be linked in a way (1. -> 2.) and the linking field (paragraph ID) must be defined somewhere.

hussein-elhussein’s picture

Hey guys maybe this module is useful: https://www.drupal.org/project/feeds_para_mapper

steffenr’s picture

@hussein-elhussein unfortunately this module is only available for D7 and not D8...

hussein-elhussein’s picture

@SteffenR unfortunately yes, but i'm working on d8 support, keep an eye on this project, it might take a week or so

mikgreen’s picture

I'll describe a way we're importing paragraph references currently.

1. Import paragraphs separately.
And make sure you import UUID in Feeds item: Item GUID.

2. Paragprahs module already has limited feeds support. We need to override it.
Put this hook in a custom module.

function feeds_custom_feeds_target_plugins_alter(array &$definitions) {
  // Our plugin serves same target type as the one from paragraphs module.
  // So we must disable that one.
  unset($definitions['paragraphs']);
}

3. Paragraphs reference is of type "entity_reference_revisions" which is similar to "entity_reference", so we can reuse that with some modifications.
Put the attached file EntityReferenceRevisions.php in your custom modules "src/Feeds/Target/".

4. In the content importer: import paragraph fields target_uuid in desired destination paragraphs field.
Use this as configuration:

Reference by: paragraph.feeds_item
Feed item: Item GUID
mikgreen’s picture

StatusFileSize
new12.87 KB
hussein-elhussein’s picture

guys the module is tested with Drupal 8 and ready now, i hope it helps

socialnicheguru’s picture

This module is available now: https://www.drupal.org/project/feeds_para_mapper

Does it solve your problem?

dpw’s picture

It took several attempts that didn't work, but I successfully have imported paragraphs from a CSV and assigned them to pre-existing nodes using the methods described in #2 and #3 (specifically, option 1 in #2). I also ran the EntityFinder patch (2976175-16.patch) and used it to lookup entities and assign the value to the parent ID. I already had the nids of the existing parent nodes, but assigning those directly to the parent ID didn't work (see possible explanation in #3).

I tried using the feeds_para_mapper module to update existing nodes but to add new paragraphs using the fields exposed through this module, but I couldn't get this working. It seemed to reset values of the existing nodes and complained if required values at the node level were missing, but those had already been created. I just wanted the paragraphs to be created... anyway, as I said, this didn't work for me.

Anyway, I'm happy this finally worked! Thanks @MegaChriz

rusticdoozy’s picture

@hussein-elhussein https://www.drupal.org/project/feeds_para_mapper has only dev release for D8, and the dev release shows empty values with nested paragraphs (which is the vital piece for nesting paragraphs), it has already been reported as an issue, would there be any update on the pending issues soon?

danharper’s picture

I have managed to do this using the post save event dispatcher, once the entity is inserted I find the parent node and save the paragraph entity into it.

I just need to do the same when the items are deleted.

Cheers Dan

kswamy’s picture

@danharper Looks like what you have done seems to be more simple and straightforward. It would be great if you can share your code here so that others can also use the custom code as this is a very familiar use case everyone would come across.

Thanks in advance

mehul.shah’s picture

Thanks, @MegaChriz for this #2 and #3. It did work for me.

Just an update in #2 make sure you untick the Authorize under ADVANCED SETTINGS while creating feeds for the Paragraphs. Otherwise, you will get an error as "User is not authorized to", as the PAragraph does not have any User associated with it directly.

danharper’s picture

@kswamy

I have something like this, my code is specific and is actually appending paragraphs.


namespace Drupal\your_module\EventSubscriber;

use Drupal\feeds\Event\EntityEvent;
use Drupal\feeds\Event\FeedsEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 *
 */
class FeedsSubscriber implements EventSubscriberInterface {

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    $events = [];
    $events[FeedsEvents::PROCESS_ENTITY_PRESAVE][] = 'presave';
    $events[FeedsEvents::PROCESS_ENTITY_POSTSAVE][] = 'postsave';

    return $events;
  }

  /**
   * Acts on presaving an entity.
   *
   * @param Drupal\feeds\Event\EntityEvent $event
   *
   * @return Drupal\feeds\Event\EntityEvent $event
   */
  public function presave(EntityEvent $event) {
  }

  /**
   * Acts on presaving an entity.
   *
   * @param Drupal\feeds\Event\EntityEvent $event
   *
   * @return Drupal\feeds\Event\EntityEvent $event
   */
  public function postsave(EntityEvent $event) {
    $feed = $event->getFeed();
    $feeds = ['oe_references', 'sub_components', 'dimensions'];
    $id = $feed->type->entity->id();
    if (in_array($id, $feeds)) {
      $entity = $event->getEntity();
      $parent_field_name = $entity->parent_field_name->value;
      $parent_id = $entity->parent_id->value;
      $vid = \Drupal::entityTypeManager()->getStorage('node')->getLatestRevisionId($parent_id);
      $part = \Drupal::entityTypeManager()->getStorage('node')->loadRevision($vid);
      $paragraph_references = $part->get($parent_field_name)->referencedEntities();
      $paragraph_references_id = [];
      if ($paragraph_references) {
        foreach ($paragraph_references as $paragraph_reference) {
          $paragraph_references_id[] = $paragraph_reference->id();
        }
      }
      if (!in_array($entity->id(), $paragraph_references_id)) {
        $fields = ['field_oe_references', 'field_sub_components_', 'field_dimensions'];
        if (in_array($parent_field_name, $fields)) {
          if ($part) {
            $part->{$parent_field_name}[] = $entity;
            $part->save();
          }
        }
      }
    }
  }

}
drupalsilm’s picture

@MegaCriz, I have used Option 1 in your post #2 to import multiple paragraphs of the same type to a parent content type. I can see the imported paragraphs using Views, and they include the correct Parent IDs but they are not visible. A view of the parent item does not show them either, so they are somewhere in the system but not properly linked, as described in #12.

Where would I actually place the code you have provided in #3, and how would I execute it? Do I need to build a new custom module or is there an easier way, as I don't know how to get started?

I also tried feeds_para_mapper and hit an error when importing multiple paragraphs.

Any help would be brilliant. Thanks in advance.

luizsgpetri’s picture

I have the same issue as #18. A combination of #2 + #3 worked for me.

luizsgpetri’s picture

Shouldve-been-farmer’s picture

@MegaCriz, @danharper, Any kind Drupal sole, please help!!

I can not get this to work. I have a paragraph type (education) which contains 5 text fields -
field_fcid - (old drupal 7 field collection id and the unique value for feed)
field_graduated, field_level, field_school, and field_degree.

I added field_edu_paragraph to the user profile which is of field type Entity reference revisions (I feel this is a little odd but ok).

My csv contains both field_fcid and the drupal 8 userid (paragraph parent id) the paragraph will be attached to. I defined parent type (user) and parent field name (field_edu_paragraph).

I run the import and the paragraphs are all imported, but not attached to the user profile. In the database, the paragraphs_item table and paragraphs_item_field_data table look great.

The user__field_edu_paragraph table does not get populated. I have tried a custom module like #3 and I am a little confused by #17 (I tried putting that in a custom module as well, but not sure I did that correctly) I also tried feeds_para_mapper, but got a whitescreen on the mapping screen.

I am not sure if this has to do with the paragraph feed not being able to write to the user entity (prob) or if this has something to do with the delta of the paragraph items not being defined.

feeds: 3.0.0-alpha10
feeds_ex: 8.x-1.0-alpha4
feeds_tamper: 8.x-2.0-beta2

Rocking in a corner awaiting a response :(
Thanks for any help!

This is my first post!!!

ivnish’s picture

The same as #18

lemmy_kilmister’s picture

Exactly the same as #21

cdeces’s picture

I've tried #2-Option 2 with #3 code in its own custom module.
The paragraphs are properly imported, but the database table corresponding to the field parent_field_name stays empty.

Apparently, the function in #3 is never called.

I've also tried #17 as a replacement of #3, but still no luck.

eabquina’s picture

I tried the feeds_para_mapper module latest Dev release and I confirm it works. Although at the moment, it can only work with one paragraph field per entity. Sharing here in case someone finds their way here too:

https://www.drupal.org/project/feeds_para_mapper/issues/3160801#comment-...

eabquina’s picture

Meanwhile, I went ahead and tried to import the Paragraphs direct with the Node entity feed. I was able to update or create the paragraphs along with the entity. However, there are only a select field types that are supported:

- Text (formatted)
- Text (formatted, long)
- Text (formatted, long, with summary)

I find it weird that Text (plain) fields are not supported though. Any other field I tried doesn't work (number, references etc).

Zain_98’s picture

I've tried #2 and visualized the results in views by contextually filtering the Parent ID but without #3 since I couldn't understand where to place the code, whether by creating a custom module or not. I have installed the feeds_para_mapper module but no luck with other field types (entity references,integers...etc.).Is there any other way to import multiple paragraphs for any field type using Feeds ? Need some help ASAP !

megachriz’s picture

@Zain_98
The code example from #3 should go into a custom module and "commerce_product" should either be replaced with the entity type you are importing for or the condition should be completely left out.

#2 can indeed not work without #3.

Zain_98’s picture

@MegaChriz Thank you for the clarification, however I ask of you the steps of creation and implementation of this custom module to include #3 because I am not experienced with the latter. I would be very grateful if I could complete this final point for my project.

megachriz’s picture

@Zain_98
Steps are:

  1. Create a directory and give the directory the name of your module. Use only lowercase letters and underscores. No spaces.
  2. Inside this folder, create two files: mymodule.info.yml and mymodule.module where 'mymodule' represents your module name.
  3. In the mymodule.info.yml file specify the metadata of your module:
    name: 'My Module'
    description: 'Helps with importing paragraphs.'
    package: Custom
    type: module
    core: 8.x
    core_version_requirement: ^8 || ^9
    

    In this file 'name' is actually the label of your module, not the machine name, so there uppercase letters and spaces are allowed.
    Details about the info.yml file: https://www.drupal.org/docs/creating-custom-modules/let-drupal-know-abou...

  4. In mymodule.module, the first line should be <?php. After that you can paste the code from #3. Replace 'ukkbstudy' with the name of your module.

Does this help?

On https://www.drupal.org/docs/creating-custom-modules there is a lot more information about creating your own modules, but there's a lot of information there that you don't need to know for this specific situation. You can use it as a reference.

Zain_98’s picture

@MegaChriz
Yes indeed what you wrote helps. The issue I just encountered is that once a created the module and went through the steps, I noticed that nothing changed when I imported since maybe I must be missing something(no namespaces in code...etc.). Below is the code (mymodule.module) showing you what I have done. On a side note, I replaced 'commerce_product' as you can see with 'node' for trial.

<?php

/**
* Implements hook_ENTITY_TYPE_insert() for 'paragraph'.
*/
function paragraphs_import_paragraph_insert(EntityInterface $paragraph) {
$parent_type = $paragraph->parent_type->value;
$parent_field_name = $paragraph->parent_field_name->value;
$parent_id = $paragraph->parent_id->value;

if ($parent_type == 'node') {
$product = \Drupal::entityTypeManager()->getStorage($parent_type)->load($parent_id);
if ($product) {
// Check if product already has a reference to this paragraph.
foreach ($product->{$parent_field_name} as $item) {
if ($item->target_id == $paragraph->id()) {
// Paragraph found. Abort.
return;
}
}

$product->{$parent_field_name}[] = $paragraph;
$product->save();
}
}
}

megachriz’s picture

I must be missing something(no namespaces in code...etc.)

Ah, I see I overlooked something.
Add use Drupal\Core\Entity\EntityInterface; as well (after <?php and before the other code). I would expect though that errors would be logged.

Your code would then probably be this:

<?php

use Drupal\Core\Entity\EntityInterface;

/**
 * Implements hook_ENTITY_TYPE_insert() for 'paragraph'.
 */
function paragraphs_import_paragraph_insert(EntityInterface $paragraph) {
  $parent_type = $paragraph->parent_type->value;
  $parent_field_name = $paragraph->parent_field_name->value;
  $parent_id = $paragraph->parent_id->value;

  if ($parent_type == 'node') {
    $product = \Drupal::entityTypeManager()->getStorage($parent_type)->load($parent_id);
    if ($product) {
      // Check if product already has a reference to this paragraph.
      foreach ($product->{$parent_field_name} as $item) {
        if ($item->target_id == $paragraph->id()) {
          // Paragraph found. Abort.
          return;
        }
      }

      $product->{$parent_field_name}[] = $paragraph;
      $product->save();
    }
  }
}

Note: To post code and have it display formatted on drupal.org, put your code between <code>-tags.

megachriz’s picture

Forgot to mention, you also need to enable the newly created module and perhaps flush caches.

Zain_98’s picture

@ MegaChriz
Thank you so very much for your help and time, it finally worked , the paragraphs are now correctly imported and seen in the editor of the content !

Zain_98’s picture

@MegaChriz
Hello, I hope you are doing well ! I have a question based on the code below :

<?php

use Drupal\Core\Entity\EntityInterface;

/**
 * Implements hook_ENTITY_TYPE_insert() for 'paragraph'.
 */
function paragraphs_import_paragraph_insert(EntityInterface $paragraph) {
  $parent_type = $paragraph->parent_type->value;
  $parent_field_name = $paragraph->parent_field_name->value;
  $parent_id = $paragraph->parent_id->value;

  if ($parent_type == 'node') {
    $product = \Drupal::entityTypeManager()->getStorage($parent_type)->load($parent_id);
    if ($product) {
      // Check if product already has a reference to this paragraph.
      foreach ($product->{$parent_field_name} as $item) {
        if ($item->target_id == $paragraph->id()) {
          // Paragraph found. Abort.
          return;
        }
      }

      $product->{$parent_field_name}[] = $paragraph;
      $product->save();
    }
  }
}

Is there a way to make the parent ID of a paragraph act as an integer field (which works as an ID) instead of the nid ?

In other words, the parent ID of a paragraph references the NID of it's parent type; what I am trying to do is allow the PID to become another field type since it worked with the Node Processor. I thought about the

parent_id -> value line

but couldn't understand it.

vasyok’s picture

StatusFileSize
new123.2 KB
new11.06 KB
new9.46 KB
new10.98 KB
new26.35 KB
new25.7 KB
new2.59 KB
new3.8 KB
new6.22 KB
new15.97 KB

Hello, drupal guru's!

MB I do something wrong, but import not working.

Here is my workflow.

0 - Custom module (yes i turned it on, and flush all caches).
code

1 - Paragraphs field on node

2 - Field settings
Field settings

3- Fields on paragraph
Fields on paragraph

4 - Feeds import mappings
Feeds import mappings

5 - Feed
Feed

6 - Source table
source table

7 - Feeds report
Feeds report

8 - view that show paragraphs
view that show paragraphs

9 - result
result

interlated’s picture

I am hacking through feeds_para_mapper which is working except for referenced entities. https://github.com/jrobens/drupal-feeds-para-mapper

afarsal’s picture

@MegaChriz
Thank you so very much for your help and time, it worked, the paragraphs are correctly imported and seen in the editor of the content !

One thing doesn't work like same #36 (picture and video) for entity type with paragraphs-Entity reference revisions like Carousel, video, modal, etc. paragraphs.
How to create and map the type of paragraph corresponding to the entity like carousel (or video, modal, etc.) to attach the slides content (pictures) ?

Thanks very much @MegaChriz

interlated’s picture

@afarsal Feeds para mapper has an issue and I got entity mapping working for my cases - taxonomy and referenced nodes https://www.drupal.org/project/feeds_para_mapper/issues/3255360

afarsal’s picture

Thanks @interlated. but does not work on [D9], same issue : https://www.drupal.org/project/feeds_para_mapper/issues/3250949
when I open the page mapping I only see a white screen.
@MegaChriz' solution works fine (and for taxonomy too).
But in #32, how to choose the type of paragraph (carousel, video, modal) ?

interlated’s picture

@afarsal I've developed extensions in an issue fork that is works in my test case - https://git.drupalcode.org/issue/feeds_para_mapper-3255360

kazah’s picture

Assigned: Unassigned » kazah
afarsal’s picture

I started working again my paragraphs import with feeds after a few days of interruption. Finally, the solution of @MegaChriz works very well. I created first the paragraphs (Type Carousel) and then I just updated the paragraphs with the correct data.

Really thank you all <:)

roshnykunjappan’s picture

Thank you for posting this issue. The solution by @MegaChriz worked for me.

kazah’s picture

Please explain how can I import content like in my case below:

There is a content type - cake
It has a field (Entity reference revisions) - berries

There is a paragraph - berries
It has fields:
- title (Entity reference)
- quantity (integer)

So the import feed should be like this:
Cake 1 ---- Strawberry, 2; Raspberry 1
Cake 2 ---- Strawberry, 1; Raspberry 3
....

irinaz’s picture

@kazah, you would need additional custom code provided by @MegaChriz to map your case.

Complete solution for paragraphs import via UI for BackdropCMS (Drupal community edition) was posted yesterday by @jenlampton https://github.com/backdrop-contrib/feeds_para_mapper. I hope that eventually this solution can be ported to D9.

irinaz’s picture

irinaz’s picture

kazah’s picture

I appreciate your help...but now I have another problem.

After a lot of research and installation of various patches ... Now I see my field in the mapping section.

The problem is that I have two fields:
1. integer
2. entity reference

These fields are not visible, I added a text field (for testing) and it became visible in mappings.

What I'm missing? Why other fields are not showing?

deelite’s picture

Hi, thanks for you time and help, @MegaChriz!

I have a node type with a paragraph field. I imported nodes and got all fields of the paragraph. Worked.

But in this paragraph I have another one nested. The nested one is an image field and some text fields (copyright, caption, etc.).

Since 1 week I try to import these nested paragraphs.

I tried option 1 and checked the parent ids of the referencing paragraphs. I didn't get the nested paragraphs imported into the parent ones.

2 questions I have:

Is importing nested paragraphs into paragraphs possible in principle?

Option 2, 5.: Which reference field type do I have to use? This point I didn't understand.

saahbaa’s picture

Is there any solution for importing the paragraphs? I really need this feature

kazah’s picture

Assigned: kazah » Unassigned
irinaz’s picture

There is a complete working solution for importing paragraphs that has beed developed for Backdrop CMS based on https://www.drupal.org/node/2912746/git-instructions/8.x-1.x/nonmaintainer

You can find the code https://github.com/backdrop-contrib/feeds_para_mapper

It would be great to get help or sponsor backporting this feature to D10.

interlated’s picture

@irinaz I presume feeds_para_mapper is based on https://www.drupal.org/project/feeds_para_mapper. Backdrop is basically d7. There is a d8 branch of https://www.drupal.org/node/2912746/git-instructions/8.x-1.x/nonmaintainer which mostly works. Does not map reference fields.

As per https://www.drupal.org/project/feeds_para_mapper/issues/3255360

Which led to me extending to https://github.com/jrobens/drupal-feeds-para-mapper

irinaz’s picture

StatusFileSize
new368.35 KB

@interlated, thanks for working on this issue! Any chance you can add your code to https://git.drupalcode.org/project/feeds_para_mapper/-/tree/8.x-1.x - it is easier to test and extend when related code in the same system :)

One critical requirement is to be able to map Hosting Entity ID
screenshot

I am not sure if paragraphs import should be part of feeds core or continue live in a separate module.

kazah’s picture

I have some specific use case, as I wrote above in #45:

So how I manage to solve it.
If someone could provide the easier solution, you're welcome.

My specification:

1. Need to create paragraphs at the same time as nodes are imported.
2. Paragraph has two fields: title (Entity reference) and quantity (integer).
3. Csv file has this structure:
***Vendor code***Title***Berries
***n1***Cake 1***Strawberry, 2;Raspberry 1

1. Create custom module: paragraphs_import
2. Create paragraphs_import.services.yml with:

services:
  paragraphs_import.berries:
    class: Drupal\paragraphs_import\EventSubscriber\Berries
    tags:
      - { name: event_subscriber }	

3. Create Berries.php in

paragraphs_import/src/EventSubscriber

with:

** all comments in code

<?php

namespace Drupal\paragraphs_import\EventSubscriber;

use Drupal\feeds\Event\EntityEvent;
use Drupal\feeds\Event\FeedsEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Reacts on articles being processed.
 */
class Berries implements EventSubscriberInterface {

	/**
	* {@inheritdoc}
	*/
	public static function getSubscribedEvents() {
		$events[FeedsEvents::PROCESS_ENTITY_PRESAVE][] = 'presave';
		return $events;
	}


	/**
	* Set corresponding values to paragraph fields.
	*/	
	public function presave(EntityEvent $event) {
	
		// Check if this is the feed type we want to manipulate.
		if ($event->getFeed()->bundle() !== 'cakes') {
			// Not the feed type that we are interested in. Abort.
			return;
		}	

		/**
		* Get an item's value. Return result:
		*
		* array [
		*  0 => "Strawberry,2"
		*  1 => "Raspberry,1"
		* ]
		*/
		$berries = array_filter($event->getItem()->get('berries'));

		if ($berries) {
			/**
			* Separate values by comma. Return result:
			*
			* array [
			*  0 => array [
			*	0 => "Strawberry"
			*	1 => "2"
			*  ]
			*  1 => array [
			*	0 => "Raspberry"
			*	1 => "1"
			*  ]
			* ]
			*/		
			$berries_list = array();
			foreach ($berries as $key => $value) {
				$berries_list[] = explode(',', $value);
			}
			
			/**
			* Change title of referenced field with it nid
			*
			* array [
			*  0 => array [
			*	0 => "2082"
			*	1 => "20"
			*  ]
			*  1 => array [
			*	0 => "2085"
			*	1 => "10"
			*  ]
			* ]
			*/
			$berries_array = array();
			foreach ($berries_list as $key => $value) {
				// get node id by title
				$nid = \Drupal::entityQuery('node')
				->condition('title', $value[0])
				->condition('type', 'berries')
				->execute();
				
				// get only first result
				$value[0] = array_shift($nid);

				$berries_array[] = $value;
			}

			
			$entity = $event->getEntity();
			
			if ( isset($entity->field_berries) ) {
				// Load our paragraphs from field berries in node
				$paragraph_berries = $entity->field_berries->referencedEntities();
				
				// match values from array with fields in paragraphs
				foreach ($paragraph_berries as $key => $p) {			
					foreach ($berries_array[$key] as $k => $v) {
						if ($k == 0) {
							$p->set('field_title', $v);
						}
						if ($k == 1) {
							$p->set('field_quantity', $v);
						}
					}
				}	
			}
			

		}
	
	} // end presave function	

}

4. In Feeds Tamper need to add plugin EXPLODE with ; *semicolumn* to our paragraph.

darshanb87’s picture

Hello @MegaChriz,

I am on Drupal 10.2.2 version. I am using feeds and paragraph modules to import paragraph data. I followed #2 (option 1) and #3 and indeed its working fine. However, when I checked table node__field_(paragraph_field_name) in database. I find that every time I run the feed import that data are inserting in this table keeping old data as it is. Actual expected behavior should be previous old data should be deleted and only new data should remain in this table. There should be no orphan data in this table which leads increasing database size.

Anyone else facing this problem in table node__field_(paragraph_field_name)?
Is there any solution that this should not happen?

interlated’s picture

@irinaz I'm happy to attempt to merge the changes for paragraph references. The changes were pretty large, so what do you think is the best way?

interlated’s picture

I've updated https://www.drupal.org/project/feeds_para_mapper/issues/3255360. I'm looking at the test cases. EntityReferenceTest should handle this case? Near enough? Is it sensible to merge here or keep a different project.