Strapi plugin to create and manage parent-child relationships between content types using custom fields
current table column filter
)>=14.19.1
>=6.x.x
Supported Strapi versions:
>=4.4.0 <5.0.0
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
After installation you will find two custom fields at the custom fields section of the content-type builder with the following names:
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.
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
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.
In this section we will use the following 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.
Name
(This is the only default Strapi basic settings field)
Relation name
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
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:
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
collection) - e.g., Audi, BMWModel
collection) - e.g., A1, A3, X5, X6When 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.
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.
name | code |
---|---|
Audi | AUD |
BMW | BMW |
name | brand_code | model_code |
---|---|---|
A1 | AUD | AUD_A1 |
A3 | AUD | AUD_A3 |
X5 | BMW | BMW_X5 |
X6 | BMW | BMW_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"
.
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 collectionbrand_code
in the Model collectionWhile 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"
.
Begin by creating the Car
collection type in Strapi. Ensure that it includes the necessary relational fields (brand
and model
) that will require filtering.
Next, add a Parent-Child Relation custom field for each of the relational fields involved in the filtering operation.
brand
Note: The Name chosen for this field is
c_brand
. This is just my convention to indicate thatc_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.
model
.
Here is a visual overview of the fields configured for the Car
collection type:
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
.
Model Field Configuration: For the model field (c_model
), specify that its parent is c_brand
.
c_brand
as the parent field. This ensures that the filtering logic will be based on the brand selected in the c_brand
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.
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.
To resolve this and display only the custom fields, use the Configure The View feature to hide the default fields.
Now, you can start creating entries with the correctly filtered brand and model relationships.
Now that we’ve learned how to create parent-child relationships between brands and models, we can extend this concept further by introducing versions.
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.
name | code |
---|---|
Audi | AUD |
BMW | BMW |
name | brand_code | model_code |
---|---|---|
A1 | AUD | AUD_A1 |
A3 | AUD | AUD_A3 |
X5 | BMW | BMW_X5 |
X6 | BMW | BMW_X6 |
name | version_code |
---|---|
Sport line edition | AUD_A1 |
Business edition | AUD_A1 |
S line | AUD_A3 |
xDrive sport | BMW_X5 |
xDrive city | BMW_X5 |
xDrive competition | BMW_X6 |
xDrive sport | BMW_X6 |
xDrive 4X4 | BMW_X6 |
model_code
that can be used as a unique identifier for grouping associated versions.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"
.
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.
Next, we will configure the custom field for version and specify that its parent is the custom field c_model.
Finally, we need to configure the c_model field, defining the fields involved in filtering the versions based on the selected model.
In the Content Manager, you will now see three default relational fields provided by Strapi:
And three custom fields you have created:
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.
In this section, we'll explain some advanced options available in the Parent-Child Relationship settings, such as:
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:
name | version_code | segment |
---|---|---|
Sport line edition | AUD_A1 | sport |
Business edition | AUD_A1 | city |
S line | AUD_A3 | sport |
xDrive sport | BMW_X5 | sport |
xDrive city | BMW_X5 | city |
xDrive competition | BMW_X6 | sport |
xDrive sport | BMW_X6 | sport |
xDrive 4X4 | BMW_X6 | suv |
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:
With the filter applied, we will only see:
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
collection)Option
collection)Fields marked with * are relational fields.
name | brand* | model* | version* |
---|---|---|---|
BMW X5 SPORT | BMW | X5 | xDrive sport |
BMW X6 COMPETITION | BMW | X6 | xDrive competition |
Cars
have a relationship with brand, model, and version.
name | version* |
---|---|
co-pilot pack | S line |
color pure white | xDrive competition |
full lead | xDrive competition |
Options
have a relationship with version*.
As you can see, both Cars
and Options
share a common relational field, version*.
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:
Both the BMW X6 COMPETITION and these two options share the same version, xDrive competition.
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.
Configuration of c_car
.
Configuration of c_options
.
db_name: param_name - one per row
OR DYNAMIC FILTER PARAMSLet’s take a closer look at the Car
collection and its relational field model
, which includes the following fields and values:
name | brand_code | model_code |
---|---|---|
A1 | AUD | AUD_A1 |
A3 | AUD | AUD_A3 |
X5 | BMW | BMW_X5 |
X6 | BMW | BMW_X6 |
In the advanced settings of c_model
, you can define db_name: param_name - one per row
like this:
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' } }
static_value: param_name - one per row
OR STATIC FILTER PARAMSIn the advanced settings of c_model
, if we define static_value: param_name - one per row
, for example:
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.
Where you have the ability to configure only some BASIC SETTINGS
Name
(This is the only default Strapi basic settings field)
Relations: one per row
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
)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.
The configuration is quite simple this time. You need to define in an enumeration field which relations can be selected from a dropdown.
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
.
In the advanced settings, specify that the parent
is always c_course_type
.
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.
Below is the schema with some values that these collections have in the database:
name | course* | other_fields |
---|---|---|
Building Website with PHP | Building Website with PHP | ... |
Mastering Node.js | Mastering Node.js | ... |
PHP and MySQL | PHP and MySQL | ... |
name | course* | other_fields |
---|---|---|
Advanced Python Data Structures | Advanced Python Data Structures | ... |
PHP Automation Scripts | PHP Automation Scripts | ... |
Python for Automation | Python for Automation | ... |
Course
).name | course* | other_fields |
---|---|---|
Opt - 1 Advanced Python Data Structures | Advanced Python Data Structures | ... |
Opt - 2 Advanced Python Data Structures | Advanced Python Data Structures | ... |
Opt - 3 Advanced Python Data Structures | Advanced Python Data Structures | ... |
... | ... | ... |
Opt - 1 Building Website with PHP | Building Website with PHP | ... |
Opt - 2 Building Website with PHP | Building Website with PHP | ... |
Opt - 3 Building Website with PHP | Building Website with PHP | ... |
... | ... | ... |
Here’s the video of how this looks in the Content Manager:
Feel free to fork and make a pull request of this plugin. All the input is welcome!
Give a star if this project helped you.
You can clone the repository and explore all the examples described in this guide, as well as additional configurations and use cases.
npm install strapi-plugin-parent-child-relationships
Check out the available plugin resources that will help you to develop your plugin or provider and get it listed on the marketplace.