Strapi plugin logo for Parent Child Relationships

Parent Child Relationships

Strapi plugin to create and manage parent-child relationships between content types using custom fields

Strapi Plugin: Parent-Child Relationships

✨ Features

  • Custom Fields (Introduces two new custom fields: Parent-Child Relation and Dynamic Relation Root)
  • Hierarchical Relationships (Enables creation and management of parent-child structures between content types)
  • Contextual Filtering (Automatically filters and displays relevant child content based on parent selection)
  • Flexible Configuration (Supports various settings for fine-tuning relationship behaviors)
  • Advanced Filtering Options (Includes additional filtering capabilities like current table column filter)
  • Common Relational Table Support (Allows filtering based on shared relational fields across collections)
  • Custom Query Parameters (Passes dynamic or static parameters to child relation services)
  • Dynamic Relational Field Display (Uses Dynamic Relation Root to conditionally show/hide relational fields based on user selection)

🖐 Requirements

  • Node.js: >=14.19.1
  • NPM: >=6.x.x

Supported Strapi versions:

  • Strapi >=4.4.0 <5.0.0

⏳ Installation

To install the plugin, run the following command in your Strapi project directory:

With npm:

npm install strapi-plugin-parent-child-relationships

With yarn:

yarn add strapi-plugin-parent-child-relationships

🖐 Usage

After installation you will find two custom fields at the custom fields section of the content-type builder with the following names:

  • Parent-Child Relation
  • Dynamic Relation Root

content-type-builder-custom-fields


📝 Overview

The Parent-Child Relationships plugin for Strapi allows you to create and manage hierarchical relationships between content types using custom fields. Enhance your content organization and establish clear hierarchical connections within your Strapi application. This functionality is ideal for structuring related data, such as a Brand -> Model -> Version hierarchy. It ensures contextual filtering and improves content organization and efficiency.

Default Strapi Relationships

In Strapi by default, relationships between content types are managed using standard relation fields. These allow you to link different content types but lack advanced features for managing hierarchical relationships such as parent-child structures


default-strapi-relationships


Parent-Child Relationships with the Plugin

The Parent-Child Relationships plugin introduces custom fields that extend default relationships, enabling you to filter and display data in a parent-child manner. For example, selecting a brand filters models associated with that brand, and selecting a model filters the available versions.


parent-child-relationships


🔧 Configuration - Setting Up a Parent-Child Relationship

In this section we will use the following custom field:

Parent-Child Relation

parent-child-relation-custom-field

Where you have the ability to configure some BASIC and ADVANCED SETTINGS. For now, it's not necessary to understand the purpose of every field in the settings I'm about to list. I’ll explain how to configure them step-by-step using examples.

BASIC SETTINGS

  • Name
    (This is the only default Strapi basic settings field)

  • Relation name

parent-child-relation-custom-field-basic-settings

ADVANCED SETTINGS

  • parent

  • current table column

  • child table column

  • common relational table

  • current table column filter

  • db_name: param_name - one per row

  • static_value: param_name - one per row

parent-child-relation-custom-field-advanced-settings


Example: Car Collection

In this section, we'll demonstrate the configuration of a parent-child relationship using only the following options available in the Parent-Child Relation custom field settings:

BASIC OPTIONS:

  • Name
  • Relation name

ADVANCED OPTIONS:

  • parent
  • current table column
  • child table column

In this example, we will configure a parent-child relationship using the Parent-Child Relationships plugin by creating a Car collection type. This collection will include the following relational fields:

  • brand (Relationship with the Brand collection) - e.g., Audi, BMW
  • model (Relationship with the Model collection) - e.g., A1, A3, X5, X6

When a specific brand is selected—let's say Audi—our objective is to dynamically filter and display only the associated models for that brand (e.g., A1, A3) while excluding unrelated models.

Achieving Contextual Filtering Using the Parent-Child Schema

To accomplish this, we need to establish a parent-child hierarchy where selecting a brand automatically filters the available model options. This setup requires that the model results are dynamically filtered based on the identifier of the selected parent brand.

For our example, we will use the code field in the Brand collection and the brand_code field in the Model collection to create this relationship. By linking these two fields, we can ensure that when a brand is chosen, only its corresponding models are displayed.

Collections Schema

Brand

namecode
AudiAUD
BMWBMW

Model

namebrand_codemodel_code
A1AUDAUD_A1
A3AUDAUD_A3
X5BMWBMW_X5
X6BMWBMW_X6

In this scheme, each brand has a code that can be used as a unique identifier to group the associated models. The brand_code field in the Model collection is used to filter the displayed models based on the selected brand.

