Is there a problem that needs an urgent fix?Urgent fix?Get emergency help →
Blog

Practical Magento 2 guides on upgrades, security, speed and migration, written by the MageBooster team.

Magento 2.4.9 categories and subcategories: step by step, with a REST API script

Create a parent category and a subcategory with products in Magento 2.4.9: every admin field from MageBooster lesson 3, a REST API script to download, and troubleshooting.
Lesson 3MageBooster Lessons · Magento 2.4.9

Creating categories and subcategories in Magento

A parent category and a subcategory with products, step by step in the admin: every field from the video, a REST API script that builds the same tree, and the fixes for when a category doesn’t show up.

Updated October 2026Video about 3 minLevel Store owners and developers

Downloads

The script uses the Luma sample data SKUs; change SKUS, the names and the URL keys to your own.

The category tree

Default Category root · ID 2 · not shown itself
├─ Women menu item
├─ Men menu item
└─ Travel Gear parent · menu item · anchor
   └─ Backpacks subcategory · drop-down · 4 products

Every store view has one root category (Stores › All Stores shows which). Its children are the main menu, and their children open as drop-downs. A new category always goes under the category that is selected in the tree.

1. Parent category: Travel Gear

Catalog › Categories, select Default Category, then Add Subcategory.

SectionFieldValueWhy
Enable CategoryYesNo hides it everywhere.
Include in MenuYesNo keeps the page, but takes it out of the main menu.
Category NameTravel GearMenu text, page title, breadcrumb.
Display SettingsAnchorYesThe page also lists the products of all subcategories, with layered navigation.
Search Engine OptimizationURL Keytravel-gearThe page is /travel-gear.html.
Search Engine OptimizationMeta TitleTravel Gear: Bags and BackpacksThe title in Google results.

Save. Travel Gear appears in the tree with its ID, for example Travel Gear (ID: 41) (0).

2. Subcategory: Backpacks

With Travel Gear selected, Add Subcategory again and name it Backpacks. Open Products in Category, type Backpack in the Name filter, press Enter and tick the products. Save.

FieldValue
Category NameBackpacks
URL Keybackpacks (filled in from the name), so the page is /travel-gear/backpacks.html
Products in CategoryDriven Backpack, Endeavor Daytrip Backpack, Fusion Backpack, Crown Summit Backpack
The number after the ID in the tree is the product count: Backpacks (ID: 42) (4).

3. On the storefront

Travel Gear is in the main menu, Backpacks opens under it, and the breadcrumb reads Home › Travel Gear › Backpacks. Travel Gear has no products of its own, but as an anchor it lists the four backpacks.

On a live store the cron job updates the indexes and caches within a minute or two. To see the result right away:

cd /var/www/magento
# are the indexers on "Update by Schedule", and is anything waiting?
sudo -u magento bin/magento indexer:status
# the cron job does the work on a live store; to see the result right now:
sudo -u magento bin/magento indexer:reindex catalog_category_product catalog_product_category catalogsearch_fulltext
sudo -u magento bin/magento cache:clean block_html full_page

The URLs Magento created:

# the URLs Magento made for the new categories
mysql magento -e "SELECT request_path, target_path FROM url_rewrite
  WHERE entity_type = 'category' AND request_path LIKE 'travel-gear%';"

The same tree by REST API

Useful when you set up many stores or move a category structure from a test store. The script logs in with the admin user and the code from your authenticator app, creates both categories and adds the products by SKU. Needs curl and jq.

magento-create-categories.shDownload

