Average time (milliseconds)
taken to load the Happy Lager
homepage over 100 requests
Slide 5
Slide 5 text
Seconds taken to load 5,000
entries at once
Slide 6
Slide 6 text
Memory (MB) consumed when
loading 5,000 entries at once
Slide 7
Slide 7 text
2. Composer
Slide 8
Slide 8 text
Craft is now a Composer
dependency right alongside other
project dependencies.
Slide 9
Slide 9 text
Craft is now a Composer
dependency right alongside other
project dependencies.
> composer require \
craftcms/cms:^3.0.0-beta.1
Slide 10
Slide 10 text
There’s also a Composer project
you can use as a starting point.
> composer create-project \
craftcms/craft \
my_project \
--stability beta
Slide 11
Slide 11 text
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/
Slide 12
Slide 12 text
Craft is on GitHub.
Slide 13
Slide 13 text
Craft is on GitHub.
Slide 14
Slide 14 text
Live on the bleeding edge.
> composer require \
craftcms/cms:"dev-develop as 3.0.0-beta.99"
Slide 15
Slide 15 text
3. Multi-Site
Slide 16
Slide 16 text
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
Slide 17
Slide 17 text
When should you use Multi-Site?
! "
Multi-lingual sites Different orgs
Sister sites No shared content
Landing pages
Slide 18
Slide 18 text
4. Internationalization
Slide 19
Slide 19 text
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
Slide 20
Slide 20 text
5. Assets
Slide 21
Slide 21 text
Image Editor
Slide 22
Slide 22 text
Image Editor
Slide 23
Slide 23 text
No content
Slide 24
Slide 24 text
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
Slide 25
Slide 25 text
6. Utilities
Slide 26
Slide 26 text
6. Utilities
Slide 27
Slide 27 text
6. Utilities
Slide 28
Slide 28 text
6. Utilities
Slide 29
Slide 29 text
6. Utilities
Slide 30
Slide 30 text
6. Utilities
Slide 31
Slide 31 text
6. Utilities
Slide 32
Slide 32 text
6. Utilities
Slide 33
Slide 33 text
6. Utilities
Slide 34
Slide 34 text
6. Utilities
Slide 35
Slide 35 text
7. Content Migrations
Slide 36
Slide 36 text
Craft can now manage migrations that are specific to
your project.
> ./craft migrate/create create_new_field
Slide 37
Slide 37 text
Content migrations are stored in
a migrations/ folder within your
Craft project.
Slide 38
Slide 38 text
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);
}
}
Slide 39
Slide 39 text
Content migrations have access to the full set of Craft
APIs, so you can do whatever you want in them.
Slide 40
Slide 40 text
8. Templating
Slide 41
Slide 41 text
Element Queries
Slide 42
Slide 42 text
ElementQuery is the new ElementCriteriaModel.
Slide 43
Slide 43 text
ElementQuery is the new ElementCriteriaModel.
Still works the same, for the most part.
{% set entries = craft.entries()
.section('news')
.limit(10) %}
Slide 44
Slide 44 text
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.
Slide 45
Slide 45 text
A few functions have changed.
Old New
find() all()
first() one()
order() orderBy()
total() count()
Slide 46
Slide 46 text
Lots of new functions have been introduced.
Name Purpose
select(columns) override the SELECT
addSelect(columns) add more columns to the
SELECT
Slide 47
Slide 47 text
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
Slide 48
Slide 48 text
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
Slide 49
Slide 49 text
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
Slide 50
Slide 50 text
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
Slide 51
Slide 51 text
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
Slide 52
Slide 52 text
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
Slide 53
Slide 53 text
Example: get entries, indexed by their IDs
{% set entriesById = craft.entries()
.section('news')
.indexBy('elements.id')
.all() %}
Slide 54
Slide 54 text
Example: get entry titles, indexed by their IDs
{% set titlesById = craft.entries()
.section('news')
.select('elements.id, content.title')
.pairs() %}
Slide 55
Slide 55 text
Example: get the average value for a custom field
{% set averageAge = craft.users()
.andWhere('field_age is not null')
.average('field_age') %}
Slide 56
Slide 56 text
Example: load users in lazy-loaded batches
{% for user in craft.users().each() %}
{{ user.name }}
{% endfor %}
Slide 57
Slide 57 text
You can output the raw SQL query to be executed:
{% set q = craft.entries().section('news') %}
{{ q.getRawSql() }}
Slide 58
Slide 58 text
You can output the raw SQL query to be executed:
{% set q = craft.entries().section('news') %}
Templates can access Craft’s application instance
anywhere with craft.app.
Slide 61
Slide 61 text
Example: access a config value
{% if craft.app.config.general.devMode %}
Craft is running in Dev Mode!
{% endif %}
Slide 62
Slide 62 text
Example: loop through all the sections
{% set sections = craft.app
.sections.getAllSections() %}
{% for section in sections %}
{{ section.name }}
{% endfor %}
Slide 63
Slide 63 text
9. Debug Toolbar
Slide 64
Slide 64 text
No content
Slide 65
Slide 65 text
No content
Slide 66
Slide 66 text
No content
Slide 67
Slide 67 text
No content
Slide 68
Slide 68 text
No content
Slide 69
Slide 69 text
No content
Slide 70
Slide 70 text
No content
Slide 71
Slide 71 text
No content
Slide 72
Slide 72 text
No content
Slide 73
Slide 73 text
No content
Slide 74
Slide 74 text
No content
Slide 75
Slide 75 text
10. Configuration
Slide 76
Slide 76 text
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"