{"users":[{"id":115923,"username":"Discourse","name":null,"avatar_template":"/user_avatar/meta.discourse.org/discourse/{size}/148734_2.png","admin":true,"trust_level":4},{"id":100484,"username":"JammyDodger","name":"","avatar_template":"/user_avatar/meta.discourse.org/jammydodger/{size}/254611_2.png","trust_level":3},{"id":118713,"username":"Jerome_Hordies","name":"Jerome Hordies","avatar_template":"/user_avatar/meta.discourse.org/jerome_hordies/{size}/267141_2.png","trust_level":1},{"id":27384,"username":"merefield","name":"Robert","avatar_template":"/user_avatar/meta.discourse.org/merefield/{size}/176214_2.png","trust_level":3},{"id":150659,"username":"Jukebo","name":"Jusi","avatar_template":"/user_avatar/meta.discourse.org/jukebo/{size}/423583_2.png","trust_level":1},{"id":23968,"username":"david","name":"David Taylor","avatar_template":"/user_avatar/meta.discourse.org/david/{size}/157490_2.png","flair_name":"team","flair_url":"https://global.discourse-cdn.com/meta/original/3X/e/b/ebee30bd98aef20357e4a177a5a1e45b877ce088.svg","flair_color":"111","flair_group_id":47,"primary_group_name":"team","admin":true,"trust_level":3},{"id":-1,"username":"system","name":"system","avatar_template":"/user_avatar/meta.discourse.org/system/{size}/443519_2.png","admin":true,"moderator":true,"trust_level":4},{"id":166720,"username":"opcourdis","name":null,"avatar_template":"https://avatars.discourse-cdn.com/v4/letter/o/45deac/{size}.png","trust_level":2},{"id":83775,"username":"fitzy","name":"Michael Fitz-Payne","avatar_template":"/user_avatar/meta.discourse.org/fitzy/{size}/192549_2.png","flair_name":"team","flair_url":"https://global.discourse-cdn.com/meta/original/3X/e/b/ebee30bd98aef20357e4a177a5a1e45b877ce088.svg","flair_color":"111","flair_group_id":47,"primary_group_name":"team","trust_level":4},{"id":82960,"username":"manuel","name":"Manuel Kostka","avatar_template":"/user_avatar/meta.discourse.org/manuel/{size}/468169_2.png","flair_name":"team","flair_url":"https://global.discourse-cdn.com/meta/original/3X/e/b/ebee30bd98aef20357e4a177a5a1e45b877ce088.svg","flair_color":"111","flair_group_id":47,"primary_group_name":"team","admin":true,"trust_level":2},{"id":135392,"username":"NateDhaliwal","name":"Nate Dhaliwal","avatar_template":"/user_avatar/meta.discourse.org/natedhaliwal/{size}/313494_2.png","flair_name":"plugin_authors","flair_url":"plug","flair_bg_color":"dddddd","flair_color":"111111","flair_group_id":48,"trust_level":3},{"id":66204,"username":"fzngagan","name":"Faizaan Gagan","avatar_template":"/user_avatar/meta.discourse.org/fzngagan/{size}/259349_2.png","flair_name":"team","flair_url":"https://global.discourse-cdn.com/meta/original/3X/e/b/ebee30bd98aef20357e4a177a5a1e45b877ce088.svg","flair_color":"111","flair_group_id":47,"primary_group_name":"team","admin":true,"trust_level":3},{"id":13900,"username":"thoka","name":"Thomas Kalka","avatar_template":"/user_avatar/meta.discourse.org/thoka/{size}/115652_2.png","trust_level":2},{"id":15209,"username":"pfaffman","name":"Jay Pfaffman","avatar_template":"/user_avatar/meta.discourse.org/pfaffman/{size}/120154_2.png","flair_name":"support-experts","flair_url":"https://global.discourse-cdn.com/meta/original/3X/e/2/e250ec403580530d19e6a9ed42d0d525a51a9dbe.svg","flair_bg_color":"FFFFFF","flair_group_id":142,"trust_level":4},{"id":16539,"username":"Osama","name":"","avatar_template":"/user_avatar/meta.discourse.org/osama/{size}/98013_2.png","flair_name":"team","flair_url":"https://global.discourse-cdn.com/meta/original/3X/e/b/ebee30bd98aef20357e4a177a5a1e45b877ce088.svg","flair_color":"111","flair_group_id":47,"primary_group_name":"team","admin":true,"trust_level":2},{"id":95552,"username":"Moin","name":"","avatar_template":"/user_avatar/meta.discourse.org/moin/{size}/554653_2.png","trust_level":3},{"id":127446,"username":"gormus","name":"Osman Görmüş","avatar_template":"/user_avatar/meta.discourse.org/gormus/{size}/428592_2.png","flair_name":"theme_authors","flair_url":"paintbrush","flair_bg_color":"ddd","flair_color":"111","flair_group_id":73,"trust_level":2},{"id":13093,"username":"pacharanero","name":"Marcus Baw","avatar_template":"/user_avatar/meta.discourse.org/pacharanero/{size}/500583_2.png","flair_name":"VolunteerMods","flair_url":"https://global.discourse-cdn.com/meta/original/4X/2/7/d/27de051915b8a604d176484cd260d10cfc956d42.svg","flair_group_id":276,"primary_group_name":"VolunteerMods","trust_level":4},{"id":98247,"username":"vinyll","name":"Vincent Agnano","avatar_template":"/user_avatar/meta.discourse.org/vinyll/{size}/222495_2.png","trust_level":2},{"id":406,"username":"RGJ","name":"Richard - Communiteq","avatar_template":"/user_avatar/meta.discourse.org/rgj/{size}/523185_2.png","flair_name":"support-experts","flair_url":"https://global.discourse-cdn.com/meta/original/3X/e/2/e250ec403580530d19e6a9ed42d0d525a51a9dbe.svg","flair_bg_color":"FFFFFF","flair_group_id":142,"trust_level":4},{"id":1,"username":"sam","name":"Sam Saffron","avatar_template":"/user_avatar/meta.discourse.org/sam/{size}/102149_2.png","flair_name":"team","flair_url":"https://global.discourse-cdn.com/meta/original/3X/e/b/ebee30bd98aef20357e4a177a5a1e45b877ce088.svg","flair_color":"111","flair_group_id":47,"primary_group_name":"team","admin":true,"trust_level":3},{"id":36685,"username":"Arkshine","name":"","avatar_template":"/user_avatar/meta.discourse.org/arkshine/{size}/298682_2.png","flair_name":"support-advocates","flair_url":"https://global.discourse-cdn.com/meta/original/3X/e/4/e4038d4d9848de2eabab38e17b8bdb69da154024.svg","flair_bg_color":"FFFFFF","flair_group_id":148,"trust_level":3},{"id":191806,"username":"saros","name":"saros","avatar_template":"https://avatars.discourse-cdn.com/v4/letter/s/77aa72/{size}.png","trust_level":1},{"id":14353,"username":"simon","name":"","avatar_template":"/user_avatar/meta.discourse.org/simon/{size}/339122_2.png","trust_level":2},{"id":114728,"username":"darkpixlz","name":"Pyx ","avatar_template":"/user_avatar/meta.discourse.org/darkpixlz/{size}/549896_2.png","flair_name":"VolunteerMods","flair_url":"https://global.discourse-cdn.com/meta/original/4X/2/7/d/27de051915b8a604d176484cd260d10cfc956d42.svg","flair_group_id":276,"primary_group_name":"VolunteerMods","trust_level":4},{"id":125230,"username":"Pieces","name":"","avatar_template":"https://avatars.discourse-cdn.com/v4/letter/p/958977/{size}.png","trust_level":2},{"id":169973,"username":"yuriy","name":"Yuriy Kurant","avatar_template":"/user_avatar/meta.discourse.org/yuriy/{size}/498097_2.png","trust_level":2},{"id":15442,"username":"jericson","name":"Jon Ericson","avatar_template":"/user_avatar/meta.discourse.org/jericson/{size}/116215_2.png","flair_name":"support-explorers","flair_url":"https://global.discourse-cdn.com/meta/original/4X/d/1/b/d1ba0acf09b9d01f87f9e05bbee1dc5b0e316d5f.png","flair_bg_color":"dddddd","flair_color":"111111","flair_group_id":118,"trust_level":2},{"id":23163,"username":"j.jaffeux","name":"Joffrey Jaffeux","avatar_template":"/user_avatar/meta.discourse.org/j.jaffeux/{size}/60297_2.png","flair_name":"team","flair_url":"https://global.discourse-cdn.com/meta/original/3X/e/b/ebee30bd98aef20357e4a177a5a1e45b877ce088.svg","flair_color":"111","flair_group_id":47,"primary_group_name":"team","admin":true,"trust_level":2},{"id":2770,"username":"awesomerobot","name":"Kris","avatar_template":"/user_avatar/meta.discourse.org/awesomerobot/{size}/142900_2.png","flair_name":"team","flair_url":"https://global.discourse-cdn.com/meta/original/3X/e/b/ebee30bd98aef20357e4a177a5a1e45b877ce088.svg","flair_color":"111","flair_group_id":47,"primary_group_name":"team","admin":true,"trust_level":3},{"id":21029,"username":"pmusaraj","name":"Penar Musaraj","avatar_template":"/user_avatar/meta.discourse.org/pmusaraj/{size}/119489_2.png","flair_name":"team","flair_url":"https://global.discourse-cdn.com/meta/original/3X/e/b/ebee30bd98aef20357e4a177a5a1e45b877ce088.svg","flair_color":"111","flair_group_id":47,"primary_group_name":"team","admin":true,"trust_level":3},{"id":125035,"username":"misham","name":"Mykhailo","avatar_template":"/user_avatar/meta.discourse.org/misham/{size}/282796_2.png","trust_level":1},{"id":13378,"username":"angus","name":"Angus McLeod","avatar_template":"/user_avatar/meta.discourse.org/angus/{size}/341715_2.png","flair_name":"support-experts","flair_url":"https://global.discourse-cdn.com/meta/original/3X/e/2/e250ec403580530d19e6a9ed42d0d525a51a9dbe.svg","flair_bg_color":"FFFFFF","flair_group_id":142,"trust_level":4}],"primary_groups":[{"id":47,"name":"team"},{"id":276,"name":"VolunteerMods"}],"flair_groups":[{"id":47,"name":"team","flair_url":"https://global.discourse-cdn.com/meta/original/3X/e/b/ebee30bd98aef20357e4a177a5a1e45b877ce088.svg","flair_bg_color":"","flair_color":"111"},{"id":48,"name":"plugin_authors","flair_url":"plug","flair_bg_color":"dddddd","flair_color":"111111"},{"id":142,"name":"support-experts","flair_url":"https://global.discourse-cdn.com/meta/original/3X/e/2/e250ec403580530d19e6a9ed42d0d525a51a9dbe.svg","flair_bg_color":"FFFFFF","flair_color":""},{"id":73,"name":"theme_authors","flair_url":"paintbrush","flair_bg_color":"ddd","flair_color":"111"},{"id":276,"name":"VolunteerMods","flair_url":"https://global.discourse-cdn.com/meta/original/4X/2/7/d/27de051915b8a604d176484cd260d10cfc956d42.svg","flair_bg_color":"","flair_color":""},{"id":148,"name":"support-advocates","flair_url":"https://global.discourse-cdn.com/meta/original/3X/e/4/e4038d4d9848de2eabab38e17b8bdb69da154024.svg","flair_bg_color":"FFFFFF","flair_color":""},{"id":118,"name":"support-explorers","flair_url":"https://global.discourse-cdn.com/meta/original/4X/d/1/b/d1ba0acf09b9d01f87f9e05bbee1dc5b0e316d5f.png","flair_bg_color":"dddddd","flair_color":"111111"}],"topic_list":{"can_create_topic":false,"filter":"latest","more_topics_url":"/c/documentation/developer-guides/56?page=1","per_page":30,"top_tags":[{"id":478,"name":"how-to","slug":"how-to"},{"id":820,"name":"theme-guides","slug":"theme-guides"},{"id":819,"name":"code","slug":"code"},{"id":274,"name":"plugin-guides","slug":"plugin-guides"},{"id":484,"name":"tutorial","slug":"tutorial"},{"id":150,"name":"dev-install","slug":"dev-install"},{"id":482,"name":"reference","slug":"reference"},{"id":479,"name":"explanation","slug":"explanation"},{"id":70,"name":"ember","slug":"ember"},{"id":58,"name":"testing","slug":"testing"},{"id":543,"name":"ai","slug":"ai"},{"id":643,"name":"auto-dark","slug":"auto-dark"},{"id":275,"name":"automation","slug":"automation"},{"id":436,"name":"css","slug":"css"},{"id":814,"name":"customization","slug":"customization"},{"id":24,"name":"docker","slug":"docker"},{"id":799,"name":"index","slug":"index"},{"id":52,"name":"markdown","slug":"markdown"},{"id":328,"name":"plugin-api","slug":"plugin-api"},{"id":566,"name":"theme-creator","slug":"theme-creator"},{"id":16,"name":"translation","slug":"translation"},{"id":25,"name":"wiki-posts","slug":"wiki-posts"}],"topics":[{"fancy_title":"Developer Guides Index","fancy_title_localized":false,"locale":"en","id":308036,"title":"Developer Guides Index","slug":"developer-guides-index","posts_count":1,"reply_count":1,"highest_post_number":1,"image_url":null,"created_at":"2024-05-15T06:05:51.350Z","last_posted_at":"2024-05-15T06:05:51.457Z","bumped":true,"bumped_at":"2026-09-19T05:45:40.300Z","archetype":"regular","unseen":false,"pinned":true,"unpinned":null,"excerpt":"Documentation about extending Discourse with plugins, themes, and theme components, working with the core code, and using the Discourse API. \nIntroduction\n\nIntroduction: Introduction to Discourse Development\n\nDevelopment&hellip;","visible":true,"closed":true,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[{"id":799,"name":"index","slug":"index"}],"tags_descriptions":{"index":"Documentation category index topics."},"views":2261,"like_count":14,"has_summary":false,"last_poster_username":"Discourse","category_id":56,"op_like_count":14,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":"latest","description":"Original Poster, Most Recent Poster","user_id":115923,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Recent Poster","user_id":100484,"primary_group_id":null,"flair_group_id":null}]},{"fancy_title":"Add localizable strings to themes and theme components","fancy_title_localized":false,"locale":"en","id":109867,"title":"Add localizable strings to themes and theme components","slug":"add-localizable-strings-to-themes-and-theme-components","posts_count":23,"reply_count":14,"highest_post_number":24,"image_url":"https://global.discourse-cdn.com/meta/optimized/4X/4/7/e/47e010f967d46f02641044230b73e321aa47f7ae_2_1024x576.png","created_at":"2019-02-22T22:21:45.254Z","last_posted_at":"2024-08-09T19:58:55.662Z","bumped":true,"bumped_at":"2026-09-24T02:59:43.642Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"For those looking to add custom languages and translations to a Discourse theme or theme component, they can now include localised strings, which are made available for use in UI components. Translations are stored in th&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":[{"max_width":null,"max_height":null,"width":1378,"height":776,"url":"https://global.discourse-cdn.com/meta/original/4X/4/7/e/47e010f967d46f02641044230b73e321aa47f7ae.png"},{"max_width":1024,"max_height":1024,"width":1024,"height":576,"url":"https://global.discourse-cdn.com/meta/optimized/4X/4/7/e/47e010f967d46f02641044230b73e321aa47f7ae_2_1024x576.png"},{"max_width":800,"max_height":800,"width":800,"height":450,"url":"https://global.discourse-cdn.com/meta/optimized/4X/4/7/e/47e010f967d46f02641044230b73e321aa47f7ae_2_800x450.png"},{"max_width":600,"max_height":600,"width":600,"height":337,"url":"https://global.discourse-cdn.com/meta/optimized/4X/4/7/e/47e010f967d46f02641044230b73e321aa47f7ae_2_600x337.png"},{"max_width":400,"max_height":400,"width":400,"height":225,"url":"https://global.discourse-cdn.com/meta/optimized/4X/4/7/e/47e010f967d46f02641044230b73e321aa47f7ae_2_400x225.png"},{"max_width":300,"max_height":300,"width":300,"height":168,"url":"https://global.discourse-cdn.com/meta/optimized/4X/4/7/e/47e010f967d46f02641044230b73e321aa47f7ae_2_300x168.png"},{"max_width":200,"max_height":200,"width":200,"height":112,"url":"https://global.discourse-cdn.com/meta/optimized/4X/4/7/e/47e010f967d46f02641044230b73e321aa47f7ae_2_200x112.png"}],"tags":[{"id":478,"name":"how-to","slug":"how-to"},{"id":820,"name":"theme-guides","slug":"theme-guides"}],"tags_descriptions":{"how-to":"How to guides contain steps to follow to solve a specific problem"},"views":5820,"like_count":54,"has_summary":false,"last_poster_username":"david","category_id":56,"op_like_count":32,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":null,"description":"Original Poster","user_id":115923,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Frequent Poster","user_id":118713,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Frequent Poster","user_id":27384,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Recent Poster","user_id":150659,"primary_group_id":null,"flair_group_id":null},{"extras":"latest","description":"Most Recent Poster","user_id":23968,"primary_group_id":47,"flair_group_id":47}]},{"fancy_title":"Using service objects in Discourse","fancy_title_localized":false,"locale":null,"id":333641,"title":"Using service objects in Discourse","slug":"using-service-objects-in-discourse","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2024-10-30T15:56:38.400Z","last_posted_at":"2024-10-30T15:56:38.536Z","bumped":true,"bumped_at":"2026-09-23T16:22:12.679Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"Overview\nA service is a small object that encompasses business logic for a given action. \nFrom outside, it should be seen as a sort of black box. You provide it with parameters, it runs (including all the side effects it&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[],"tags_descriptions":{},"views":927,"like_count":17,"has_summary":false,"last_poster_username":"system","category_id":56,"op_like_count":17,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user_id":-1,"primary_group_id":null,"flair_group_id":null}]},{"fancy_title":"Set up Discourse for development on Fedora Linux","fancy_title_localized":false,"locale":"en","id":163348,"title":"Set up Discourse for development on Fedora Linux","slug":"set-up-discourse-for-development-on-fedora-linux","posts_count":14,"reply_count":12,"highest_post_number":26,"image_url":null,"created_at":"2020-09-08T11:00:32.308Z","last_posted_at":"2026-06-19T05:20:22.329Z","bumped":true,"bumped_at":"2026-09-22T21:14:49.351Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"This guide has been tested against a fresh install of Fedora 31 and 33, but may work on older versions that also use dnf as the package management tool. This is not an official guide but may be useful for other developer&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[{"id":478,"name":"how-to","slug":"how-to"},{"id":150,"name":"dev-install","slug":"dev-install"}],"tags_descriptions":{"how-to":"How to guides contain steps to follow to solve a specific problem","dev-install":"Instructions and issues with installing Discourse for development"},"views":4863,"like_count":44,"has_summary":false,"last_poster_username":"NateDhaliwal","category_id":56,"op_like_count":27,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":null,"description":"Original Poster","user_id":115923,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Frequent Poster","user_id":166720,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Frequent Poster","user_id":83775,"primary_group_id":47,"flair_group_id":47},{"extras":null,"description":"Recent Poster","user_id":82960,"primary_group_id":47,"flair_group_id":47},{"extras":"latest","description":"Most Recent Poster","user_id":135392,"primary_group_id":null,"flair_group_id":48}]},{"fancy_title":"Using the AI bot via the Discourse API","fancy_title_localized":false,"locale":null,"id":412826,"title":"Using the AI bot via the Discourse API","slug":"using-the-ai-bot-via-the-discourse-api","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2026-09-19T05:45:35.552Z","last_posted_at":"2026-09-19T05:45:35.638Z","bumped":true,"bumped_at":"2026-09-19T05:45:35.638Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"Overview\nDiscourse AI exposes an admin/API endpoint for streaming an AI Agent reply over a raw chunked HTTP response. \n\nProtocol: Raw chunked HTTP transfer encoding (NOT Server-Sent Events).\nImplementation: Hijacks the&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[],"tags_descriptions":{},"views":51,"like_count":2,"has_summary":false,"last_poster_username":"system","category_id":56,"op_like_count":2,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user_id":-1,"primary_group_id":null,"flair_group_id":null}]},{"fancy_title":"Developer&rsquo;s guide to Markdown extensions","fancy_title_localized":false,"locale":"en","id":66023,"title":"Developer's guide to Markdown extensions","slug":"developers-guide-to-markdown-extensions","posts_count":2,"reply_count":13,"highest_post_number":24,"image_url":null,"created_at":"2017-07-11T21:23:25.941Z","last_posted_at":"2026-06-01T08:45:53.539Z","bumped":true,"bumped_at":"2026-09-11T18:11:04.601Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"Discourse uses a Markdown engine called Markdown-it. \nHere are some dev notes that will help you either fix bugs in core or create your new plugins. \nThe Basics\nDiscourse only contains a few helpers on top of the engine,&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[{"id":482,"name":"reference","slug":"reference"},{"id":52,"name":"markdown","slug":"markdown"},{"id":819,"name":"code","slug":"code"}],"tags_descriptions":{},"views":13739,"like_count":36,"has_summary":false,"last_poster_username":"NateDhaliwal","category_id":56,"op_like_count":36,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":null,"description":"Original Poster","user_id":115923,"primary_group_id":null,"flair_group_id":null},{"extras":"latest","description":"Most Recent Poster","user_id":135392,"primary_group_id":null,"flair_group_id":48}]},{"fancy_title":"Adding a new &lsquo;managed&rsquo; authentication method to Discourse","fancy_title_localized":false,"locale":"en","id":106695,"title":"Adding a new 'managed' authentication method to Discourse","slug":"adding-a-new-managed-authentication-method-to-discourse","posts_count":3,"reply_count":1,"highest_post_number":7,"image_url":null,"created_at":"2019-01-16T13:44:45.295Z","last_posted_at":"2023-11-29T07:48:14.411Z","bumped":true,"bumped_at":"2026-09-11T09:12:27.661Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"Continuing from Future Social Authentication Improvements… \nWe are now in the process of moving all ‘associated account’ information into a single database table. This will help to significantly reduce duplicated logic, &hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[{"id":479,"name":"explanation","slug":"explanation"}],"tags_descriptions":{},"views":3822,"like_count":30,"has_summary":false,"last_poster_username":"thoka","category_id":56,"op_like_count":23,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":null,"description":"Original Poster","user_id":115923,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Recent Poster","user_id":66204,"primary_group_id":47,"flair_group_id":47},{"extras":"latest","description":"Most Recent Poster","user_id":13900,"primary_group_id":null,"flair_group_id":null}]},{"fancy_title":"Theme Developer Tutorial: 7. Wrapping up","fancy_title_localized":false,"locale":null,"id":357802,"title":"Theme Developer Tutorial: 7. Wrapping up","slug":"theme-developer-tutorial-7-wrapping-up","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2025-03-18T15:59:12.182Z","last_posted_at":"2025-03-18T15:59:12.273Z","bumped":true,"bumped_at":"2026-09-10T17:41:14.475Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"This tutorial has been a whistle-stop tour through the process of creating a Discourse theme and experimenting with a few of the most common APIs. Of course, there’s plenty more to learn, so let’s map out some more place&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[],"tags_descriptions":{},"views":385,"like_count":2,"has_summary":false,"last_poster_username":"system","category_id":56,"op_like_count":2,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user_id":-1,"primary_group_id":null,"flair_group_id":null}]},{"fancy_title":"Theme Developer Tutorial: 6. Using the JS API","fancy_title_localized":false,"locale":null,"id":357801,"title":"Theme Developer Tutorial: 6. Using the JS API","slug":"theme-developer-tutorial-6-using-the-js-api","posts_count":4,"reply_count":2,"highest_post_number":4,"image_url":null,"created_at":"2025-03-18T15:59:11.630Z","last_posted_at":"2025-04-14T23:16:42.528Z","bumped":true,"bumped_at":"2026-09-10T17:41:13.433Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"In the last couple of chapters, we’ve explored how to use the JavaScript API to render content into outlets. renderInOutlet is the most commonly-used API, but there are a ton more! In this chapter we’ll try out a few of &hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[],"tags_descriptions":{},"views":1148,"like_count":9,"has_summary":false,"last_poster_username":"pfaffman","category_id":56,"op_like_count":3,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":null,"description":"Original Poster","user_id":-1,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Recent Poster","user_id":23968,"primary_group_id":47,"flair_group_id":47},{"extras":"latest","description":"Most Recent Poster","user_id":15209,"primary_group_id":null,"flair_group_id":142}]},{"fancy_title":"Add settings to your Discourse theme","fancy_title_localized":false,"locale":"en","id":82557,"title":"Add settings to your Discourse theme","slug":"add-settings-to-your-discourse-theme","posts_count":7,"reply_count":52,"highest_post_number":91,"image_url":"https://global.discourse-cdn.com/meta/original/4X/f/1/8/f184f8f16a50a7e3c15efc462e1f07b6dbada223.jpeg","created_at":"2018-03-08T22:28:58.820Z","last_posted_at":"2025-07-08T19:43:17.589Z","bumped":true,"bumped_at":"2026-09-10T17:41:12.366Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"Discourse has the ability for themes to have “settings” that can be added by theme developers to allow site owners to customize themes through UI without having to change any line of code and worry about losing their cha&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":[{"max_width":null,"max_height":null,"width":735,"height":339,"url":"https://global.discourse-cdn.com/meta/original/4X/f/1/8/f184f8f16a50a7e3c15efc462e1f07b6dbada223.jpeg"},{"max_width":600,"max_height":600,"width":600,"height":276,"url":"https://global.discourse-cdn.com/meta/optimized/4X/f/1/8/f184f8f16a50a7e3c15efc462e1f07b6dbada223_2_600x276.jpeg"},{"max_width":400,"max_height":400,"width":400,"height":184,"url":"https://global.discourse-cdn.com/meta/optimized/4X/f/1/8/f184f8f16a50a7e3c15efc462e1f07b6dbada223_2_400x184.jpeg"},{"max_width":300,"max_height":300,"width":300,"height":138,"url":"https://global.discourse-cdn.com/meta/optimized/4X/f/1/8/f184f8f16a50a7e3c15efc462e1f07b6dbada223_2_300x138.jpeg"},{"max_width":200,"max_height":200,"width":200,"height":92,"url":"https://global.discourse-cdn.com/meta/optimized/4X/f/1/8/f184f8f16a50a7e3c15efc462e1f07b6dbada223_2_200x92.jpeg"}],"tags":[{"id":478,"name":"how-to","slug":"how-to"},{"id":820,"name":"theme-guides","slug":"theme-guides"}],"tags_descriptions":{"how-to":"How to guides contain steps to follow to solve a specific problem"},"views":17551,"like_count":69,"has_summary":false,"last_poster_username":"gormus","category_id":56,"op_like_count":54,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":null,"description":"Original Poster","user_id":115923,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Frequent Poster","user_id":16539,"primary_group_id":47,"flair_group_id":47},{"extras":null,"description":"Frequent Poster","user_id":15209,"primary_group_id":null,"flair_group_id":142},{"extras":null,"description":"Recent Poster","user_id":95552,"primary_group_id":null,"flair_group_id":null},{"extras":"latest","description":"Most Recent Poster","user_id":127446,"primary_group_id":null,"flair_group_id":73}]},{"fancy_title":"Theme Developer Quick Reference Guide","fancy_title_localized":false,"locale":"en","id":110448,"title":"Theme Developer Quick Reference Guide","slug":"theme-developer-quick-reference-guide","posts_count":3,"reply_count":2,"highest_post_number":4,"image_url":null,"created_at":"2019-03-01T16:22:45.321Z","last_posted_at":"2021-06-28T17:13:16.090Z","bumped":true,"bumped_at":"2026-09-10T17:41:10.461Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"As themes grow more powerful, there’s more to remember about how they work. We have loads of detailed documentation under #theme-guides, but if you just need something to jog your memory, this guide may help. \nGeneral Re&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[{"id":482,"name":"reference","slug":"reference"},{"id":820,"name":"theme-guides","slug":"theme-guides"}],"tags_descriptions":{},"views":10047,"like_count":58,"has_summary":false,"last_poster_username":"vinyll","category_id":56,"op_like_count":40,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":null,"description":"Original Poster","user_id":115923,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Recent Poster","user_id":13093,"primary_group_id":276,"flair_group_id":276},{"extras":"latest","description":"Most Recent Poster","user_id":98247,"primary_group_id":null,"flair_group_id":null}]},{"fancy_title":"Designing for Responsive Widths (Breakpoints, Viewport &amp; Containers)","fancy_title_localized":false,"locale":null,"id":409279,"title":"Designing for Responsive Widths (Breakpoints, Viewport & Containers)","slug":"designing-for-responsive-widths-breakpoints-viewport-containers","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2026-08-04T15:57:19.956Z","last_posted_at":"2026-08-04T15:57:20.124Z","bumped":true,"bumped_at":"2026-09-10T17:41:09.474Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"This document outlines the APIs used to adapt Discourse’s user interface to different widths — both the browser viewport, and individual containers on the page. \nWe design “mobile first” and then add customizations for l&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[],"tags_descriptions":{},"views":123,"like_count":3,"has_summary":false,"last_poster_username":"system","category_id":56,"op_like_count":3,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user_id":-1,"primary_group_id":null,"flair_group_id":null}]},{"fancy_title":"Designing for Different Devices (Touch &amp; Hover)","fancy_title_localized":false,"locale":null,"id":367810,"title":"Designing for Different Devices (Touch & Hover)","slug":"designing-for-different-devices-touch-hover","posts_count":15,"reply_count":11,"highest_post_number":15,"image_url":null,"created_at":"2025-05-27T18:17:05.719Z","last_posted_at":"2026-01-25T21:34:26.908Z","bumped":true,"bumped_at":"2026-09-10T17:41:08.406Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"This document outlines the APIs used to adapt Discourse’s user interface for different devices. \nTouch &amp; Hover\nSome devices only have touchscreens, some only have a traditional mouse pointer, and some have both. Importan&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[],"tags_descriptions":{},"views":1265,"like_count":26,"has_summary":false,"last_poster_username":"merefield","category_id":56,"op_like_count":13,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":null,"description":"Original Poster","user_id":-1,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Frequent Poster","user_id":23968,"primary_group_id":47,"flair_group_id":47},{"extras":null,"description":"Frequent Poster","user_id":135392,"primary_group_id":null,"flair_group_id":48},{"extras":null,"description":"Recent Poster","user_id":406,"primary_group_id":null,"flair_group_id":142},{"extras":"latest","description":"Most Recent Poster","user_id":27384,"primary_group_id":null,"flair_group_id":null}]},{"fancy_title":"Guidelines for CSS classes using BEM","fancy_title_localized":false,"locale":null,"id":361851,"title":"Guidelines for CSS classes using BEM","slug":"guidelines-for-css-classes-using-bem","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2025-04-15T05:48:23.418Z","last_posted_at":"2025-04-15T05:48:23.483Z","bumped":true,"bumped_at":"2026-09-10T17:41:07.479Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"Background\nWhen writing CSS classes for Discourse components, themes, or plugins, we follow a modified variant of Block Element Modifier (BEM). Following these guidelines will make it much less likely for CSS conflicts t&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[],"tags_descriptions":{},"views":386,"like_count":8,"has_summary":false,"last_poster_username":"system","category_id":56,"op_like_count":8,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user_id":-1,"primary_group_id":null,"flair_group_id":null}]},{"fancy_title":"Customizing the topic list","fancy_title_localized":false,"locale":null,"id":350411,"title":"Customizing the topic list","slug":"customizing-the-topic-list","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2025-02-04T10:40:33.076Z","last_posted_at":"2025-02-04T10:40:33.148Z","bumped":true,"bumped_at":"2026-09-10T17:41:06.489Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"The topic-list is one of the most-used and most-customized user-interfaces in Discourse. There are many different tools available to theme and plugin developers to achieve this customization, each with their own advantag&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[],"tags_descriptions":{},"views":871,"like_count":8,"has_summary":false,"last_poster_username":"system","category_id":56,"op_like_count":8,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user_id":-1,"primary_group_id":null,"flair_group_id":null}]},{"fancy_title":"Using the DModal API to render Modal windows (aka popups/dialogs) in Discourse","fancy_title_localized":false,"locale":"en","id":268304,"title":"Using the DModal API to render Modal windows (aka popups/dialogs) in Discourse","slug":"using-the-dmodal-api-to-render-modal-windows-aka-popups-dialogs-in-discourse","posts_count":1,"reply_count":1,"highest_post_number":1,"image_url":"https://global.discourse-cdn.com/meta/original/4X/4/0/b/40be9a7c253202136882269ba77d47ad86bd6d35.png","created_at":"2023-07-03T09:52:06.275Z","last_posted_at":"2023-07-03T09:52:06.275Z","bumped":true,"bumped_at":"2026-09-10T17:41:03.594Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"Discourse 3.1.0.beta6 ships with a brand new &lt;DModal&gt; component-based API. DModal is part of the UI kit and is imported from discourse/ui-kit/d-modal. \n\n:information_source: This supersedes the old controller-based API, &hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":[{"max_width":null,"max_height":null,"width":696,"height":258,"url":"https://global.discourse-cdn.com/meta/original/4X/4/0/b/40be9a7c253202136882269ba77d47ad86bd6d35.png"},{"max_width":600,"max_height":600,"width":600,"height":222,"url":"https://global.discourse-cdn.com/meta/optimized/4X/4/0/b/40be9a7c253202136882269ba77d47ad86bd6d35_2_600x222.png"},{"max_width":400,"max_height":400,"width":400,"height":148,"url":"https://global.discourse-cdn.com/meta/optimized/4X/4/0/b/40be9a7c253202136882269ba77d47ad86bd6d35_2_400x148.png"},{"max_width":300,"max_height":300,"width":300,"height":111,"url":"https://global.discourse-cdn.com/meta/optimized/4X/4/0/b/40be9a7c253202136882269ba77d47ad86bd6d35_2_300x111.png"},{"max_width":200,"max_height":200,"width":200,"height":74,"url":"https://global.discourse-cdn.com/meta/optimized/4X/4/0/b/40be9a7c253202136882269ba77d47ad86bd6d35_2_200x74.png"}],"tags":[{"id":819,"name":"code","slug":"code"}],"tags_descriptions":{},"views":2256,"like_count":17,"has_summary":false,"last_poster_username":"Discourse","category_id":56,"op_like_count":17,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":"latest","description":"Original Poster, Most Recent Poster","user_id":115923,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Recent Poster","user_id":1,"primary_group_id":47,"flair_group_id":47}]},{"fancy_title":"The UI kit of shared Discourse components, helpers, and modifiers","fancy_title_localized":false,"locale":null,"id":411319,"title":"The UI kit of shared Discourse components, helpers, and modifiers","slug":"the-ui-kit-of-shared-discourse-components-helpers-and-modifiers","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2026-08-31T17:34:15.933Z","last_posted_at":"2026-08-31T17:34:16.178Z","bumped":true,"bumped_at":"2026-09-10T17:41:01.737Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"ui-kit is the layer of reusable, domain-free building blocks that core, plugins, and themes compose their interfaces from. It lives under frontend/discourse/app/ui-kit/ and ships three kinds of primitive: \n\nComponents:&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[],"tags_descriptions":{},"views":120,"like_count":3,"has_summary":false,"last_poster_username":"system","category_id":56,"op_like_count":3,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user_id":-1,"primary_group_id":null,"flair_group_id":null}]},{"fancy_title":"Install Discourse on Windows for development","fancy_title_localized":false,"locale":"en","id":75149,"title":"Install Discourse on Windows for development","slug":"install-discourse-on-windows-for-development","posts_count":17,"reply_count":57,"highest_post_number":120,"image_url":null,"created_at":"2017-12-01T06:36:51.406Z","last_posted_at":"2026-04-22T10:18:42.190Z","bumped":true,"bumped_at":"2026-09-09T03:30:27.819Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":":information_source: This tutorial has been tested on Windows 10 and 11. \nTo set up a development environment for Discourse on Windows, you can do it using Windows Subsystem for Linux feature. \nThis setup requires the &hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[{"id":478,"name":"how-to","slug":"how-to"},{"id":150,"name":"dev-install","slug":"dev-install"}],"tags_descriptions":{"how-to":"How to guides contain steps to follow to solve a specific problem","dev-install":"Instructions and issues with installing Discourse for development"},"views":74914,"like_count":68,"has_summary":false,"last_poster_username":"merefield","category_id":56,"op_like_count":52,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":null,"description":"Original Poster","user_id":115923,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Frequent Poster","user_id":36685,"primary_group_id":null,"flair_group_id":148},{"extras":null,"description":"Frequent Poster","user_id":135392,"primary_group_id":null,"flair_group_id":48},{"extras":null,"description":"Recent Poster","user_id":191806,"primary_group_id":null,"flair_group_id":null},{"extras":"latest","description":"Most Recent Poster","user_id":27384,"primary_group_id":null,"flair_group_id":null}]},{"fancy_title":"Install Discourse on Ubuntu or Debian for Development","fancy_title_localized":false,"locale":"en","id":14727,"title":"Install Discourse on Ubuntu or Debian for Development","slug":"install-discourse-on-ubuntu-or-debian-for-development","posts_count":84,"reply_count":490,"highest_post_number":756,"image_url":null,"created_at":"2014-04-12T22:22:07.751Z","last_posted_at":"2025-06-22T00:31:14.326Z","bumped":true,"bumped_at":"2026-09-09T03:30:25.595Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":":warning: This guide covers installation instructions in a development environment. For a production guide see: Install Discourse in production with the official supported instructions \n\n\nSo you want to set up Discour&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[{"id":478,"name":"how-to","slug":"how-to"},{"id":150,"name":"dev-install","slug":"dev-install"}],"tags_descriptions":{"how-to":"How to guides contain steps to follow to solve a specific problem","dev-install":"Instructions and issues with installing Discourse for development"},"views":202273,"like_count":134,"has_summary":true,"last_poster_username":"NateDhaliwal","category_id":56,"op_like_count":66,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":null,"description":"Original Poster","user_id":115923,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Frequent Poster","user_id":14353,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Frequent Poster","user_id":114728,"primary_group_id":276,"flair_group_id":276},{"extras":null,"description":"Recent Poster","user_id":27384,"primary_group_id":null,"flair_group_id":null},{"extras":"latest","description":"Most Recent Poster","user_id":135392,"primary_group_id":null,"flair_group_id":48}]},{"fancy_title":"Install Discourse on macOS for development","fancy_title_localized":false,"locale":"en","id":15772,"title":"Install Discourse on macOS for development","slug":"install-discourse-on-macos-for-development","posts_count":103,"reply_count":236,"highest_post_number":402,"image_url":null,"created_at":"2014-05-19T16:59:50.976Z","last_posted_at":"2026-04-24T18:38:20.659Z","bumped":true,"bumped_at":"2026-09-09T03:30:24.313Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":":warning: This guide covers installation instructions for a macOS development environment, for production guides see: Install Discourse in production with the official supported instructions \n\nSo you want to set up Disc&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[{"id":478,"name":"how-to","slug":"how-to"},{"id":150,"name":"dev-install","slug":"dev-install"}],"tags_descriptions":{"how-to":"How to guides contain steps to follow to solve a specific problem","dev-install":"Instructions and issues with installing Discourse for development"},"views":116958,"like_count":283,"has_summary":true,"last_poster_username":"jericson","category_id":56,"op_like_count":78,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":null,"description":"Original Poster","user_id":115923,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Frequent Poster","user_id":125230,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Frequent Poster","user_id":14353,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Recent Poster","user_id":169973,"primary_group_id":null,"flair_group_id":null},{"extras":"latest","description":"Most Recent Poster","user_id":15442,"primary_group_id":null,"flair_group_id":118}]},{"fancy_title":"Bundle splitting for plugins","fancy_title_localized":false,"locale":null,"id":411886,"title":"Bundle splitting for plugins","slug":"bundle-splitting-for-plugins","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2026-09-08T11:07:29.302Z","last_posted_at":"2026-09-08T11:07:29.464Z","bumped":true,"bumped_at":"2026-09-08T11:07:29.464Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"By default, every javascript module in a plugin is loaded when Discourse boots. This guide describes the staticModules system, which allows code to be automatically loaded on-demand, thereby improving initial boot times. &hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[],"tags_descriptions":{},"views":78,"like_count":1,"has_summary":false,"last_poster_username":"system","category_id":56,"op_like_count":1,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user_id":-1,"primary_group_id":null,"flair_group_id":null}]},{"fancy_title":"Using Transformers to customize client-side values and behavior","fancy_title_localized":false,"locale":null,"id":349954,"title":"Using Transformers to customize client-side values and behavior","slug":"using-transformers-to-customize-client-side-values-and-behavior","posts_count":3,"reply_count":0,"highest_post_number":3,"image_url":null,"created_at":"2025-01-31T20:19:51.229Z","last_posted_at":"2026-09-05T02:53:05.790Z","bumped":true,"bumped_at":"2026-09-05T02:53:05.790Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"Discourse core includes a number of “transformer” hooks which can be used to customize client behavior. These fall into two categories: \n\n\nValue Transformers take an output from Discourse core, and optionally modify it, &hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[],"tags_descriptions":{},"views":770,"like_count":13,"has_summary":false,"last_poster_username":"NateDhaliwal","category_id":56,"op_like_count":10,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":null,"description":"Original Poster","user_id":-1,"primary_group_id":null,"flair_group_id":null},{"extras":"latest","description":"Most Recent Poster","user_id":135392,"primary_group_id":null,"flair_group_id":48}]},{"fancy_title":"Discourse toolkit to render forms","fancy_title_localized":false,"locale":null,"id":326439,"title":"Discourse toolkit to render forms","slug":"discourse-toolkit-to-render-forms","posts_count":29,"reply_count":18,"highest_post_number":33,"image_url":null,"created_at":"2024-09-13T21:20:27.941Z","last_posted_at":"2025-12-23T17:55:56.356Z","bumped":true,"bumped_at":"2026-09-01T18:53:43.134Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"Basic Usage\nFormKit exposes a single component as its public API: &lt;Form /&gt;. All other elements are yielded as contextual components, modifiers, or plain data. \nEvery form is composed of one or multiple fields, represen&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[],"tags_descriptions":{},"views":1851,"like_count":55,"has_summary":false,"last_poster_username":"merefield","category_id":56,"op_like_count":6,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":null,"description":"Original Poster","user_id":-1,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Frequent Poster","user_id":23163,"primary_group_id":47,"flair_group_id":47},{"extras":null,"description":"Frequent Poster","user_id":2770,"primary_group_id":47,"flair_group_id":47},{"extras":null,"description":"Recent Poster","user_id":15209,"primary_group_id":null,"flair_group_id":142},{"extras":"latest","description":"Most Recent Poster","user_id":27384,"primary_group_id":null,"flair_group_id":null}]},{"fancy_title":"Drag, resize, and gesture primitives","fancy_title_localized":false,"locale":null,"id":410549,"title":"Drag, resize, and gesture primitives","slug":"drag-resize-and-gesture-primitives","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2026-08-20T16:44:51.931Z","last_posted_at":"2026-08-20T16:44:52.183Z","bumped":true,"bumped_at":"2026-08-31T17:35:02.656Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"ui-kit ships the input-driven gesture primitives: dragging a payload onto a \ntarget, resizing a region, and reading a swipe or a pointer drag. This page is \nthe usage reference. Each primitive’s own TSDoc carries the f&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[],"tags_descriptions":{},"views":125,"like_count":5,"has_summary":false,"last_poster_username":"system","category_id":56,"op_like_count":5,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user_id":-1,"primary_group_id":null,"flair_group_id":null}]},{"fancy_title":"JavaScript type hinting &amp; validation (typescript)","fancy_title_localized":false,"locale":null,"id":395136,"title":"JavaScript type hinting & validation (typescript)","slug":"javascript-type-hinting-validation-typescript","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2026-02-04T10:38:25.830Z","last_posted_at":"2026-02-04T10:38:25.913Z","bumped":true,"bumped_at":"2026-08-31T17:34:58.115Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"Discourse ships type information for its JavaScript code. This can provide inline documentation, autocomplete, and other useful IDE features. It can also be used for some basic type validation, using the @ts-check direct&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[],"tags_descriptions":{},"views":240,"like_count":8,"has_summary":false,"last_poster_username":"system","category_id":56,"op_like_count":8,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user_id":-1,"primary_group_id":null,"flair_group_id":null}]},{"fancy_title":"AppEvents Triggers Reference","fancy_title_localized":false,"locale":null,"id":338465,"title":"AppEvents Triggers Reference","slug":"appevents-triggers-reference","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2024-11-26T10:20:08.061Z","last_posted_at":"2024-11-26T10:20:08.461Z","bumped":true,"bumped_at":"2026-08-31T17:34:52.470Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"AppEvents\nThe AppEvent system in Discourse provides a pub/sub mechanism for handling UI updates and component interactions - and these events are triggered via calls of AppEvent.trigger. \nThis topic consolidates a list&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[],"tags_descriptions":{},"views":564,"like_count":10,"has_summary":false,"last_poster_username":"system","category_id":56,"op_like_count":10,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user_id":-1,"primary_group_id":null,"flair_group_id":null}]},{"fancy_title":"Write end-to-end system specs for the Discourse user interface","fancy_title_localized":false,"locale":null,"id":325937,"title":"Write end-to-end system specs for the Discourse user interface","slug":"write-end-to-end-system-specs-for-the-discourse-user-interface","posts_count":4,"reply_count":2,"highest_post_number":5,"image_url":"https://global.discourse-cdn.com/meta/original/4X/5/5/5/55573c386666cc876d212e64995fd6a7a8bccc64.png","created_at":"2024-09-11T04:07:31.148Z","last_posted_at":"2025-08-28T14:51:13.004Z","bumped":true,"bumped_at":"2026-08-31T17:34:46.127Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"Background\nRails system specs are used to simulate the actions of a real user using the app in a browser. We use the Playwright ruby driver which is becoming an industry standard. The tests run locally and in CI out of t&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":[{"max_width":null,"max_height":null,"width":990,"height":602,"url":"https://global.discourse-cdn.com/meta/original/4X/5/5/5/55573c386666cc876d212e64995fd6a7a8bccc64.png"},{"max_width":800,"max_height":800,"width":800,"height":486,"url":"https://global.discourse-cdn.com/meta/optimized/4X/5/5/5/55573c386666cc876d212e64995fd6a7a8bccc64_2_800x486.png"},{"max_width":600,"max_height":600,"width":600,"height":364,"url":"https://global.discourse-cdn.com/meta/optimized/4X/5/5/5/55573c386666cc876d212e64995fd6a7a8bccc64_2_600x364.png"},{"max_width":400,"max_height":400,"width":400,"height":243,"url":"https://global.discourse-cdn.com/meta/optimized/4X/5/5/5/55573c386666cc876d212e64995fd6a7a8bccc64_2_400x243.png"},{"max_width":300,"max_height":300,"width":300,"height":182,"url":"https://global.discourse-cdn.com/meta/optimized/4X/5/5/5/55573c386666cc876d212e64995fd6a7a8bccc64_2_300x182.png"},{"max_width":200,"max_height":200,"width":200,"height":121,"url":"https://global.discourse-cdn.com/meta/optimized/4X/5/5/5/55573c386666cc876d212e64995fd6a7a8bccc64_2_200x121.png"}],"tags":[],"tags_descriptions":{},"views":739,"like_count":12,"has_summary":false,"last_poster_username":"merefield","category_id":56,"op_like_count":9,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":null,"description":"Original Poster","user_id":-1,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Recent Poster","user_id":21029,"primary_group_id":47,"flair_group_id":47},{"extras":"latest","description":"Most Recent Poster","user_id":27384,"primary_group_id":null,"flair_group_id":null}]},{"fancy_title":"(not recommended) Overriding Discourse templates from a Theme or Plugin","fancy_title_localized":false,"locale":"en","id":247487,"title":"(not recommended) Overriding Discourse templates from a Theme or Plugin","slug":"not-recommended-overriding-discourse-templates-from-a-theme-or-plugin","posts_count":10,"reply_count":6,"highest_post_number":14,"image_url":null,"created_at":"2022-12-02T13:52:58.399Z","last_posted_at":"2024-03-07T13:20:54.842Z","bumped":true,"bumped_at":"2026-08-31T17:34:42.109Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"Ideally, when customizing Discourse via themes/plugins, you should use CSS, the JavaScript Plugin API, or plugin outlets. If none of these work for your use-case, feel free to open a PR to Discourse core or start a <span class=\"hashtag-icon-placeholder\"></span>Devel&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"visibility_reason_id":4,"tags":[{"id":478,"name":"how-to","slug":"how-to"}],"tags_descriptions":{"how-to":"How to guides contain steps to follow to solve a specific problem"},"views":2948,"like_count":42,"has_summary":false,"last_poster_username":"merefield","category_id":56,"op_like_count":17,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":null,"description":"Original Poster","user_id":115923,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Frequent Poster","user_id":23968,"primary_group_id":47,"flair_group_id":47},{"extras":null,"description":"Frequent Poster","user_id":125035,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Recent Poster","user_id":100484,"primary_group_id":null,"flair_group_id":null},{"extras":"latest","description":"Most Recent Poster","user_id":27384,"primary_group_id":null,"flair_group_id":null}]},{"fancy_title":"Preventing accidental serialization of ActiveRecord models","fancy_title_localized":false,"locale":"en","id":314495,"title":"Preventing accidental serialization of ActiveRecord models","slug":"preventing-accidental-serialization-of-activerecord-models","posts_count":3,"reply_count":1,"highest_post_number":5,"image_url":null,"created_at":"2024-07-01T19:58:28.233Z","last_posted_at":"2024-07-23T17:59:58.860Z","bumped":true,"bumped_at":"2026-08-31T17:34:40.981Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"We’ve introduced a patch to prevent the accidental serialization of ActiveRecord models without specifying the fields to be serialized. This change ensures that we control which fields are included, avoiding potential is&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[{"id":482,"name":"reference","slug":"reference"}],"tags_descriptions":{},"views":546,"like_count":12,"has_summary":false,"last_poster_username":"pfaffman","category_id":56,"op_like_count":6,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":null,"description":"Original Poster","user_id":115923,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Recent Poster","user_id":13378,"primary_group_id":null,"flair_group_id":142},{"extras":"latest","description":"Most Recent Poster","user_id":15209,"primary_group_id":null,"flair_group_id":142}]},{"fancy_title":"Creating Routes in Discourse and Showing Data","fancy_title_localized":false,"locale":"en","id":48827,"title":"Creating Routes in Discourse and Showing Data","slug":"creating-routes-in-discourse-and-showing-data","posts_count":1,"reply_count":25,"highest_post_number":1,"image_url":null,"created_at":"2016-08-18T20:18:49.501Z","last_posted_at":"2016-08-18T20:18:49.572Z","bumped":true,"bumped_at":"2026-08-31T17:34:38.704Z","archetype":"regular","unseen":false,"pinned":false,"unpinned":null,"excerpt":"Over time Discourse has grown in complexity and it can be daunting for beginners to understand how data gets all the way from the back end Ruby on Rails application to the Ember.js application in front. \nThis tutorial is&hellip;","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"thumbnails":null,"tags":[{"id":484,"name":"tutorial","slug":"tutorial"},{"id":70,"name":"ember","slug":"ember"}],"tags_descriptions":{"tutorial":""},"views":11920,"like_count":46,"has_summary":false,"last_poster_username":"Discourse","category_id":56,"op_like_count":46,"pinned_globally":false,"featured_link":null,"has_accepted_answer":false,"can_vote":false,"posters":[{"extras":"latest","description":"Original Poster, Most Recent Poster","user_id":115923,"primary_group_id":null,"flair_group_id":null},{"extras":null,"description":"Recent Poster","user_id":100484,"primary_group_id":null,"flair_group_id":null}]}]}}