#!/usr/bin/env bash
# Build the lesson's category tree through the Magento REST API:
#   Default Category (root, ID 2) > Travel Gear (anchor) > Backpacks (+ products by SKU)
# usage: STORE=https://www.example.com ADMIN_USER=youradmin ./magento-create-categories.sh
# Needs curl and jq. Asks for the admin password and the 6-digit code from your authenticator app
# (Magento 2.4 admin accounts use two-factor authentication).
set -euo pipefail
STORE=${STORE:?set STORE, e.g. https://www.example.com}
ADMIN_USER=${ADMIN_USER:?set ADMIN_USER}
ROOT_ID=${ROOT_ID:-2}                                    # Default Category
SKUS=${SKUS:-"24-WB03 24-WB06 24-MB02 24-MB03"}          # Luma sample backpacks
CURL=(curl -sS --fail-with-body ${INSECURE:+-k})         # INSECURE=1 for a self-signed test certificate

read -rsp "Admin password: " PASS; echo
read -rp  "Authenticator code: " OTP
TOKEN=$("${CURL[@]}" -X POST "$STORE/rest/V1/tfa/provider/google/authenticate" -H 'Content-Type: application/json' \
  -d "$(jq -n --arg u "$ADMIN_USER" --arg p "$PASS" --arg o "$OTP" '{username:$u,password:$p,otp:$o}')" | jq -r .)
API() { "${CURL[@]}" -X "$1" "$STORE/rest/all/V1/$2" -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' ${3:+-d "$3"}; }

new_category() {   # name parent url_key [meta_title] -> prints the new ID
  API POST categories "$(jq -n --arg n "$1" --argjson p "$2" --arg k "$3" --arg m "${4:-}" '{category:{
    name:$n, parent_id:$p, is_active:true, include_in_menu:true,
    custom_attributes:([{attribute_code:"url_key",value:$k},{attribute_code:"is_anchor",value:"1"}]
      + (if $m == "" then [] else [{attribute_code:"meta_title",value:$m}] end))}}')" | jq -r .id
}

PARENT=$(new_category "Travel Gear" "$ROOT_ID" travel-gear "Travel Gear: Bags and Backpacks")
echo "Travel Gear: ID $PARENT"
CHILD=$(new_category "Backpacks" "$PARENT" backpacks)
echo "Backpacks:   ID $CHILD"
for sku in $SKUS; do
  API POST "categories/$CHILD/products" "$(jq -n --arg s "$sku" --argjson c "$CHILD" '{productLink:{sku:$s,category_id:$c,position:0}}')" >/dev/null
  echo "  + $sku"
done
echo "Done. Open $STORE/travel-gear/backpacks.html (the menu shows it after the next cron run or a cache flush)."

Run: STORE=https://www.example.com ADMIN_USER=youradmin bash magento-create-categories.sh. Add INSECURE=1 for a self-signed test certificate.

Good to know

  • Move a category by drag and drop in the tree. Magento rewrites the URLs and, with “Create Permanent Redirect for URLs if URL Key Changed” on, adds 301 redirects.
  • Keep the tree shallow. Two or three levels are enough for most stores; deep trees make menus and breadcrumbs long.
  • Hide instead of delete. Enable Category = No, or Include in Menu = No. Deleting a category removes its URL rewrites and position data for good.
  • Anchor for parent categories, off only when a parent should show its own hand-picked products.

Troubleshooting

SymptomCause and fix
New category missing from the menuCached menu block or full page cache. Wait for cron, or run cache:clean block_html full_page. Check Include in Menu.
Category page is emptyIndexers on schedule and cron not running: indexer:status, then fix cron. Products must be enabled, in stock and visible in Catalog.
Parent page shows no productsAnchor is No and the parent has no products of its own: set Anchor = Yes.
404 on the category URLURL key changed or rewrite missing: check the url_rewrite query above; save the category again to regenerate.
Category not in the tree you expectIt was created under the selected category. Drag it to the right parent.
Planning a catalogue structure?We design category trees, filters and URLs for Magento and Mage-OS stores, and migrate them from other platforms.

▶ Watch every MageBooster lesson on YouTube: all lessons in order · subscribe to the channel

Installation guides: Magento 2.4.9 on Ubuntu Mage-OS Hyvä
Spotted a mistake on this page? Tell us and we will fix it right away.

Free Site Audit

Send your store details. We check speed, security and extensions, then reply with three quick wins within 3 working days.

Let's talk

Get a quote

Tell us about your store and we’ll reply within one working day. Prefer to chat? Say hello from WhatsApp

MageBooster Book a UnoPim demo See UnoPim live with products like yours. A new PIM or a move from Akeneo: we reply with a plan, a timeline and a quote.
✓ Official UnoPim partner✓ AI agent set up for your team✓ Connected to Magento
MageBooster Start your Hyvä project From scratch or from your current store. We reply with a project plan, a timeline and a quote.
✓ Design and structure by us✓ Hyvä-optimised server✓ Bonus modules included

MageBooster

Let us get in touch with you

Leave your details and your store address. We look at your store first and contact you within one business day, by phone, WhatsApp or email, whichever you prefer.

Partner with us