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/
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
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
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
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.
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
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
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
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
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
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
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`, ...
Example: loop through all the sections {% set sections = craft.app .sections.getAllSections() %} {% for section in sections %} {{ section.name }} {% endfor %}
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"