For instance, models belonging to Audi have a brand_code of "AUD", while models belonging to BMW use "BMW".

Leveraging the Parent-Child Relation Custom Field in Strapi

The Parent-Child Relation custom field is crucial for defining the hierarchical relationships between collections in Strapi. In our example, we will focus on the following fields:

  • code in the Brand collection
  • brand_code in the Model collection

While these fields do not share identical names, it is essential that their values match to establish the desired parent-child filtering effect.

For instance, when the Audi brand is selected, which has a code of "AUD", the custom field will automatically filter and display only those models that have a corresponding brand_code of "AUD".

Step-by-Step Configuration in Strapi

Step 1: Create the Car Collection

Begin by creating the Car collection type in Strapi. Ensure that it includes the necessary relational fields (brand and model) that will require filtering.


Content Type Builder - Creating Car Collection

Step 2: Add Parent-Child Relation Custom Fields

Next, add a Parent-Child Relation custom field for each of the relational fields involved in the filtering operation.

  • Brand Field: Set the Relation name as brand

Note: The Name chosen for this field is c_brand. This is just my convention to indicate that c_brand is a custom field related to the Brand collection. You can enter any name in this field; it has no restrictions. In contrast, the Relation name field must match the name of the related relational field to which it is linked. If you try to enter a relation name that does not exist in the collection (in our case, Car), this will not allow you to proceed when you click on the finish button, the window will remain open until a valid relation name is provided.

Content Type Builder - Adding Custom Field for Brand

  • Model Field: Set the Relation name as model.

Content Type Builder - Adding Custom Field for Model

Final Overview of Car Collection Type Fields

Here is a visual overview of the fields configured for the Car collection type:

Content Type Builder - Car Configuration Fields Overview

Advanced Configuration of Filtering Logic

  • Brand Field Configuration: The c_brand field will be configured without a parent.

    • Inside the current table column settings option, insert code (the field related to the code in the brand collection).

    • Inside the child table column settings option, insert brand_code (the field related to the brand_code in the child relation model collection).

This configuration ensures that the models displayed have a matching brand_code corresponding to the selected brand's code.

Advanced Settings - Brand Field

  • Model Field Configuration: For the model field (c_model), specify that its parent is c_brand.

    • Inside the parent settings option, choose c_brand as the parent field. This ensures that the filtering logic will be based on the brand selected in the c_brand field.

Advanced Settings - Model Field

This configuration establishes a dependent relationship where the c_model field (child) is filtered according to the selected c_brand field (parent), effectively creating a parent-child relationship between the two.

You have now successfully set up a hierarchical relationship between brand and model in your Car collection type by specifying parent-child filtering rules.

Customizing the Content Manager View

In the Content Manager, you will now see both the default Strapi fields and the custom fields whit the same name. This is expected behavior.

Content Manager - Car Collection Fields Overview

To resolve this and display only the custom fields, use the Configure The View feature to hide the default fields.

Content Manager - Configure The View

Final Output

Now, you can start creating entries with the correctly filtered brand and model relationships.

Content Manager - Creating Brand and Model Relationships

## Next Step: Extending Parent-Child Relationships to Versions

Now that we’ve learned how to create parent-child relationships between brands and models, we can extend this concept further by introducing versions.

Objective: Filter Versions Based on Model Selection

The goal is to dynamically filter and display only the versions associated with a selected model. This setup requires establishing a parent-child relationship between the selected model and its corresponding versions.

Collections Schema

Brand

namecode
AudiAUD
BMWBMW

Model

namebrand_codemodel_code
A1AUDAUD_A1
A3AUDAUD_A3
X5BMWBMW_X5
X6BMWBMW_X6

Version

nameversion_code
Sport line editionAUD_A1
Business editionAUD_A1
S lineAUD_A3
xDrive sportBMW_X5
xDrive cityBMW_X5
xDrive competitionBMW_X6
xDrive sportBMW_X6
xDrive 4X4BMW_X6

How It Works

  • Each model has a model_code that can be used as a unique identifier for grouping associated versions.
  • The version_code field in the Version collection is used to filter the versions based on the selected model.

For example, versions belonging to the A1 model will have a version_code of "AUD_A1", and versions for the X5 model will use "BMW_X5".

Setting Up Version Filtering in the Content Type Builder

Let's begin by adding a relational field for version in the Car collection type and creating the custom field for the newly added relational field.

Content Type Builder - Adding Version Field

Next, we will configure the custom field for version and specify that its parent is the custom field c_model.

Content Type Builder - Configuring Version Field Parent

