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. View Slide

  2. 1. Security & Performance

    View Slide

  3. Modern Tech Stack
    — PHP 7
    — Yii 2
    — Guzzle 6
    — Twig 2
    — OpenSSL

    View Slide

  4. Average time (milliseconds)
    taken to load the Happy Lager
    homepage over 100 requests

    View Slide

  5. Seconds taken to load 5,000
    entries at once

    View Slide

  6. Memory (MB) consumed when
    loading 5,000 entries at once

    View Slide

  7. 2. Composer

    View Slide

  8. Craft is now a Composer
    dependency right alongside other
    project dependencies.

    View Slide

  9. Craft is now a Composer
    dependency right alongside other
    project dependencies.
    > composer require \
    craftcms/cms:^3.0.0-beta.1

    View Slide

  10. There’s also a Composer project
    you can use as a starting point.
    > composer create-project \
    craftcms/craft \
    my_project \
    --stability beta

    View Slide

  11. 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/

    View Slide

  12. Craft is on GitHub.

    View Slide

  13. Craft is on GitHub.

    View Slide

  14. Live on the bleeding edge.
    > composer require \
    craftcms/cms:"dev-develop as 3.0.0-beta.99"

    View Slide

  15. 3. Multi-Site

    View Slide

  16. 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

    View Slide

  17. When should you use Multi-Site?
    ! "
    Multi-lingual sites Different orgs
    Sister sites No shared content
    Landing pages

    View Slide

  18. 4. Internationalization

    View Slide

  19. 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

    View Slide

  20. 5. Assets

    View Slide

  21. Image Editor

    View Slide

  22. Image Editor

    View Slide

  23. View Slide

  24. 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

    View Slide

  25. 6. Utilities

    View Slide

  26. 6. Utilities

    View Slide

  27. 6. Utilities

    View Slide

  28. 6. Utilities

    View Slide

  29. 6. Utilities

    View Slide

  30. 6. Utilities

    View Slide

  31. 6. Utilities

    View Slide

  32. 6. Utilities

    View Slide

  33. 6. Utilities

    View Slide

  34. 6. Utilities

    View Slide

  35. 7. Content Migrations

    View Slide

  36. Craft can now manage migrations that are specific to
    your project.
    > ./craft migrate/create create_new_field

    View Slide

  37. Content migrations are stored in
    a migrations/ folder within your
    Craft project.

    View Slide

  38. 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);
    }
    }

    View Slide

  39. Content migrations have access to the full set of Craft
    APIs, so you can do whatever you want in them.

    View Slide

  40. 8. Templating

    View Slide

  41. Element Queries

    View Slide

  42. ElementQuery is the new ElementCriteriaModel.

    View Slide

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

    View Slide

  44. 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.

    View Slide

  45. A few functions have changed.
    Old New
    find() all()
    first() one()
    order() orderBy()
    total() count()

    View Slide

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

    View Slide

  47. 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

    View Slide

  48. 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

    View Slide

  49. 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

    View Slide

  50. 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

    View Slide

  51. 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

    View Slide

  52. 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

    View Slide

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

    View Slide

  54. Example: get entry titles, indexed by their IDs
    {% set titlesById = craft.entries()
    .section('news')
    .select('elements.id, content.title')
    .pairs() %}

    View Slide

  55. Example: get the average value for a custom field
    {% set averageAge = craft.users()
    .andWhere('field_age is not null')
    .average('field_age') %}

    View Slide

  56. Example: load users in lazy-loaded batches
    {% for user in craft.users().each() %}
    {{ user.name }}
    {% endfor %}

    View Slide

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

    View Slide

  58. You can output the raw SQL query to be executed:
    {% set q = craft.entries().section('news') %}
    {{ q.getRawSql() }}
    Output:
    SELECT `elements`.`id`,
    `elements`.`fieldLayoutId`,
    `elements`.`uid`, ...

    View Slide

  59. cra!.app

    View Slide

  60. Templates can access Craft’s application instance
    anywhere with craft.app.

    View Slide

  61. Example: access a config value
    {% if craft.app.config.general.devMode %}
    Craft is running in Dev Mode!
    {% endif %}

    View Slide

  62. Example: loop through all the sections
    {% set sections = craft.app
    .sections.getAllSections() %}
    {% for section in sections %}
    {{ section.name }}
    {% endfor %}

    View Slide

  63. 9. Debug Toolbar

    View Slide

  64. View Slide

  65. View Slide

  66. View Slide

  67. View Slide

  68. View Slide

  69. View Slide

  70. View Slide

  71. View Slide

  72. View Slide

  73. View Slide

  74. View Slide

  75. 10. Configuration

    View Slide

  76. 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"

    View Slide

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

    View Slide

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

    View Slide

  79. 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',
    ],
    ],
    ];

    View Slide

  80. Volume settings can be overridden in
    config/volumes.php.
    return [
    'userPhotos' => [
    'path' => getenv('PHOTOS_PATH'),
    'url' => getenv('PHOTOS_URL'),
    ],
    ];

    View Slide

  81. All plugin settings can be overridden with config
    files now.

    View Slide

  82. You can set default Guzzle settings from
    config/guzzle.php.

    View Slide

  83. return [
    'headers' => ['Foo' => 'Bar'],
    'query' => ['testing' => '123'],
    'auth' => ['username', 'password'],
    'proxy' => 'tcp://localhost:80'
    ];

    View Slide

  84. You can override Craft’s core application configuration
    with config/app.php.

    View Slide

  85. 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);
    }
    ],
    ];

    View Slide

  86. 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

    View Slide