Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Intro to Craft 3

Intro to Craft 3

A look at the new features coming in Craft CMS 3

Brandon Kelly

April 26, 2017
Tweet

More Decks by Brandon Kelly

Other Decks in Technology

Transcript

  1. Modern Tech Stack — PHP 7 — Yii 2 —

    Guzzle 6 — Twig 2 — OpenSSL
  2. Craft is now a Composer dependency right alongside other project

    dependencies. > composer require \ craftcms/cms:^3.0.0-beta.1
  3. There’s also a Composer project you can use as a

    starting point. > composer create-project \ craftcms/craft \ my_project \ --stability beta
  4. The default project structure has changed a bit. Old New

    craft/app/ vendor/craftcms/cms/ craft/config/ config/ craft/storage/ storage/ craft/templates/ templates/ public/ web/
  5. Sites are like locales, except… — you give them a

    custom name and handle — they have language, but they are not defined by it — multiple sites can share the same language — fields can be translated per-site, per-language, or even something custom
  6. When should you use Multi-Site? ! " Multi-lingual sites Different

    orgs Sister sites No shared content Landing pages
  7. Internationalization improvements in Craft 3: — Craft uses the Intl

    extension when available. — Fallback data for all the locales is available at github.com/craftcms/locales — Support for PostgreSQL ! — Translation categories
  8. Volumes — Asset Sources are called “Volumes” now — Plugins

    can supply custom volume types — User photos are stored as assets now, and you choose which volume
  9. Craft can now manage migrations that are specific to your

    project. > ./craft migrate/create create_new_field
  10. use craft\db\Migration; use craft\fields\PlainText; class m170331_030925_create_new_field extends Migration { public

    function safeUp() { $field = new PlainText(); $field->groupId = 1; $field->name = 'Address'; $field->handle = 'address'; $field->multiline = true; \Craft::$app->fields->saveField($field); } }
  11. Content migrations have access to the full set of Craft

    APIs, so you can do whatever you want in them.
  12. ElementQuery is the new ElementCriteriaModel. Still works the same, for

    the most part. {% set entries = craft.entries() .section('news') .limit(10) %}
  13. ElementQuery is the new ElementCriteriaModel. Still works the same, for

    the most part. {% set entries = craft.entries() .section('news') .limit(10) %} But way, way more powerful.
  14. A few functions have changed. Old New find() all() first()

    one() order() orderBy() total() count()
  15. Lots of new functions have been introduced. Name Purpose select(columns)

    override the SELECT addSelect(columns) add more columns to the SELECT
  16. Lots of new functions have been introduced. Name Purpose where(condition)

    override the WHERE andWhere(condition) add an AND condition to the WHERE orWhere(condition) add an OR condition to the WHERE
  17. Lots of new functions have been introduced. Name Purpose innerJoin(table)

    add an INNER JOIN leftJoin(table) add a LEFT JOIN rightJoin(table) add a RIGHT JOIN
  18. Lots of new functions have been introduced. Name Purpose asArray()

    return raw data arrays rather than Element models indexBy(column) indexes returned values by a column’s value
  19. Lots of new functions have been introduced. Name Returns column()

    first column’s values pairs() key/value pairs scalar() first value of first column exists() if there are any results
  20. Lots of new functions have been introduced. Name Returns sum(column)

    sum value average(column) average value min(column) smallest value max(column) largest value
  21. Lots of new functions have been introduced. Name Returns batch(size)

    lazy-loaded batched results each(size) iterator for all results, but lazy-loaded in batches behind the scenes
  22. Example: get entries, indexed by their IDs {% set entriesById

    = craft.entries() .section('news') .indexBy('elements.id') .all() %}
  23. Example: get entry titles, indexed by their IDs {% set

    titlesById = craft.entries() .section('news') .select('elements.id, content.title') .pairs() %}
  24. Example: get the average value for a custom field {%

    set averageAge = craft.users() .andWhere('field_age is not null') .average('field_age') %}
  25. Example: load users in lazy-loaded batches {% for user in

    craft.users().each() %} <li>{{ user.name }}</li> {% endfor %}
  26. You can output the raw SQL query to be executed:

    {% set q = craft.entries().section('news') %} <pre>{{ q.getRawSql() }}</pre>
  27. You can output the raw SQL query to be executed:

    {% set q = craft.entries().section('news') %} <pre>{{ q.getRawSql() }}</pre> Output: SELECT `elements`.`id`, `elements`.`fieldLayoutId`, `elements`.`uid`, ...
  28. Example: loop through all the sections {% set sections =

    craft.app .sections.getAllSections() %} {% for section in sections %} <li>{{ section.name }}</li> {% endfor %}
  29. Define environment-specific variables in a .env file that doesn’t get

    committed to Git. DB_SERVER="localhost" DB_USER="homestead" DB_PASSWORD="secret" DB_DATABASE="happylager"
  30. Ways to define environment-specific settings: — Per-environment configs — PHP

    dotenv environment variables — environmentVariables
  31. Ways to define environment-specific settings: — Per-environment configs — PHP

    dotenv environment variables — environmentVariables
  32. Site URLs can be defined per-environment using the siteUrl config

    setting in config/general.php. return [ '*' => [], '.dev' => [ 'siteUrl' => 'http://site.dev', ], '.com' => [ 'siteUrl' => '//site.com', ], ], ];
  33. Volume settings can be overridden in config/volumes.php. return [ 'userPhotos'

    => [ 'path' => getenv('PHOTOS_PATH'), 'url' => getenv('PHOTOS_URL'), ], ];
  34. return [ 'headers' => ['Foo' => 'Bar'], 'query' => ['testing'

    => '123'], 'auth' => ['username', 'password'], 'proxy' => 'tcp://localhost:80' ];
  35. return [ 'components' => [ 'mailer' => function() { $settings

    = Craft::$app->systemSettings->emailSettings; $settings->transportType = MailgunAdapter::class; $settings->transportSettings = [ 'domain' => 'foo.com', 'apiKey' => 'key-xxxxxxxxxx', ]; return MailerHelper::createMailer($settings); } ], ];
  36. Recap 1. Security & Performance 2. Composer 3. Multi-Site 4.

    Internationalization 5. Assets 6. Utilities 7. Content Migrations 8. Templating 9. Debug Toolbar 10. Configuration