Finally, we need to configure the c_model field, defining the fields involved in filtering the versions based on the selected model.

Content Type Builder - Configuring Version Filter by Model

Content Manager View with Version Filtering

In the Content Manager, you will now see three default relational fields provided by Strapi:

  • brand
  • model
  • version

And three custom fields you have created:

  • c_brand
  • c_model
  • c_version

In the video below, you can see the difference between using the original fields (the first three in a row, right below the name), which display all possible results without any filtering, and the custom fields displayed in separate rows.

Notice how the default fields show no filtering, while the custom fields provide contextual filtering based on your selections. You cannot select a model without first choosing a brand, and similarly, you cannot select a version without first selecting a model.

In Configure The View, you can hide the default fields and display only the custom fields to streamline the interface.

This entire process is demonstrated in the video.

Content Manager - Managing Brand, Model, and Version Relationships


Advanced Field Options: Explanation of Additional Fields

In this section, we'll explain some advanced options available in the Parent-Child Relationship settings, such as:

  • common relational table
  • current table column filter
  • db_name: param_name - one per row
  • static_value: param_name - one per row

Advanced Field Options in Parent-Child Relationship


current table column filter

The current table column filter field allows you to add an extra layer of filtering to the results returned by a relation. Let’s look at an example.

Suppose we have an additional field called segment in our Versions collection:

Versions

nameversion_codesegment
Sport line editionAUD_A1sport
Business editionAUD_A1city
S lineAUD_A3sport
xDrive sportBMW_X5sport
xDrive cityBMW_X5city
xDrive competitionBMW_X6sport
xDrive sportBMW_X6sport
xDrive 4X4BMW_X6suv

With the current table column filter, you can apply a JSON filter to limit the results further.

For instance, if we only want to display sports versions of cars, we can apply the following filter:

1{ "segment": "sport" }

By adding this filter, only the sports versions will be displayed in the results.

For example, if we select the brand BMW and the model X5, without the filter we would see:

  • xDrive sport
  • xDrive city

With the filter applied, we will only see:

  • xDrive sport
Example of the current table column filter in action, showing only sports versions of the BMW X5 after filtering.

It's possible to create more complex filters.

For example, let's say we want to introduce an additional condition, where we only want versions whose names contain xdrive (case-insensitive).

We can modify the previously applied filter like this:

1{ "segment": "sport", "name": { "$containsi": "xdrive" } }

Now, the results will only return versions where the segment is equal to "sport" and the name contains the word "xdrive" (case-insensitive).


common relational table

To understand how the common relational table filter works, let's walk through an example.

Suppose we've already created several entries in the Car collection. Now, we want to associate the Car collection as a relational field in another collection called Lead with the following relational fields:

  • car (Relationship with the Car collection)
  • options (Relationship with the Option collection)

Collections Schema

Fields marked with * are relational fields.

  • brand*
  • model*
  • version*

Cars

namebrand*model*version*
BMW X5 SPORTBMWX5xDrive sport
BMW X6 COMPETITIONBMWX6xDrive competition

Cars have a relationship with brand, model, and version.

Options

nameversion*
co-pilot packS line
color pure whitexDrive competition
full leadxDrive competition

Options have a relationship with version*.

As you can see, both Cars and Options share a common relational field, version*.

Filtering Options Based on a Common Relation

During the creation of a Lead, after selecting a specific car (for instance, BMW X6 COMPETITION), we want to filter the Options displayed based on the common relational field they share—version.

This means only the following options should be displayed:

  • color pure white
  • full lead

Both the BMW X6 COMPETITION and these two options share the same version, xDrive competition.

How to Configure

We follow a similar approach as when we configured the parent-child relationship between brand and model. This time, the configuration is between car and options, specifying the common relational table they share.

Below are the configuration details with corresponding images:

  • Overview of the Lead fields.

    Lead content type builder overview

  • Configuration of c_car.

    Car field configuration in Lead

    Car field advanced settings

  • Configuration of c_options.

    Options field configuration in Lead

    Options field advanced settings

Lead - Content Manager View

Lead Content Manager overview


db_name: param_name - one per row OR DYNAMIC FILTER PARAMS

Let’s take a closer look at the Car collection and its relational field model, which includes the following fields and values:

Models

namebrand_codemodel_code
A1AUDAUD_A1
A3AUDAUD_A3
X5BMWBMW_X5
X6BMWBMW_X6

In the advanced settings of c_model, you can define db_name: param_name - one per row like this:

  • model_code: different_model_code_name

This configuration enables passing a dynamic filters object to the child collection’s service, formatted as:

