I am using a combination of MODX Cloud + Git Package Management (GPM) and Cursor to have AI build me total MODX elements and features. (guide)
It really works great, I can tell it to setup a FAQ page with MIGX and a optional header image or basically anything I need.
I have static files for my chunks, templates, snippets and plugins so AI can edit and read them:
GPM creates a gpm.yaml file that looks like this:
name: aiDevModx
version: 0.0.1
lowCaseName: aidevmodx
namespace: aiDevModx
description: "This is a AI DEV MODX package for MODX 3"
author: mpietersen
build:
license: core/components/aidevmodx/docs/license.txt
changelog: core/components/aidevmodx/docs/changelog.txt
readme: core/components/aidevmodx/docs/readme.txt
requires:
Ace: ">=1.9.3"
Babel: ">=3.5.2"
Call to Action TV: ">=3.0.2"
ClientConfig: ">=2.5.0"
Collections: ">=4.1.1"
ColorPicker: ">=2.0.5"
FormIt: ">=5.1.1"
Image+: ">=2.9.4"
MIGX: ">=3.0.2"
pdoTools: ">=3.0.2"
pThumb: ">=2.3.3"
Resizer: ">=1.0.2"
SEO Suite: ">=3.1.9"
SimpleSearch: ">=3.1.0"
TinyMCE Rich Text Editor: ">=3.1.5"
menus:
- text: aidevmodx.menu
action: manage
categories:
- name: general
rank: 1
- name: blog
rank: 2
- name: faq
rank: 3
- name: contact
rank: 4
- name: request
rank: 5
- name: navigation
- name: social
- name: search
- name: Page options
- name: Breadcrumb
- name: Sidebar
- name: Content blocks
- name: homepage
children:
- name: Hero section
rank: 1
- name: Feature section
rank: 2
- name: Bento section
rank: 3
- name: Blog section
rank: 4
- name: CTA section
rank: 5
templates:
- name: homepage
description: "Homepage template."
- name: basic-page
description: "General page template."
- name: blog-overview-page
description: "Blog listing page template."
- name: blog-detail-page
description: "Blog article detail page template."
properties:
- name: contentblocks.disabled
value: "0"
type: textfield
- name: faq-page
description: "FAQ page template with accordion functionality."
- name: contact-page
description: "Contact page template."
- name: request-page
description: "Request page template."
- name: search-results-page
description: "Search results page template."
- name: overview-page
description: "Overview page template."
- name: content-block-page
description: "Content block page template."
properties:
- name: contentblocks.disabled
value: "0"
type: textfield
- name: demo-page
description: "Demo page template."
snippets:
- name: fileWithVersionTimeStamp
chunks:
- name: scripts
description: "Scripts on all pages"
category: general
- name: header
description: ""
category: general
- name: header
description: ""
category: general
- name: head
description: ""
category: general
- name: main_nav_parent_row
description: "Main navigation parent row"
category: navigation
- name: footer
description: ""
category: general
- name: home_image_tpl
description: "Home image"
category: Hero section
- name: blog_row_tpl
description: "Blog post card for listing pages"
category: blog
- name: faq_accordion_item
description: "Individual FAQ accordion item"
category: faq
- name: faq_accordion_wrapper
description: "FAQ accordion container wrapper"
category: faq
- name: product_dropdown
description: "Product dropdown menu for header navigation"
category: general
- name: mobile_menu
description: "Mobile navigation menu with slide-out panel"
category: general
- name: main_menu
description: "Main navigation menu"
category: general
- name: contact_form
description: "Outer code for a contact form"
category: contact
- name: request_form_inner
description: "Request form inner"
category: request
- name: blog_image_main_tpl
description: "Blog image main"
category: blog
- name: blog_image_overview_tpl
description: "Blog image overview"
category: blog
- name: blog_image_latest_tpl
description: "Blog image latest"
category: blog
- name: blog_latest_row_tpl
description: "Blog latest row"
category: blog
- name: social_media_icons
description: "Social media icons"
category: social
- name: search_popup
description: "Search popup"
category: search
- name: search_toggle
description: "Search toggle"
category: search
- name: search_tpl
description: "Search form template"
category: search
- name: search_input_above_tpl
description: "Search form template above the results"
category: search
- name: search_result_tpl
description: "Search result template"
category: search
- name: search_result_container
description: "Search result container"
category: search
- name: search_result_page_tpl
description: "Search result page template"
category: search
- name: search_result_current_page_tpl
description: "Search result current page template"
category: search
- name: search_no_results_tpl
description: "Search no results template"
category: search
- name: home_cta_link_chunk
description: "Home CTA link chunk"
category: CTA section
- name: home_cta_link_2_chunk
description: "Home CTA link 2 chunk"
category: CTA section
- name: bento_section_1_cta_link_chunk
description: "Bento section 1 CTA link chunk"
category: Feature section
- name: cta_box_link_chunk
description: "CTA box link chunk"
- name: cta_banner_button_chunk
description: "CTA banner button chunk"
category: CTA section
- name: cta_banner_button_2_chunk
description: "CTA banner secondary button chunk"
category: CTA section
- name: breadcrumb_chunk
description: "Breadcrumb chunk"
category: Breadcrumb
- name: sidebar_navigation
description: "Sidebar navigation"
category: Sidebar
- name: cta_section
description: "CTA section"
category: CTA section
- name: contact_form_inner
description: "Contact form inner"
category: contact
- name: contact_email_tpl
description: "Contact email template"
category: contact
- name: contact_email_reply_tpl
description: "Contact email reply template"
category: contact
- name: request_form_inner
description: "Request form inner"
category: request
- name: request_email_tpl
description: "Request email template"
category: request
- name: request_email_reply_tpl
description: "Request email reply template"
category: request
- name: social_media_icons_dark
description: "Social media icons on dark background"
category: social
- name: schema_org
description: "Schema.org markup"
category: social
- name: bento_section_1_image_tpl
description: "Bento section 1 image template"
category: Bento section
- name: bento_section_2_image_tpl
description: "Bento section 2 image template"
category: Bento section
- name: bento_section_3_image_tpl
description: "Bento section 3 image template"
category: Bento section
- name: bento_section_4_image_tpl
description: "Bento section 4 image template"
category: Bento section
- name: bento_section_5_image_tpl
description: "Bento section 5 image template"
category: Bento section
tvs:
- name: blog_image
file: blog_image.tpl
caption: "Blog Image"
type: imageplus
description: "Main image for blog posts"
category: blog
inputOptions:
{
"targetWidth": "1200",
"targetRatio": "1.77777777777",
"allowAltTag": "false",
}
templates:
- "blog-detail-page"
- "blog-overview-page"
- name: home_image
file: home_image.tpl
caption: "Home Image"
type: imageplus
description: "Main image for homepage"
category: Hero section
inputOptions: { "targetRatio": "1.77777777777", "allowAltTag": "false" }
templates:
- "homepage"
- name: cta_link
file: cta_link.tpl
caption: "CTA Link"
type: textfield
description: "Call to action link URL"
category: blog
templates:
- "blog-detail-page"
- name: cta_text
file: cta_text.tpl
caption: "CTA Text"
type: textfield
description: "Call to action button text"
defaultValue: "Read More"
category: blog
templates:
- "blog-detail-page"
- name: faq_items
file: faq_items.tpl
caption: "FAQ Items"
type: migx
description: "FAQ questions and answers using MIGX"
category: faq
inputOptions:
formtabs: '{"0":{"caption":"FAQ Item","fields":{"question":{"field":"question","caption":"Question","inputTV":"","inputTVtype":"textfield","configs":"","validation":"","props":""},"answer":{"field":"answer","caption":"Answer","inputTV":"","inputTVtype":"richtext","configs":"","validation":"","props":""}}}}'
columns: '{"0":{"header":"Question","dataIndex":"question","width":"60%"},"1":{"header":"Answer Preview","dataIndex":"answer","width":"40%","renderer":"this.stripTags"}}'
btntext: "Add FAQ Item"
winbuttons: '{"0":{"text":"Save","handler":"this.submit"},"1":{"text":"Cancel","handler":"this.close"}}'
winwidth: 800
winheight: 600
maxitems: 50
templates:
- "faq-page"
- name: home_cta_link
file: home_cta_link.tpl
caption: "CTA Link"
type: calltoactiontv
description: "Leave link text empty to not display a button."
category: Hero section
sortOrder: "3"
inputOptions:
values: "@SELECT CONCAT(`pagetitle`, ' (', `id`, ')') AS `name`,`id` FROM `[[+PREFIX]]site_content` WHERE `published` = 1 AND `deleted` = 0 AND `context_key` = '[[+context_key]]'"
types: "resource||external||tel||mailto"
templates:
- "homepage"
- name: blog_section_title
file: blog_section_title.tpl
caption: "Blog section Title"
type: textfield
defaultValue: "Dolor sit amet"
category: Blog section
sortOrder: "1"
templates:
- "homepage"
- name: blog_section_description
file: blog_section_description.tpl
caption: "Blog section Description"
type: textarea
defaultValue: "Possimus magnam voluptatum cupiditate veritatis in accusamus quisquam."
category: Blog section
sortOrder: "2"
templates:
- "homepage"
- name: bento_section_title
caption: "Bento section Title"
type: textfield
defaultValue: "Voor particulier & zakelijk!"
category: Bento section
sortOrder: "1"
templates:
- "homepage"
- name: bento_section_sub_title
caption: "Bento section Subtitle"
type: textfield
defaultValue: "Slimme energieoplossingen van Sunconnect"
category: Bento section
sortOrder: "2"
templates:
- "homepage"
- name: bento_section_1_image
file: bento_section_1_image.tpl
caption: "Bento 1 Image"
type: imageplus
category: Bento section
sortOrder: "41"
inputOptions: { "targetRatio": "1.77777777777", "allowAltTag": "false" }
templates:
- "homepage"
- name: bento_section_1_title
caption: "Bento 1 Title"
type: textfield
defaultValue: ""
category: Bento section
sortOrder: "41"
templates:
- "homepage"
- name: bento_section_1_sub_title
caption: "Bento 1 Subtitle"
type: textfield
defaultValue: ""
category: Bento section
sortOrder: "42"
templates:
- "homepage"
- name: bento_section_1_content
caption: "Bento 1 Content"
type: textarea
defaultValue: ""
category: Bento section
sortOrder: "43"
templates:
- "homepage"
- name: bento_section_1_cta_link
file: bento_section_1_cta_link.tpl
caption: "Bento 1 CTA Link"
type: calltoactiontv
description: "Leave link text empty to not display a button."
category: Bento section
sortOrder: "44"
inputOptions:
values: "@SELECT CONCAT(`pagetitle`, ' (', `id`, ')') AS `name`,`id` FROM `[[+PREFIX]]site_content` WHERE `published` = 1 AND `deleted` = 0 AND `context_key` = '[[+context_key]]'"
types: "resource||external||tel||mailto"
templates:
- "homepage"
- name: bento_section_2_image
file: bento_section_2_image.tpl
caption: "Bento 2 Image"
type: imageplus
category: Bento section
sortOrder: "45"
inputOptions: { "targetRatio": "1.77777777777", "allowAltTag": "false" }
templates:
- "homepage"
- name: bento_section_2_title
caption: "Bento 2 Title"
type: textfield
defaultValue: ""
category: Bento section
sortOrder: "45"
templates:
- "homepage"
- name: bento_section_2_sub_title
caption: "Bento 2 Subtitle"
type: textfield
defaultValue: ""
category: Bento section
sortOrder: "46"
templates:
- "homepage"
- name: bento_section_2_content
caption: "Bento 2 Content"
type: textarea
defaultValue: ""
category: Bento section
sortOrder: "47"
templates:
- "homepage"
- name: bento_section_2_cta_link
file: bento_section_2_cta_link.tpl
caption: "Bento 2 CTA Link"
type: calltoactiontv
description: "Leave link text empty to not display a button."
category: Bento section
sortOrder: "48"
inputOptions:
values: "@SELECT CONCAT(`pagetitle`, ' (', `id`, ')') AS `name`,`id` FROM `[[+PREFIX]]site_content` WHERE `published` = 1 AND `deleted` = 0 AND `context_key` = '[[+context_key]]'"
types: "resource||external||tel||mailto"
templates:
- "homepage"
- name: bento_section_3_image
file: bento_section_3_image.tpl
caption: "Bento 3 Image"
type: imageplus
category: Bento section
sortOrder: "49"
inputOptions: { "targetRatio": "1.77777777777", "allowAltTag": "false" }
templates:
- "homepage"
- name: bento_section_3_title
caption: "Bento 3 Title"
type: textfield
defaultValue: ""
category: Bento section
sortOrder: "49"
templates:
- "homepage"
- name: bento_section_3_sub_title
caption: "Bento 3 Subtitle"
type: textfield
defaultValue: ""
category: Bento section
sortOrder: "50"
templates:
- "homepage"
- name: bento_section_3_content
caption: "Bento 3 Content"
type: textarea
defaultValue: ""
category: Bento section
sortOrder: "51"
templates:
- "homepage"
- name: bento_section_3_cta_link
file: bento_section_3_cta_link.tpl
caption: "Bento 3 CTA Link"
type: calltoactiontv
description: "Leave link text empty to not display a button."
category: Bento section
sortOrder: "52"
inputOptions:
values: "@SELECT CONCAT(`pagetitle`, ' (', `id`, ')') AS `name`,`id` FROM `[[+PREFIX]]site_content` WHERE `published` = 1 AND `deleted` = 0 AND `context_key` = '[[+context_key]]'"
types: "resource||external||tel||mailto"
templates:
- "homepage"
- name: bento_section_4_image
file: bento_section_4_image.tpl
caption: "Bento 4 Image"
type: imageplus
category: Bento section
sortOrder: "53"
inputOptions: { "targetRatio": "1.77777777777", "allowAltTag": "false" }
templates:
- "homepage"
- name: bento_section_4_title
caption: "Bento 4 Title"
type: textfield
defaultValue: ""
category: Bento section
sortOrder: "53"
templates:
- "homepage"
- name: bento_section_4_sub_title
caption: "Bento 4 Subtitle"
type: textfield
defaultValue: ""
category: Bento section
sortOrder: "54"
templates:
- "homepage"
- name: bento_section_4_content
caption: "Bento 4 Content"
type: textarea
defaultValue: ""
category: Bento section
sortOrder: "55"
templates:
- "homepage"
- name: bento_section_4_cta_link
file: bento_section_4_cta_link.tpl
caption: "Bento 4 CTA Link"
type: calltoactiontv
description: "Leave link text empty to not display a button."
category: Bento section
sortOrder: "56"
inputOptions:
values: "@SELECT CONCAT(`pagetitle`, ' (', `id`, ')') AS `name`,`id` FROM `[[+PREFIX]]site_content` WHERE `published` = 1 AND `deleted` = 0 AND `context_key` = '[[+context_key]]'"
types: "resource||external||tel||mailto"
templates:
- "homepage"
- name: bento_section_5_image
file: bento_section_5_image.tpl
caption: "Bento 5 Image"
type: imageplus
category: Bento section
sortOrder: "57"
inputOptions: { "targetRatio": "1.77777777777", "allowAltTag": "false" }
templates:
- "homepage"
- name: bento_section_5_title
caption: "Bento 5 Title"
type: textfield
defaultValue: ""
category: Bento section
sortOrder: "57"
templates:
- "homepage"
- name: bento_section_5_sub_title
caption: "Bento 5 Subtitle"
type: textfield
defaultValue: ""
category: Bento section
sortOrder: "58"
templates:
- "homepage"
- name: bento_section_5_content
caption: "Bento 5 Content"
type: textarea
defaultValue: ""
category: Bento section
sortOrder: "59"
templates:
- "homepage"
- name: bento_section_5_cta_link
file: bento_section_5_cta_link.tpl
caption: "Bento 5 CTA Link"
type: calltoactiontv
description: "Leave link text empty to not display a button."
category: Bento section
sortOrder: "60"
inputOptions:
values: "@SELECT CONCAT(`pagetitle`, ' (', `id`, ')') AS `name`,`id` FROM `[[+PREFIX]]site_content` WHERE `published` = 1 AND `deleted` = 0 AND `context_key` = '[[+context_key]]'"
types: "resource||external||tel||mailto"
templates:
- "homepage"
- name: bento_section_1_title
caption: "Bento 1 Title"
type: textfield
defaultValue: ""
category: Bento section
sortOrder: "41"
templates:
- "homepage"
- name: bento_section_1_sub_title
caption: "Bento 1 Subtitle"
type: textfield
defaultValue: ""
category: Bento section
sortOrder: "42"
templates:
- "homepage"
- name: bento_section_1_content
caption: "Bento 1 Content"
type: textarea
defaultValue: ""
category: Bento section
sortOrder: "43"
templates:
- "homepage"
- name: bento_section_1_cta_link
file: bento_section_1_cta_link.tpl
caption: "Bento 1 CTA Link"
type: calltoactiontv
description: "Leave link text empty to not display a button."
category: Bento section
sortOrder: "44"
inputOptions:
values: "@SELECT CONCAT(`pagetitle`, ' (', `id`, ')') AS `name`,`id` FROM `[[+PREFIX]]site_content` WHERE `published` = 1 AND `deleted` = 0 AND `context_key` = '[[+context_key]]'"
types: "resource||external||tel||mailto"
templates:
- "homepage"
- name: cta_banner_show
file: cta_banner_show.tpl
caption: "Display CTA Banner"
type: option
defaultValue: "no"
inputOptionValues: "yes||no"
category: CTA section
sortOrder: "0"
templates:
- "homepage"
- "basic-page"
- "overview-page"
- "content-block-page"
- name: cta_banner_title
file: cta_banner_title.tpl
caption: "CTA Banner Title"
type: textfield
defaultValue: "Vraag geheel vrijblijvend een offerte aan!"
category: CTA section
sortOrder: "1"
templates:
- "homepage"
- "basic-page"
- "overview-page"
- "content-block-page"
- name: cta_banner_description
file: cta_banner_description.tpl
caption: "CTA Banner Description"
type: textarea
defaultValue: "Heeft u interesse in duurzame energiesystemen? Dan bent u bij ons aan aan het juiste adres!"
category: CTA section
sortOrder: "2"
templates:
- "homepage"
- "basic-page"
- "overview-page"
- "content-block-page"
- name: cta_banner_button_1
file: cta_banner_button_1.tpl
caption: "CTA Banner Button 1"
type: calltoactiontv
description: "Leave link text empty to not display a button."
category: CTA section
sortOrder: "3"
inputOptions:
values: "@SELECT CONCAT(`pagetitle`, ' (', `id`, ')') AS `name`,`id` FROM `[[+PREFIX]]site_content` WHERE `published` = 1 AND `deleted` = 0 AND `context_key` = '[[+context_key]]'"
types: "resource||external||tel||mailto"
templates:
- "homepage"
- "basic-page"
- "overview-page"
- "content-block-page"
- name: cta_banner_button_2
file: cta_banner_button_2.tpl
caption: "CTA Banner Button 2"
type: calltoactiontv
description: "Leave link text empty to not display a button."
category: CTA section
sortOrder: "4"
inputOptions:
values: "@SELECT CONCAT(`pagetitle`, ' (', `id`, ')') AS `name`,`id` FROM `[[+PREFIX]]site_content` WHERE `published` = 1 AND `deleted` = 0 AND `context_key` = '[[+context_key]]'"
types: "resource||external||tel||mailto"
templates:
- "homepage"
- "basic-page"
- "overview-page"
- "content-block-page"
- name: showbreadcrumb
file: showbreadcrumb.tpl
caption: "Display breadcrumb"
type: option
defaultValue: "yes"
inputOptionValues: "yes||no"
category: Page options
sortOrder: "1"
templates:
- "overview-page"
- "basic-page"
- name: showsidebar
file: showsidebar.tpl
caption: "Display sidebar"
type: option
defaultValue: "no"
inputOptionValues: "yes||no"
category: Page options
sortOrder: "2"
templates:
- "overview-page"
- "basic-page"
systemSettings:
- key: theme_dir.custom_path
value: "{{pkg_assets_path}}/"
- key: theme_dir.custom_url
value: "{{pkg_assets_path}}/"