Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Patience and the right tools – ways to approach...
Search
stefan judis
February 08, 2018
Technology
690
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Patience and the right tools – ways to approach content modelling
stefan judis
February 08, 2018
More Decks by stefan judis
See All by stefan judis
Back to boring (part 2)
stefanjudis
0
380
Playwright can do this?
stefanjudis
0
260
Things you should know about Frontend Development in 2022
stefanjudis
0
560
Throw yourself out there for fun and profit
stefanjudis
0
140
Back to Boring
stefanjudis
1
540
Wanna scale up? Make sure your CMS is ready for it!
stefanjudis
0
290
Did we(b development) lose the right direction?
stefanjudis
6
2.2k
Regular expressions – my secret love
stefanjudis
1
1.1k
Write a Function
stefanjudis
0
630
Other Decks in Technology
See All in Technology
ハーレムエンジニアリング
kazuma777777
0
180
生成 AI の基礎 〜 サンプル実装で学ぶ基本原理
enakai00
7
4.4k
【AG-UI × A2UI × MCP Apps】Generative UIをやさしく解説する
nrinetcom
PRO
1
140
SO-101×VLAによる3色キューブのピック&プレース
abeja
0
210
Goでデータパイプラインを作ろう
sansantech
PRO
1
500
20分でわかるセキュアAPI
nwiizo
2
300
AIコーディングの次。コードレビューと理解負荷を解消して組織の開発生産性を高める
moongift
PRO
2
2.6k
Sansan Engineering Unit 紹介資料
sansan33
PRO
1
4.9k
研究開発部の紹介 / Sansan R&D Profile
sansan33
PRO
4
24k
Master Dataグループ紹介資料
sansan33
PRO
1
4.8k
FDEの心得
noriakioji
5
6.2k
【CEDEC2026】『ウマ娘 プリティーダービー』 英語版のキャラクターの方言や口調をローカライズするための創造的アプローチ
cygames
PRO
2
1.1k
Featured
See All Featured
Making the Leap to Tech Lead
cromwellryan
135
10k
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.5k
Reflections from 52 weeks, 52 projects
jeffersonlam
356
21k
Navigating Team Friction
lara
192
16k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
360
30k
Amusing Abliteration
ianozsvald
1
250
Being A Developer After 40
akosma
91
590k
Making Projects Easy
brettharned
120
6.7k
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
300
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
700
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
56
3.4k
Transcript
Patience and the right tools @stefanjudis Ways to approach content
modelling
Stefan Judis Frontend Developer, Occasional Teacher, Meetup Organizer ❤ Open
Source, Performance and Accessibility ❤ @stefanjudis
Where we come from
Karen McGrane I don’t necessarily know where this content is
going to live. I don’t know how it’s going to be used in the future. But, I do know that I have to create lots of flexible content that has metadata attached to it because I know it’s going to be reused in different places. “
None
None
It's like Lego
NOBODY(!) GETS IT RIGHT THE FIRST TIME...
share Share & reuse
github.com/joshhebb/angularjs-contentful-starter
None
www.npmjs.com/package/contentful-import www.npmjs.com/package/contentful-export
It's just code Setting up a space is quickly done
When you know how...
I believe in tooling and defaults!
Eat your own dog food
None
USEFUL FOR ANYONE?
Share content models?
None
www.contentfulcommunity.com MAYBE HERE?
Analyse
None
www.npmjs.com/package/contentful-graph
None
YOUR CONTENT MODEL VISUALISED.
None
None
CLI is great, but there is more
contentful-graph.yaraslav.com/
Evolve
Clean up time
www.npmjs.com/package/contentful-migration-cli
MIGRATION CLI CONTENT TYPE OPERATIONS Create a content type 01
02 03 04 05 Delete a content type Edit a content type Create/edit/delete fields Change a field ID
FIELDS TO DELETE
Drop fields module.exports = function (migration) { const event =
migration.editContentType('event') const project = migration.editContentType('project') }
module.exports = function (migration) { const event = migration.editContentType('event') event.deleteField('hotel')
event.deleteField('venue') const project = migration.editContentType('project') project.deleteField('screenshot') } Drop fields
None
FIELDS TO RENAME VS
module.exports = function (migration) { const tilPost = migration.editContentType('tilPost') }
Change field ID
module.exports = function (migration) { const tilPost = migration.editContentType('tilPost') tilPost.changeFieldId('categories',
'tags') tilPost.editField('tags', { name: 'Tags' }) tilPost.moveField('tags').afterField('date') } Change field ID
None
FRONTTRENDS 2017 COUNTRY : PL CITY : WARSAW ... FRONTTRENDS
2018 COUNTRY : PL CITY : WARSAW ... DERIVE ENTRIES AND LINK
FT COUNTRY: PL CITY : WARSAW FRONTTRENDS 2017 COUNTRY :
PL CITY : WARSAW ... FRONTTRENDS 2018 COUNTRY : PL CITY : WARSAW ... DERIVE ENTRIES AND LINK
FRONTTRENDS 2017 CONFERENCE : FT ... FRONTTRENDS 2018 CONFERENCE :
FT ... FT COUNTRY: PL CITY : WARSAW DERIVE ENTRIES AND LINK
A looong manual nightshift
No way!
repetetive error-prone not scalable MANUAL CONTENT MODEL CHANGES ARE NOT
THE SOLUTION
Transform an entry in place 01 02 Derive an entry
from another MIGRATION CLI CONTENT TRANSFORMATIONS
module.exports = function (migration) { const conference = migration.createContentType('conference') .name('Conference/Meetup')
.displayField('name') conference.createField('name') .type('Symbol') .required(true) .name('Conference/Meetup name') conference.createField('country') .type('Symbol') .required(true) .name('Country Code') conference.createField('city') .type('Symbol') .required(true) .name('City') Derive entries and link
.name('Country Code') conference.createField('city') .type('Symbol') .required(true) .name('City') const event = migration.editContentType('event')
event.createField('conference') .name('Conference') .type('Link') .linkType('Entry') .validations([ { "linkContentType": ['conference'] } ]) Derive entries and link
]) migration.deriveLinkedEntries({ contentType: 'event', from: ['name', 'country', 'city'], toReferenceField: 'conference',
derivedContentType: 'conference', derivedFields: ['name', 'country', 'city'], identityKey: async (from) => { return getId(from.name['en-US']) }, deriveEntryForLocale: async (inputFields, locale) => { return { name: inputFields.name[locale].replace(/\s(\d{2,4}|#\d+)/g, ''), country: inputFields.country[locale] || 'N/A', city: inputFields.city[locale] || 'N/A' } } }) Derive entries and link
]) migration.deriveLinkedEntries({ contentType: 'event', from: ['name', 'country', 'city'], toReferenceField: 'conference',
derivedContentType: 'conference', derivedFields: ['name', 'country', 'city'], identityKey: async (from) => { return getId(from.name['en-US']) }, deriveEntryForLocale: async (inputFields, locale) => { return { name: inputFields.name[locale].replace(/\s(\d{2,4}|#\d+)/g, ''), country: inputFields.country[locale] || 'N/A', city: inputFields.city[locale] || 'N/A' } } }) Derive entries and link
]) migration.deriveLinkedEntries({ contentType: 'event', from: ['name', 'country', 'city'], toReferenceField: 'conference',
derivedContentType: 'conference', derivedFields: ['name', 'country', 'city'], identityKey: async (from) => { return getId(from.name['en-US']) }, deriveEntryForLocale: async (inputFields, locale) => { return { name: inputFields.name[locale].replace(/\s(\d{2,4}|#\d+)/g, ''), country: inputFields.country[locale] || 'N/A', city: inputFields.city[locale] || 'N/A' } } }) Derive entries and link
]) migration.deriveLinkedEntries({ contentType: 'event', from: ['name', 'country', 'city'], toReferenceField: 'conference',
derivedContentType: 'conference', derivedFields: ['name', 'country', 'city'], identityKey: async (from) => { return getId(from.name['en-US']) }, deriveEntryForLocale: async (inputFields, locale) => { return { name: inputFields.name[locale].replace(/\s(\d{2,4}|#\d+)/g, ''), country: inputFields.country[locale] || 'N/A', city: inputFields.city[locale] || 'N/A' } } }) Derive entries and link
} } }) event.moveField('conference').afterField('name') event.deleteField('country') event.deleteField('city') } Derive entries and
link
None
module.exports = function (migration) { const conference = migration.createContentType('conference') .name('Conference/Meetup')
.displayField('name') conference.createField('name').type('Symbol').required(true).name('Conference/Meetup name') conference.createField('country').type('Symbol').required(true).name('Country Code') conference.createField('city').type('Symbol').required(true).name('City') const event = migration.editContentType('event') event.createField('conference') .name('Conference') .type('Link') .linkType('Entry') .validations([ { "linkContentType": ['conference'] } ]) migration.deriveLinkedEntries({ contentType: 'event', from: ['name', 'country', 'city'], toReferenceField: 'conference', derivedContentType: 'conference', derivedFields: ['name', 'country', 'city'], identityKey: async (from) => { return from.name['en-US'] // remove year .replace(/\s(\d{2,4}|#\d+)/g, '') // clear spaces .replace(/\s/g, '-') // clear "weird characters" .replace(/(,|\/|\\|:|\.|\(|\))/g, '') .toLowerCase() }, deriveEntryForLocale: async (inputFields, locale) => { return { name: inputFields.name[locale].replace(/\s(\d{2,4}|#\d+)/g, ''), country: inputFields.country[locale] || 'N/A', city: inputFields.city[locale] || 'N/A' } } }) event.moveField('conference').afterField('name') event.deleteField('country') event.deleteField('city') } LOC 48 REQUESTS 382 ENTRIES CREATED 88 ENTRIES UPDATED 96
MIGRATION CLI ADVANTAGES Repeatable 01 02 03 04 Can be
kept in VC Includes sanity checks Perfect for CI
NOBODY(!) GETS IT RIGHT THE FIRST TIME...
61 WAYS TO SURVIVE SHARE & REUSE ANALYSE EVOLVE
with the right tools...
Thanks. @stefanjudis Slides ctfl.io/content-modelling-is-tricky Article ctfl.io/content-modelling-is-tricky-article