Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
Patience and the right tools – ways to approach content modelling
stefan judis
February 08, 2018
Technology
1
460
Patience and the right tools – ways to approach content modelling
stefan judis
February 08, 2018
Tweet
Share
More Decks by stefan judis
See All by stefan judis
Things you should know about Frontend Development in 2022
stefanjudis
0
260
Throw yourself out there for fun and profit
stefanjudis
0
28
Back to Boring
stefanjudis
1
110
Wanna scale up? Make sure your CMS is ready for it!
stefanjudis
0
110
Did we(b development) lose the right direction?
stefanjudis
6
1.9k
Regular expressions – my secret love
stefanjudis
1
870
Write a Function
stefanjudis
0
380
React in a worker, worker, worker...
stefanjudis
2
350
HTTP headers for the responsible developer
stefanjudis
5
3.9k
Other Decks in Technology
See All in Technology
Google Cloud Workflows: API automation, patterns and best practices
glaforge
0
100
Oracle Transaction Manager for Microservices Free 22.3 製品概要
oracle4engineer
PRO
5
110
OpenShift.Run2023_create-aro-with-terraform
ishiitaiki20fixer
1
310
Pentesting Password Reset Functionality
anugrahsr
0
520
Multi-Cloud Gatewayでデータを統治せよ!/ Data Federation with MCG
tutsunom
1
310
ECテックカンファレンス2023 EC事業部のモバイル開発2023
tatsumi0000
0
310
AI Services 概要 / AI Services overview
oracle4engineer
PRO
0
170
【NGK2023S】 ノードエディタ形式の画像処理ツール「Image-Processing-Node-Editor」
kazuhitotakahashi
0
310
開発者と協働できるメトリクスダッシュボードを作ろう!/SRE Lounge 2023
lmi
3
500
スクラム導入して変わったチーム、組織のありかた
yumechi
0
200
Kaggleシミュレーションコンペの動向
nagiss
0
280
NGINXENG JP#2 - 1-NGINX-エンジニアリング勉強会-きょうの見どころ
hiropo20
0
110
Featured
See All Featured
Web Components: a chance to create the future
zenorocha
304
40k
Bash Introduction
62gerente
601
210k
Visualization
eitanlees
128
12k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
217
21k
JazzCon 2018 Closing Keynote - Leadership for the Reluctant Leader
reverentgeek
175
9.1k
Building an army of robots
kneath
301
40k
How To Stay Up To Date on Web Technology
chriscoyier
779
250k
A better future with KSS
kneath
230
16k
Fantastic passwords and where to find them - at NoRuKo
philnash
32
1.9k
Teambox: Starting and Learning
jrom
124
7.9k
Typedesign – Prime Four
hannesfritz
34
1.5k
Building Adaptive Systems
keathley
27
1.3k
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