Skip to content

Commit

Permalink
Merge pull request #667 from craftcms/five-tutorial
Browse files Browse the repository at this point in the history
Getting Started: 5.x
  • Loading branch information
AugustMiller authored Oct 16, 2024
2 parents 700b130 + f0de52d commit 1cb3540
Show file tree
Hide file tree
Showing 66 changed files with 615 additions and 500 deletions.
4 changes: 4 additions & 0 deletions docs/.vuepress/components/Poi.vue
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ export default {
methods: {
activatePoi() {
this.isActive = true;
const $browser = document.getElementById(this.target);
$browser.scrollIntoView({ behavior: 'smooth' });
},
deactivatePoi() {
this.isActive = false;
Expand Down
4 changes: 2 additions & 2 deletions docs/.vuepress/theme/global-components/Badge.vue
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,15 @@ export default {
border-width: 1px;
border-color: var(--border-color);
color: var(--sidebar-link-color);
padding: 4px calc(5px - 0.1em) 4px 5px;
padding: 4px calc(4px - 0.1em) 4px 5px;
}
&.edition {
@apply uppercase bg-transparent text-xs tracking-widest leading-none h-auto text-center font-medium;
border-width: 1px;
border-color: var(--text-color);
color: var(--text-color);
padding: 0.3em 0.4em 0.1em;
padding: 0.35em 0.3em 0.2em 0.4em;
}
& + & {
Expand Down
1 change: 1 addition & 0 deletions docs/.vuepress/theme/global-components/BrowserShot.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<template>
<component
class="browser-shot"
:id="id"
:is="link ? 'a' : 'div'"
:href="link ? url : null"
:target="link ? '_blank' : null"
Expand Down
6 changes: 1 addition & 5 deletions docs/4.x/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,7 @@ While we [strongly recommend](#why-ddev) DDEV for new Craft projects, [alternate
ddev composer create -y --no-scripts "craftcms/craft:^4"
```

1. Run the Craft setup wizard, and accept all defaults (in `[square brackets]`):

```bash
ddev craft install
```
The setup wizard will start automatically! Accept all defaults (in `[square brackets]`), and note your chosen username and password.

::: tip
Our [First-Time Setup](kb:first-time-setup) guide in the Knowledge Base has more information about what to expect during setup.
Expand Down
8 changes: 2 additions & 6 deletions docs/5.x/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,10 @@ While we [strongly recommend](#why-ddev) DDEV for new Craft projects, [alternate
1. Scaffold the project from the official [starter project](https://github.com/craftcms/craft):

```bash
ddev composer create -y --no-scripts "craftcms/craft"
ddev composer create -y "craftcms/craft"
```

1. Run the Craft setup wizard, and accept all defaults (in `[square brackets]`):

```bash
ddev craft install
```
The setup wizard will start automatically! Accept all defaults (in `[square brackets]`), and note your chosen username and password.

::: tip
Our [First-Time Setup](kb:first-time-setup) guide in the Knowledge Base has more information about what to expect during setup.
Expand Down
10 changes: 6 additions & 4 deletions docs/commerce/5.x/development/cart.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ This is generally not necessary, and can have significant performance impacts on

To see what cart information you can use in your templates, take a look at the [Order](commerce5:craft\commerce\elements\Order) class reference. You can also refer to the example templates’ [`shop/cart/index.twig`](https://github.com/craftcms/commerce/blob/5.x/example-templates/dist/shop/cart/index.twig) file.

Once a cart is completed and turned into an order, accessing the current cart via either method starts this process over.
Once a cart is completed and becomes an order, accessing the current cart via either method starts this process over.

## Displaying Cart Contents

Expand Down Expand Up @@ -93,9 +93,9 @@ Craft includes a powerful [internationalization engine](guide:tutorial-i18n#plur

### Line Items

A cart’s contents are represented by _line items_. Line items are typically populated from [purchasables](../system/purchasables.md) when they are added to the cart, but [custom line items](#custom-line-items) can also be created on-the-fly. <Since product="commerce" ver="5.1.0" feature="Custom, ad-hoc line items" />
A cart’s contents are represented by _line items_. Line items are typically populated and refreshed from [purchasables](../system/purchasables.md) when they are added to the cart, but [custom line items](#custom-line-items) can also be created on-the-fly. <Since product="commerce" ver="5.1.0" feature="Custom, ad-hoc line items" />

Out-of-the-box, line items [variant](../system/products-variants.md), and have a quantity, description, notes, a calculated subtotal, options, adjustments (like tax and shipping costs), and other metadata. Most importantly, though, the line item retains a reference to its purchasable so that it can be refreshed with the latest information from your store while the customer is shopping.
Out-of-the-box, most line items represent a [variant](../system/products-variants.md), and have a quantity, description, notes, a calculated subtotal, options, adjustments (like tax and shipping costs), and other metadata. Most importantly, though, the line item retains a reference to its purchasable so that it can be refreshed with the latest information from your store while the customer is shopping. [Donations](../system/donations.md) are also added to the cart as line items.

::: tip
In the event a product or variant is altered or deleted after a customer checks out, enough information is memoized on each line item to reconstruct what was purchased, and how much was paid. Some of this is recorded directly on the line item (like [prices](#prices) and its [physical attributes](#physical-properties)), and some is stored as metadata (like [options](#line-item-options-and-notes) and [snapshots](../system/purchasables.md#snapshots)).
Expand All @@ -116,7 +116,9 @@ Line items are always returned as an array, even if there is only a single item
</ul>
```

You can get a line item’s source [purchasable](../system/purchasables.md) by calling `item.purchasable`. Let’s take a closer look at some other data available via line items.
You can get a line item’s source [purchasable](../system/purchasables.md) (most often a [variant](../system/products-variants.md#variants)) by calling `item.purchasable`, and the product a variant belongs to via `item.purchasable.product` or `item.purchasable.owner`.

Let’s take a closer look at some other data available via line items.

#### Prices

Expand Down
8 changes: 7 additions & 1 deletion docs/getting-started-tutorial/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ If you get stuck, [join us on Discord](https://craftcms.com/discord)! We all wan

Craft is a flexible, user-friendly <abbr title="Content management system">CMS</abbr> for creating custom digital experiences on the web—and beyond.

You have a _ton_ of options when it comes to choosing a CMS. Craft is uniquely equipped to deliver high-quality, content-driven experiences to your clients and their audiences, in large part due to its blank-slate approach to content modeling.
You have a _ton_ of options when it comes to choosing a CMS. Craft is uniquely equipped to deliver high-quality, content-driven experiences to your clients and their audiences, in large part due to its blank-slate approach to content modeling and front-end development.

To demonstrate Craft’s agility, we’ll build a basic blog—and in doing so, touch a number of powerful tools that let you design, build, and manage _any_ kind of content.

## Editions + Licensing

Craft’s <Badge type="edition" vertical="text-bottom">Solo</Badge> edition is free to use for personal projects. Everything we’ll cover in this tutorial is available in Solo, and you won’t be asked to sign up for accounts or add payment info. If you want to explore features of Craft’s <Badge type="edition" vertical="text-bottom">Team</Badge> or <Badge type="edition" vertical="text-bottom">Pro</Badge> editions, you are welcome to upgrade and test locally for as long as you like!

_Please note that installing any version of Craft binds you to our [Terms of Service](https://craftcms.com/terms-of-service) and [Acceptable Use Policy](https://craftcms.com/acceptable-use-policy)._
2 changes: 1 addition & 1 deletion docs/getting-started-tutorial/build/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Craft supports two fundamentally different approaches to building a front-end:
::: tip
Both methods give you complete access to your content. You are free to choose one of these approaches, combine aspects that suit your project, switch between them at a later date, deploy both for different audiences, or come up with your own hybrid architecture!

Craft doesn’t dictate anything about how you consume your content—in fact, it can be used as a back-end for a native application or kiosk, a bare API… or have no front-end at all, and exist solely as a warehouse for structured data.
Craft doesn’t dictate _anything_ about how you consume your content—in fact, it can be used as a back-end for a native application or kiosk, a bare API… or have no front-end at all, and exist solely as a warehouse for structured data.
:::

This tutorial will focus on a “monolithic” architecture, due to its lack of external dependencies—however, we will touch on the [GraphQL API](../more/graphql.md) in the _More_ section.
Expand Down
48 changes: 28 additions & 20 deletions docs/getting-started-tutorial/build/blog-templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Create `templates/blog/_entry.twig` and paste this code to it:
The first highlighted line connects our post template with the layout template, using the `{% extends %}` tag. The second highlight defines a `{% block ... %}`, the content of which will be output in the corresponding region of `_layout.twig`.

::: tip
When using layouts, all output must be within `block` tag pairs—but you may have as many `block` tags as you wish!
When extending a layout, all output must be within `block` tag pairs—but you may have as many `block` tags as you wish!
:::

Now that the blog section’s template is ready, you can visit the URL for a published post:
Expand Down Expand Up @@ -120,7 +120,7 @@ If you were to go back into the control panel and create some more posts, you co

#### Feature Image

Let’s output the image we attached via [the “Feature Image” asset field](../configure/resources.md#feature-image). That field had a handle of `featureImage`, so it will be available on the `entry` variable as `entry.featureImage`, just like the title was:
Let’s display the image we attached via [the “Feature Image” asset field](../configure/resources.md#feature-image). When we attached the assets field to the _Post_ field layout, we gave it a handle of `featureImage`so it will be available on the `entry` variable as `entry.featureImage`, just like its title was:

```twig{4,15-19}
{% extends '_layout' %}
Expand Down Expand Up @@ -171,6 +171,8 @@ If you would prefer to build the image element yourself, you can get the individ
height="{{ featureImage.height }}" />
```

Note the use of `featureImage.alt`! Craft automatically adds this attribute when building the tag itself—but it will be empty unless you add the **Alternative Text** field layout element to the volume’s field layout (and populate it with a description of the image).

</Block>

Refresh the page to see your changes:
Expand Down Expand Up @@ -241,9 +243,9 @@ If you pasted this into `templates/blog/_entry.twig` and the indentation got mes

Let’s output the [post content](../configure/resources.md#post-content) stored in our Matrix field. This process starts in a familiar way:

1. Load matrix blocks via the `postContent` field handle and store them in a variable;
1. Loop over those blocks with a `{% for %}` tag;
1. Render different content based on the blocks’ types, using an `{% if %}` tag;
1. Load the nested entries via the `postContent` field handle and store them in a variable;
1. Loop over those entries with a `{% for %}` tag;
1. Render different content based on the entries’ types, using an `{% if %}` tag;

After the line that declares our `topics` variable, add a new `set` tag:

Expand All @@ -254,7 +256,7 @@ After the line that declares our `topics` variable, add a new `set` tag:
{% set postContent = entry.postContent.all() %}
```

With the content loaded into a `postContent` variable, we can start outputting data for each block. Below the topics list, add a new `for` loop:
With the content loaded into a `postContent` variable, we can start outputting data for each block. Below the topics list and feature image, add a new `for` loop:

```twig{2,4,7,12,17,22}
<div class="post-content">
Expand Down Expand Up @@ -290,9 +292,9 @@ With the content loaded into a `postContent` variable, we can start outputting d

Looking at the highlighted lines in this block of code…

- Our `for` loop uses the `postContent` variable defined at the top of the template, and makes each block available in turn as `contentBlock`;
- We capture the “type” of block in a variable named `blockType` so we can compare against it later;
- The `if`, `elseif`, and `else` tags test the value of `blockType` each time through the loop and render different sections of the template;
- Our `for` loop uses the `postContent` variable defined at the top of the template, and makes each nested entry available in turn as `contentBlock`;
- We capture the “type” of entry in a variable named `blockType` so we can compare against it later;
- The `if`, `elseif`, and `else` tags test the value of `blockType` each time through the loop and render different parts of the template;
- “Image” blocks contain an asset field that can be used exactly the same way as the `featureImage` field is on the main entry;
- An `else` tag is used to provide some debugging information for us—but it will only show up if we’ve gotten our block type handles mixed up;
- A final `else` tag actually belongs to the main `for` loop, and allows us to output a message when there are no blocks to display;
Expand All @@ -305,11 +307,11 @@ How could we add a new _Quote_ block type?

Back in the control panel:

1. Visit **Settings** &rarr; **Fields** &rarr; **Post Content**;
1. Click **New Block Type**;
1. Name it _Quote_, and give it a handle of `quote`;
1. Add a **Plain Text** field named _Quote_ (also with a handle of `quote`), and mark it as **Required**;
1. Save the field;
1. Visit <Journey path="Settings, Fields, Post Content" />;
1. In the **Entry Types** selector, click **+ Create**;
1. Name the new entry type “Quote”, and give it a handle of `quote`;
1. Add our plain text field (_Text_) to its field layout, leaving the name and label as-is;
1. Save the entry type;

At this point, return to one of your blog entries’s edit screens, and add a **Quote** block to the **Post Content** matrix field. Reload that post’s page in the front-end, and you should see something like this:

Expand All @@ -321,9 +323,9 @@ In `templates/blog/_entry.twig`, add a new `elseif` comparison tag in the conten
{# ... #}
{% elseif blockType == 'quote' %}
<div class="content-block quote">
<blockquote>{{ contentBlock.quote | md }}</blockquote>
<blockquote>{{ contentBlock.text | md }}</blockquote>
</div>
{% else %} {# This `else` tag is what outputs our “unsupported” message! #}
{% else %} {# This `else` tag already exists, and is what outputs our “unsupported” message. #}
{# ... #}
```

Expand Down Expand Up @@ -378,19 +380,25 @@ Create a new template at `templates/blog/index.twig`, with the following content
{% endblock %}
```

In your browser, navigate to `https://tutorial.ddev.site/blog`, and verify you see all the posts you created via the control panel!

Notice that this template makes no reference to an `entry` variable. This is because it won’t be rendered based on an element’s URI format—Craft is just matching the request to `/blog` with a template.

That doesn’t mean we can’t access our content, though! The first highlighted line uses what’s called an _element query_. Element queries are different from the automatically-injected `entry` variable: instead of containing a _specific_ entry object, they define some _criteria_ for loading one or more entries from the database.
That doesn’t mean we can’t access our content, though! The first highlighted line uses what’s called an _element query_. Element queries are different from the automatically-injected `entry` variable: instead of containing a _specific_ entry object, they define some _parameters_ for loading one or more entries from the database.

Element queries are designed to be written and read in relatively plain language. Let’s break this one down:

1. `craft` is a global variable that collects a number of functions and features;
1. `.entries()` creates a new element query with specific functionality for fetching entries;
1. `.section()` configures the query to select only entries from the passed section(s);
1. `.section()` configures that query to select only entries from the passed section(s);
1. `.all()` executes the query and returns _all_ matching entries;

Most element queries will have steps 1 and 4 in common, but steps 2 and 3 are specific to our need to fetch _entries_ in a particular _section_. We’ll have a chance to use some more element query features in the next step!

::: tip
Craft sorts entries by their `postDate` (newest to oldest), by default.
:::

### Topic Pages

Now that our blog index displays a list of posts, let’s implement the topic index pages. Much of the display logic will remain consistent between them, so this template will look pretty familiar.
Expand Down Expand Up @@ -435,9 +443,9 @@ From the blog index, click through to one of your posts, then click the topic li

Like the blog index, we get a list of posts that each link out to their individual pages.

_Unlike_ the blog index, our topic template automatically has access to a `category` variable. This is because every topic page is backed by a category element, just like our individual post pages. It’s still up to us, though, to decide what other data should be displayed—and to fetch it with element queries.
_Unlike_ the blog index, our topic template automatically has access to a `category` variable. This is because every topic page is backed by a category element, just like our post entries. It’s still up to us, though, to decide what other data should be displayed—and to fetch it with element queries.

We’ve used the `category` variable in a new entry element query, near the top of the template:
We’ve used the `category` variable in a new entry query, near the top of the template:

```twig
{% set posts = craft.entries().section('blog').postCategories(category).all() %}
Expand Down
Loading

0 comments on commit 1cb3540

Please sign in to comment.