Build a template-enforcement tool
Reset stray slides back to the Northwind master layout — fix decks that drifted.
Published Sep 28, 2025
Every Northwind deck starts on-brand and ends up off-brand. Someone duplicates a slide, deletes the title placeholder, drops a free-floating text box where the header should be, and now the layout system has nothing to grab onto. A month later the deck looks like a ransom note. The fix is not “lecture the designers” — it is to scan for slides that have lost their placeholders and reset them back to the master layout.
This script walks a deck and replaces any slide that has no placeholders left with a fresh slide on the default layout. The original is removed, the replacement keeps its position in the deck order, and the rest of the deck is left alone. It is deliberately conservative: it only touches slides that have nothing left to anchor to, so a stylistic flourish is safe but a fully freeformed slide gets reset.
What you’ll need
- A Google Slides deck that has drifted from its template.
- A copy of the deck to test on — this script is destructive and removes slides. Always run it on a copy first.
- Nothing else — no external services, no API keys.
The script
// The layout to reset stray slides to. Change this to whatever your master
// uses as its default body layout — TITLE_AND_BODY is the most common.
const DEFAULT_LAYOUT = SlidesApp.PredefinedLayout.TITLE_AND_BODY;
/**
* Replaces any slide that has lost all its placeholders with a fresh slide
* on the given layout. The replacement is inserted at the same position so
* the deck order is preserved.
*
* @param {string} deckId The Slides file ID.
* @param {SlidesApp.PredefinedLayout} [layout] Layout to use for resets.
* @returns {number} How many slides were reset.
*/
function enforceLayout(deckId, layout = DEFAULT_LAYOUT) {
if (!deckId) throw new Error('enforceLayout needs a deckId.');
const deck = SlidesApp.openById(deckId);
const slides = deck.getSlides();
let reset = 0;
// 1. Iterate over a snapshot of the slides so removing one mid-loop does
// not throw off the index of the others.
slides.forEach((slide, index) => {
// 2. A slide with no placeholders has nothing the master layout can
// bind to — that's the signature of a freeformed slide.
if (slide.getPlaceholders().length > 0) return;
// 3. Insert the replacement at the same index, then remove the
// original. Doing it in this order keeps the deck order stable.
deck.insertSlide(index, layout);
slide.remove();
reset++;
Logger.log(`Reset slide ${index + 1} to ${layout}.`);
});
Logger.log(`Done — reset ${reset} slide(s) in deck ${deckId}.`);
return reset;
}
/**
* Convenience wrapper so you can click Run in the editor without writing a
* caller. Replace the ID with your own — and run it on a COPY first.
*/
function enforceNorthwindDeck() {
enforceLayout('1abcDeckCopyId');
}
How it works
enforceLayoutopens the deck and snapshots the slides into an array. By iterating over the snapshot rather than re-readingdeck.getSlides()on every step, removing a slide mid-loop does not throw off the indexes of the remaining ones.- For each slide it asks
getPlaceholders()— these are the title, body, and other shapes the master layout owns. A slide with at least one placeholder is still connected to the template, so the script leaves it alone. - When a slide returns zero placeholders, it has been freeformed past the point of recovery. The script inserts a fresh slide on the default layout at the same index, then removes the offending slide. Doing the insert first preserves the deck’s slide order.
- It logs the slide number it reset so the designer can go back and re-create the content on a clean canvas.
- At the end it returns the count, useful if you want to wire this into a bigger report or alert on decks that drifted badly.
Example run
Say 1abcDeckCopyId is a 10-slide deck where slides 3 and 7 have had every
placeholder deleted and replaced with floating shapes. After a run:
| Slide | Before | After |
|---|---|---|
| 1 | Title slide (intact) | Unchanged |
| 2 | Body slide (intact) | Unchanged |
| 3 | Freeformed — no placeholders | Reset to TITLE_AND_BODY |
| 4-6 | Body slides (intact) | Unchanged |
| 7 | Freeformed — no placeholders | Reset to TITLE_AND_BODY |
| 8-10 | Body slides (intact) | Unchanged |
The log shows:
Reset slide 3 to TITLE_AND_BODY.
Reset slide 7 to TITLE_AND_BODY.
Done — reset 2 slide(s) in deck 1abcDeckCopyId.
The designer now has two blank-but-on-brand slides at the right positions and the content to rebuild from the previous version.
Run it
This is an on-demand job — run it when a deck audit turns up drift:
- Make a copy of the original deck. This script is destructive.
- In the Apps Script editor, select
enforceNorthwindDeckand click Run. - Approve the authorisation prompt the first time.
- Open the copy, check which slides were reset, and rebuild their content on the fresh placeholders.
For a stricter version, expand the rule: flag slides whose placeholders are present but empty, or whose title text doesn’t match the master’s typography. Those checks belong in a separate “audit” function that reports rather than mutates.
Watch out for
- This is destructive. The original slide is removed, including any content the script could not preserve. Always run on a copy and compare side by side before replacing the live deck.
- It does not migrate content. A reset slide is blank — the script makes no attempt to find the title text or bullets on the freeformed version and copy them over. That’s intentional: guessing wrong silently loses content.
- The placeholder-count heuristic is conservative. A slide with one placeholder left is considered “fine”, even if the rest of it is a mess. Tighten the check if your template defines a specific minimum.
- Layouts must exist on the master.
PredefinedLayout.TITLE_AND_BODYworks on any standard Slides theme, but a custom theme may have renamed or removed it — pick a layout that actually exists in your deck’s master.
Related
Extract all deck text into a sheet
Pull text out of every slide for review, translation, or copy-editing.
Updated Jan 4, 2026
Generate sales-enablement decks per segment
Tailor Northwind's messaging slides by audience segment — fintech, healthcare, retail.
Updated Dec 28, 2025
Insert chapter divider slides from an outline
Add section-break slides between chapters in a Northwind deck.
Updated Dec 21, 2025
Build a deck accessibility checker
Flag missing alt text, low contrast, and tiny fonts across a Northwind deck.
Updated Dec 14, 2025
Drive menu and price-list signage from a Sheet
Generate display slides for a Northwind venue — menus or price lists driven by a Sheet.
Updated Dec 7, 2025