Patience and the right tools – ways to approach content modelling

22725c2d3eb331146549bf0d5d3c050c?s=47 stefan judis
February 08, 2018

Patience and the right tools – ways to approach content modelling

22725c2d3eb331146549bf0d5d3c050c?s=128

stefan judis

February 08, 2018
Tweet

Transcript

  1. Patience and the right tools @stefanjudis Ways to approach
 content

    modelling
  2. Stefan Judis Frontend Developer, Occasional Teacher, Meetup Organizer ❤ Open

    Source, Performance and Accessibility ❤ @stefanjudis
  3. Where we come from

  4. 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. “
  5. None
  6. None
  7. It's like Lego

  8. NOBODY(!) GETS IT RIGHT THE FIRST TIME...

  9. share Share & reuse

  10. github.com/joshhebb/angularjs-contentful-starter

  11. None
  12. www.npmjs.com/package/contentful-import www.npmjs.com/package/contentful-export

  13. It's just code Setting up a space is quickly done

  14. When you know how...

  15. I believe in tooling and defaults!

  16. Eat your own dog food

  17. None
  18. USEFUL FOR ANYONE?

  19. Share content models?

  20. None
  21. www.contentfulcommunity.com MAYBE HERE?

  22. Analyse

  23. None
  24. www.npmjs.com/package/contentful-graph

  25. None
  26. YOUR CONTENT MODEL VISUALISED.

  27. None
  28. None
  29. CLI is great, but there is more

  30. contentful-graph.yaraslav.com/

  31. Evolve

  32. Clean up time

  33. www.npmjs.com/package/contentful-migration-cli

  34. 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
  35. FIELDS TO DELETE

  36. Drop fields module.exports = function (migration) { const event =

    migration.editContentType('event') const project = migration.editContentType('project') }
  37. 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
  38. None
  39. FIELDS TO RENAME VS

  40. module.exports = function (migration) { const tilPost = migration.editContentType('tilPost') }

    Change field ID
  41. 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
  42. None
  43. FRONTTRENDS 2017 COUNTRY : PL CITY : WARSAW ... FRONTTRENDS

    2018 COUNTRY : PL CITY : WARSAW ... DERIVE ENTRIES AND LINK
  44. FT COUNTRY: PL CITY : WARSAW FRONTTRENDS 2017 COUNTRY :

    PL CITY : WARSAW ... FRONTTRENDS 2018 COUNTRY : PL CITY : WARSAW ... DERIVE ENTRIES AND LINK
  45. FRONTTRENDS 2017 CONFERENCE : FT ... FRONTTRENDS 2018 CONFERENCE :

    FT ... FT COUNTRY: PL CITY : WARSAW DERIVE ENTRIES AND LINK
  46. A looong manual nightshift

  47. No way!

  48. repetetive error-prone not scalable MANUAL CONTENT MODEL CHANGES ARE NOT

    THE SOLUTION
  49. Transform an entry in place 01 02 Derive an entry

    from another MIGRATION CLI CONTENT TRANSFORMATIONS
  50. 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
  51. .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
  52. ]) 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
  53. ]) 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
  54. ]) 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
  55. ]) 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
  56. } } }) event.moveField('conference').afterField('name') event.deleteField('country') event.deleteField('city') } Derive entries and

    link
  57. None
  58. 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
  59. MIGRATION CLI ADVANTAGES Repeatable 01 02 03 04 Can be

    kept in VC Includes sanity checks Perfect for CI
  60. NOBODY(!) GETS IT RIGHT THE FIRST TIME...

  61. 61 WAYS TO SURVIVE SHARE & REUSE ANALYSE EVOLVE

  62. with the right tools...

  63. Thanks. @stefanjudis Slides ctfl.io/content-modelling-is-tricky Article ctfl.io/content-modelling-is-tricky-article