filters: { different_model_code_name: { '$eq': [selected_model_code_value] } }

When the model X6 is selected, and we click on the versions select, the following dynamic filter will be populated and sent to the version service:

filters: { different_model_code_name: { '$eq': 'BMW_X6' } }

Lead Content Manager overview


static_value: param_name - one per row OR STATIC FILTER PARAMS

In the advanced settings of c_model, if we define static_value: param_name - one per row, for example:

  • static_value: generic_param_name

This configuration allows you to set static filter parameters that are sent directly to the child collection’s service. When we click on the versions select, the following static filter is populated and sent to the version service:

filters: { generic_param_name: { '$eq': 'static_value' } }

This is useful when you need to apply a fixed value to your query, independent of dynamic user selection.

Lead Content Manager overview


🔧 Configuration - Setting Up a Dynamic Relation Root

Dynamic Relation Root Custom Field

Where you have the ability to configure only some BASIC SETTINGS

BASIC SETTINGS

  • Name
    (This is the only default Strapi basic settings field)

  • Relations: one per row

Dynamic Relation Root Content Type Builder Basic Settings

The Dynamic Relation Root custom field is a conditional custom field that allows defining a set of relational fields that can dynamically change based on a simple select input.

To understand it better, let's look at this example where we build the Course Page collection with the following relevant fields:

  • free_course (Relation with Free_course)
  • paid_course (Relation with Paid_course)

Our goal is to hide both fields in the Content Manager and provide the ability to choose from a dropdown which field to display/use.

Step-by-Step Configuration

The configuration is quite simple this time. You need to define in an enumeration field which relations can be selected from a dropdown.

Dynamic Relation Root Content Type Builder Configuration

As shown in the image, we have named the custom field c_course_type.

Now, we need to add the custom field we’ve discussed before, Parent-Child Relation, and in the basic settings, for the relation name, we enter c_course_type.

Dynamic Relation Root Content Type Builder Configuration

In the advanced settings, specify that the parent is always c_course_type.

Parent-Child Relation with Dynamic Relation Root - Content Type Builder Configuration

That’s it! The configuration is now complete. In the Content Manager, you will have a dropdown that dynamically changes the Parent-Child Relation custom field we named c_course.

From this point forward, you can proceed with the same logic used for the Parent-Child Relation field.

In this example, the filtering logic is based on a shared course relational table between the selected course type (either free_course or paid_course) and the course_options that must share the same relational table as the selected course.

Even though I didn’t explicitly mention it earlier, all the collections free_course, paid_course, and course_options have a relation to the Course collection.

Dynamic Relation Root Content Type Builder Configuration

Below is the schema with some values that these collections have in the database:

Collections Schema

Free_course

namecourse*other_fields
Building Website with PHPBuilding Website with PHP...
Mastering Node.jsMastering Node.js...
PHP and MySQLPHP and MySQL...

Paid_course

namecourse*other_fields
Advanced Python Data StructuresAdvanced Python Data Structures...
PHP Automation ScriptsPHP Automation Scripts...
Python for AutomationPython for Automation...
  • course* indicates that this is a relational field within the schema (Relation with Course).
  • Note that the names within the records match the associated course names. This is just a coincidence.

Course Option

namecourse*other_fields
Opt - 1 Advanced Python Data StructuresAdvanced Python Data Structures...
Opt - 2 Advanced Python Data StructuresAdvanced Python Data Structures...
Opt - 3 Advanced Python Data StructuresAdvanced Python Data Structures...
.........
Opt - 1 Building Website with PHPBuilding Website with PHP...
Opt - 2 Building Website with PHPBuilding Website with PHP...
Opt - 3 Building Website with PHPBuilding Website with PHP...
.........

Here’s the video of how this looks in the Content Manager:

Course Page - Content Manager Video

🤝 Contributing

Feel free to fork and make a pull request of this plugin. All the input is welcome!

⭐️ Show your support

Give a star if this project helped you.

🔗 Links

GitHub Repository with Examples

You can clone the repository and explore all the examples described in this guide, as well as additional configurations and use cases.

🌎 Community support

  • You can contact me on the Strapi Discord channel.

📝 License

Install now

npm install strapi-plugin-parent-child-relationships

STATS

4 GitHub stars45 weekly downloads

Last updated

30 days ago

Strapi Version

>=4.4.0 <5.0.0

Author

github profile image for Dmytro Tkach
Dmytro Tkach

Useful links

Create your own plugin

Check out the available plugin resources that will help you to develop your plugin or provider and get it listed on the marketplace.