فهرست منبع

Getting started and advanced tutorials (#362)

Co-authored-by: Roxanna Coldiron <roxanna@coderedcorp.com>
Co-authored-by: Vince Salvino <salvino@coderedcorp.com>
Roxanna Coldiron 4 سال پیش
والد
کامیت
925f0e4b6b
100فایلهای تغییر یافته به همراه2736 افزوده شده و 91 حذف شده
  1. 338 0
      docs/advanced/advanced01.rst
  2. 419 0
      docs/advanced/advanced02.rst
  3. BIN
      docs/advanced/img/advanced_customcss1.png
  4. BIN
      docs/advanced/img/advanced_folder_structure1.png
  5. BIN
      docs/advanced/img/advanced_footer_front.png
  6. BIN
      docs/advanced/img/advanced_footer_overall_padding.png
  7. BIN
      docs/advanced/img/advanced_improved_website1.png
  8. BIN
      docs/advanced/img/advanced_two_tiered_navbar.png
  9. BIN
      docs/advanced/img/cupcake_landing_published.png
  10. BIN
      docs/advanced/img/cupcake_page_published.png
  11. 8 0
      docs/advanced/index.rst
  12. 22 2
      docs/features/page_types/form_pages.rst
  13. BIN
      docs/features/page_types/img/confirmation_email.png
  14. 18 6
      docs/getting_started/customize_design.rst
  15. 0 57
      docs/getting_started/customize_develop.rst
  16. BIN
      docs/getting_started/img/tutorial__form_edit.png
  17. BIN
      docs/getting_started/img/tutorial_basic_pagelist_published.png
  18. BIN
      docs/getting_started/img/tutorial_blank_article.png
  19. BIN
      docs/getting_started/img/tutorial_blog_admin_view.png
  20. BIN
      docs/getting_started/img/tutorial_blog_classifiers1.png
  21. BIN
      docs/getting_started/img/tutorial_blog_landing_edit1.png
  22. BIN
      docs/getting_started/img/tutorial_blog_landing_layout_tab.png
  23. BIN
      docs/getting_started/img/tutorial_blog_landing_published.png
  24. BIN
      docs/getting_started/img/tutorial_blog_post_edit.png
  25. BIN
      docs/getting_started/img/tutorial_blog_post_published.png
  26. BIN
      docs/getting_started/img/tutorial_contact_us_edit.png
  27. BIN
      docs/getting_started/img/tutorial_contact_us_published.png
  28. BIN
      docs/getting_started/img/tutorial_dark_navbar.png
  29. BIN
      docs/getting_started/img/tutorial_edit_classifiers.png
  30. BIN
      docs/getting_started/img/tutorial_edit_home1.png
  31. BIN
      docs/getting_started/img/tutorial_edit_home2.png
  32. BIN
      docs/getting_started/img/tutorial_example_classified_by.png
  33. BIN
      docs/getting_started/img/tutorial_footer_edit1.png
  34. BIN
      docs/getting_started/img/tutorial_footer_edit2.png
  35. BIN
      docs/getting_started/img/tutorial_footer_edit3.png
  36. BIN
      docs/getting_started/img/tutorial_footer_previews.png
  37. BIN
      docs/getting_started/img/tutorial_form_published.png
  38. BIN
      docs/getting_started/img/tutorial_front_home1.png
  39. BIN
      docs/getting_started/img/tutorial_front_home2.png
  40. BIN
      docs/getting_started/img/tutorial_home_child_edit1.png
  41. BIN
      docs/getting_started/img/tutorial_home_child_edit2.png
  42. BIN
      docs/getting_started/img/tutorial_imagelink_example.png
  43. BIN
      docs/getting_started/img/tutorial_images_editor.png
  44. BIN
      docs/getting_started/img/tutorial_images_upload_admin.png
  45. BIN
      docs/getting_started/img/tutorial_latest_pages_blank.png
  46. BIN
      docs/getting_started/img/tutorial_latestpages_classifiers_example.png
  47. BIN
      docs/getting_started/img/tutorial_logo.png
  48. BIN
      docs/getting_started/img/tutorial_logo_front.png
  49. BIN
      docs/getting_started/img/tutorial_navbar_add_item1.png
  50. BIN
      docs/getting_started/img/tutorial_navbar_front1.png
  51. BIN
      docs/getting_started/img/tutorial_new_classifier.png
  52. BIN
      docs/getting_started/img/tutorial_new_form_page.png
  53. BIN
      docs/getting_started/img/tutorial_new_nav_edit1.png
  54. BIN
      docs/getting_started/img/tutorial_page_seo_options.png
  55. BIN
      docs/getting_started/img/tutorial_password_protect_edit1.png
  56. BIN
      docs/getting_started/img/tutorial_password_protect_options.png
  57. BIN
      docs/getting_started/img/tutorial_settings_seo_global.png
  58. BIN
      docs/getting_started/img/tutorial_sitename.png
  59. BIN
      docs/getting_started/img/tutorial_web_page_edit.png
  60. BIN
      docs/getting_started/img/tutorial_web_page_published.png
  61. 8 3
      docs/getting_started/index.rst
  62. 30 0
      docs/getting_started/install.rst
  63. 11 8
      docs/getting_started/tutorial01.rst
  64. 8 8
      docs/getting_started/tutorial02.rst
  65. 135 5
      docs/getting_started/tutorial03.rst
  66. 162 0
      docs/getting_started/tutorial04.rst
  67. 29 0
      docs/getting_started/tutorial05.rst
  68. 105 0
      docs/getting_started/tutorial06.rst
  69. 104 0
      docs/getting_started/tutorial07.rst
  70. 55 0
      docs/getting_started/tutorial08.rst
  71. 70 0
      docs/getting_started/tutorial09.rst
  72. 43 0
      docs/getting_started/tutorial10.rst
  73. 24 0
      docs/how_to/translation.rst
  74. 2 0
      docs/index.rst
  75. 0 0
      docs/reference/django_settings.rst
  76. 7 0
      docs/reference/index.rst
  77. 1 1
      docs/releases/v0.15.0.rst
  78. 1 1
      docs/releases/v0.16.0.rst
  79. 9 0
      tutorial/mysite/.gitattributes
  80. 399 0
      tutorial/mysite/.gitignore
  81. 38 0
      tutorial/mysite/README.md
  82. 10 0
      tutorial/mysite/manage.py
  83. 0 0
      tutorial/mysite/mysite/__init__.py
  84. 0 0
      tutorial/mysite/mysite/settings/__init__.py
  85. 205 0
      tutorial/mysite/mysite/settings/base.py
  86. 18 0
      tutorial/mysite/mysite/settings/dev.py
  87. 79 0
      tutorial/mysite/mysite/settings/prod.py
  88. 37 0
      tutorial/mysite/mysite/urls.py
  89. 16 0
      tutorial/mysite/mysite/wsgi.py
  90. 10 0
      tutorial/mysite/requirements.txt
  91. 0 0
      tutorial/mysite/website/__init__.py
  92. 5 0
      tutorial/mysite/website/apps.py
  93. 32 0
      tutorial/mysite/website/migrations/0001_initial.py
  94. 55 0
      tutorial/mysite/website/migrations/0002_initial_data.py
  95. 28 0
      tutorial/mysite/website/migrations/0003_auto_20200909_1259.py
  96. 18 0
      tutorial/mysite/website/migrations/0004_auto_20200909_1428.py
  97. 0 0
      tutorial/mysite/website/migrations/__init__.py
  98. 151 0
      tutorial/mysite/website/models.py
  99. 26 0
      tutorial/mysite/website/static/website/css/custom.css
  100. 0 0
      tutorial/mysite/website/static/website/js/custom.js

+ 338 - 0
docs/advanced/advanced01.rst

@@ -0,0 +1,338 @@
+Customizing HTML/CSS in Templates
+==================================
+
+Overview
+---------
+CodeRed CMS is an extension of Wagtail CMS. You can further customize your site by overriding the
+built-in templates to suit your needs. For this tutorial, we will assume that you have basic knowledge
+of the Django templating system. You can read more about it by visiting
+`Django template language <https://docs.djangoproject.com/en/stable/ref/templates/language/>`_.
+
+The templating language uses a series of ``{%  %}`` to pull in content from your page models (found in
+the ``models.py`` file) and add minimal logic to the page. This allows it to render the page after content
+is added in the CMS and allows you to create multiple pages with the same layout. At the top of the page,
+you also want to make sure to either specify that you are **extending a page template** and that you are
+pulling in Wagtail tags to make your template work the way it should.
+
+.. note::
+    If you are completely overriding a template, you will not use the ``{% extends "path/to/template" %}``
+    at the top of your template. You do, however, need to make sure to use the appropriate template
+    tags at the top of the template or your template will not render.
+
+The templates directory inside your ``website`` app is empty by default. Any templates you put
+in here will override the default coderedcms templates if they follow the same name and directory
+structure. This uses the standard Django template rendering engine. For example, to change the
+formatting of the article page, copy ``coderedcms/templates/coderedcms/pages/article_page.html``
+to ``website/templates/coderedcms/pages/article_page.html`` and modify it.
+The `source code for built-in templates can be found on GitHub
+<https://github.com/coderedcorp/coderedcms/blob/dev/coderedcms/templates/coderedcms/>`_.
+
+
+Example 1: Navbar Customization
+-------------------------------
+
+The built-in template for the navbar can be found in ``templates/coderedcms/snippets/navbar.html``. This
+file may not actually be in your installation folders for your site; however, you can see its contents
+by visiting the CodeRed CMS source code here: `navbar.html <https://github.com/coderedcorp/coderedcms/blob/dev/coderedcms/templates/coderedcms/snippets/navbar.html>`_.
+
+Let’s say that you want to have a 2-tiered navbar with the logo on the top tier and the menu items on the
+second tier. The default navbar does not have that as an option, so you will want to override this template.
+
+Look at your folder structure for your project. In the ``website`` folder, you should see another folder
+called ``templates``. In there are two folders as well: ``website`` and ``coderedcms``. The ``coderedcms`` template
+folder is likely empty at this point because the CMS is pulling in the default templates from source, but you can
+add templates to the ``coderedcms`` folder **if you are overriding the default templates**.
+
+Most of your custom templates will go into your ``website`` folder because they are not overriding the
+default templates in the CMS but either extending them or creating completely new ones specific to
+your site.
+
+.. note::
+    Adding templates to the ``coderedcms`` templates folder does not change the default templates
+    throughout all of CodeRed CMS but does override those specific templates for your website app.
+
+Your ``website`` folder currently only has a folder for ``coderedcms`` in the ``templates`` folder.
+You can add a new ``website`` folder in ``templates`` (because we will use it in another tutorial),
+but for now, you will want to add a ``snippets`` folder inside the ``templates\coderedcms`` folder
+so that your folder structure looks something like this:
+
+.. figure:: img/advanced_folder_structure1.png
+    :alt: Our folder structure for templates.
+
+    Our folder structure for templates within our website app.
+
+The folder structure needs to be the same as the default folder structure in the CMS if you want to
+override the navbar template. Now you should have ``templates\coderedcms\snippets``. Navigate to
+the ``snippets`` folder and create a ``navbar.html`` file inside of that folder.
+
+**You are now ready to begin customizing the navbar template!**
+
+1. Examine the default template for the navbar. What code will we want to use from it? You can use
+   what’s there in your customization.
+
+2. We will need the Wagtail tags at the top, so copy those and paste them into
+   your ``navbar.html`` file.
+
+.. code-block:: Django
+
+    {% load wagtailcore_tags wagtailsettings_tags wagtailimages_tags coderedcms_tags i18n %}
+
+3. Next, we need to figure out how to move the logo (aka the ``navbar-brand``) into its own section for
+   the navbar. Maybe we could essentially create two navbars, one that just has the logo and one that has
+   the menu. Hmm, let’s try that!
+
+4. We want to preserve the basic functionality of the navbar, so we should keep the tags for CMS settings
+   and the overall layout inside of a container.
+
+5. The 2-tiered navbar will have two navbars on top of each other but one will only have the
+   ``navbar-brand`` (logo) while the other will allow for adding menu items via the CMS. So, the top
+   navbar is not going to have access to CSS settings in the CMS that are reserved for the main navbar –-
+   which means that you will need to add any custom classes to the top navbar, such as the background
+   color or where you want the logo to be placed. Keep that in mind.
+
+   .. code-block:: Django
+
+      {% load wagtailcore_tags wagtailsettings_tags wagtailimages_tags coderedcms_tags i18n %}
+
+
+      {% if not settings.coderedcms.LayoutSettings.navbar_wrapper_fluid %}
+      <div class="container">
+      {% endif %}
+      <nav class="navbar navbar-header bg-warning">
+
+      {% if not settings.coderedcms.LayoutSettings.navbar_content_fluid %}
+      <div class="container">
+      {% endif %}
+         <div>
+         <a class="navbar-brand" href="/">
+               {% if settings.coderedcms.LayoutSettings.logo %}
+               {% image settings.coderedcms.LayoutSettings.logo original as logo %}
+               <img class="img-fluid" src="{{logo.url}}" alt="{{site.site_name}}" />
+               {% else %}
+               {{site.site_name}}
+               {% endif %}
+         </a>
+         </div>
+      {% if not settings.coderedcms.LayoutSettings.navbar_content_fluid %}
+      </div><!-- /.container -->
+      {% endif %}
+
+      </nav>
+
+   We have set the foundation for the top navbar, which will be the banner section for the logo. Instead of
+   ``<nav class="navbar {% get_navbar_css %}">``, we have added our own Bootstrap classes since this part of the
+   navbar will not be getting its CSS settings from the CMS.
+
+   However, we did keep the ``{% if settings.coderedcms.LayoutSettings.logo %} {% endif %}`` block because we want
+   to show the name of the site **if no logo is uploaded in the CMS**.
+
+6. Now we can include the code block for the normal navbar beneath it. Place this code below the ``</nav>`` in
+   your template. We want to preserve majority of the navbar as-is (without the block for ``navbar-brand``) so that
+   when we add menu items in the CMS, those items will show up as navigation links.
+
+   .. code-block:: Django
+
+      <!--Put this below the previous nav closing tag -->
+
+      <nav class="navbar {% get_navbar_css %}">
+
+      {% if not settings.coderedcms.LayoutSettings.navbar_content_fluid %}
+      <div class="container">
+      {% endif %}
+         <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar" aria-controls="navbar" aria-expanded="false" aria-label="Toggle navigation">
+               <span class="navbar-toggler-icon"></span>
+         </button>
+
+         <div class="collapse navbar-collapse" id="navbar">
+         {% get_navbars as navbars %}
+         {% for navbar in navbars %}
+         <ul class="navbar-nav {{navbar.custom_css_class}}"
+               {% if navbar.custom_id %}id="{{navbar.custom_id}}"{% endif %} >
+               {% for item in navbar.menu_items %}
+                  {% include_block item with liclass="nav-item" aclass="nav-link" ga_event_category="Navbar" %}
+               {% endfor %}
+         </ul>
+         {% endfor %}
+         {% if settings.coderedcms.LayoutSettings.navbar_search %}
+         <form class="ml-auto form-inline" action="{% url 'codered_search' %}" method="GET">
+               {% load bootstrap4 %}
+               {% get_searchform request as form %}
+               {% bootstrap_form form layout='inline' %}
+               <div class="form-group">
+                  <button class="btn btn-outline-primary ml-2" type="submit">{% trans 'Search' %}</button>
+               </div>
+         </form>
+         {% endif %}
+
+         </div>
+
+      {% if not settings.coderedcms.LayoutSettings.navbar_content_fluid %}
+      </div><!-- /.container -->
+      {% endif %}
+
+      </nav>
+
+      {% if not settings.coderedcms.LayoutSettings.navbar_wrapper_fluid %}
+      </div><!-- /.container -->
+      {% endif %}
+
+      {# Navbar offset #}
+      {% if settings.coderedcms.LayoutSettings.navbar_fixed %}
+         {% if settings.coderedcms.LayoutSettings.logo %}
+         <div class="{{settings.coderedcms.LayoutSettings.navbar_format}}-fixed-img-offset {{settings.coderedcms.LayoutSettings.navbar_collapse_mode}}"></div>
+         {% else %}
+         <div class="{{settings.coderedcms.LayoutSettings.navbar_format}}-fixed-offset {{settings.coderedcms.LayoutSettings.navbar_collapse_mode}}"></div>
+         {% endif %}
+      {% endif %}
+
+   Let's talk about what is happening here. So, we pulled in the code for the navbar a second time, with the removal of
+   ``navbar-brand`` section from the original template, but preserved majority of the default code for this section.
+   The ``if`` statements refer to whether or not some settings are chosen in the CMS and tells the template what to do in those
+   cases. We also needed to close to top-level ``container``.
+
+   Another section that we kept was for the ``navbar-toggler``, which sets the hamburger menu when the screen sizes change.
+   Finally, we also kept the ``{% get_navbar_css %}`` tag in the class for the ``nav`` because we can use CSS classes for this
+   navbar from the CMS.
+
+.. note::
+    To add classes in the CMS, look for the line **Custom CSS Class**, which can be found as a field in sections of
+    the admin for a snippet or page, or in the **Advanced** section of a Layout Block. This is where you would put a class
+    like ``bg-warning`` from Bootstrap or a class that you created yourself, like ``logo-banner``.
+
+Adding Custom CSS to the Navbar
+'''''''''''''''''''''''''''''''
+
+If you noticed, we have a few custom classes that are not found in Bootstrap. To style our navbar with these classes,
+we need to include them in our CSS file and set the styles the way we want. Once you've done that and saved your work,
+your navbar is ready to show the world!
+
+CSS files will be found in **website > static > css** in your project folder. Unless you are using SASS, you
+will be editing the ``custom.css`` file. For those using SASS, you will want to create a ``navbar.scss`` file in your ``src``
+folder and add a link to it in your ``custom.scss`` file.
+
+.. note::
+    If you want to learn how to use SASS, we really like this tutorial:
+    `SASS Guide <https://sass-lang.com/guide>`_.
+
+This is the CSS that we used for our navbar:
+
+.. code-block:: CSS
+
+    .navbar .nav-link {
+        font-family: 16px;
+        text-transform: uppercase;
+    }
+
+As you can see, you may not need to use a lot of custom CSS. Sometimes a Bootstrap class will work perfectly.
+Sometimes all you need to do is customize your template HTML and then add Bootstrap classes as needed. It all
+depends on your use case.
+
+For our custom navbar, we needed to un-check the "fixed navbar" option in the CMS via **Settings > Layout** in
+order for it to work. Check out what our 2-tiered navbar looks like:
+
+.. figure:: img/advanced_two_tiered_navbar.png
+    :alt: Our 2-tiered navbar.
+
+    Our custom 2-tiered navbar on our website.
+
+
+Example 2: Footer Customization
+-------------------------------
+
+Our footer does not need a customized HTML template; however, we think it does need some custom CSS to make it
+look the way we want. Some of our CSS can easily be done in the CMS -- without even touching our CSS file!
+
+First, go to the Footer Snippet in the **Snippets > Footers** admin in CMS. We had previously added a Bootstrap
+class of ``bg-warning`` to the Attributes section in the Main Footer, but now we want to add CSS classes to each
+of the Layout Blocks for the footer as well.
+
+1. All of our footer menu items brush up against the top of the footer block. We can add some padding to
+   the footer using `Bootstrap spacing utilities <https://getbootstrap.com/docs/4.0/utilities/spacing/>`_.
+
+2. Let's add the padding class ``pt-5`` (which means "padding-top spacer 5") in the Attributes section of
+   the Main Footer. Save and check it out.
+
+   .. figure:: img/advanced_footer_overall_padding.png
+      :alt: We added padding to the Attributes section of footer.
+
+      Our footer with pt-5 added as a class in Attributes section.
+
+3. We want to change the way that the links look, but it doesn't seem as if there is a Bootstrap class for that.
+   That means that it's time to go into our CSS file.
+
+4. We want our links to be that cherry-red, so we will need to use custom CSS and include it in our CSS file.
+   But we also don't want to make ALL of our links this color. That means we should create a class that can be used
+   to specify the link. For example, we could add a class called ``cherry-links`` and target the ``a`` tag.
+
+   .. code:: CSS
+
+      .cherry-links a {
+      color: #f75990;
+      }
+
+   Then we place the ``cherry-links`` class in the **Advanced** section of the Layout Block that contains the text
+   for the links, like this:
+
+   .. figure:: img/advanced_customcss1.png
+      :alt: Adding a custom class to the Layout Block
+
+      Our custom class added to the Layout Block in CMS
+
+   We add it to every Layout Block that needs it. In this case, we have three blocks with links.
+
+   .. figure:: img/advanced_footer_front.png
+      :alt: Our footer right now
+
+      Our footer with the custom classes
+
+.. note::
+    We changed the ``pt-5`` class to ``py-5`` to add padding to the top and bottom. Sometimes you will need to try and
+    see which classes will give you the results that you want.
+
+What else could we do to make the footer look better? Take some time to play around with Bootstrap classes in the
+CMS or create some of your own classes to target elements in the footer.
+
+Making More Drastic CSS Changes Sitewide
+----------------------------------------
+
+**What we did:** So, we went back and changed some of our classes in the HTML template and in the CMS to reflect some
+new classes that we created, such as ``bg-lightyellow`` and ``bg-cherry``.
+
+We've also added some additional padding classes in places where we thought it would look good.
+
+Finally, we decided that our logo needed an update as well. So, we swapped our original logo for one
+that fit our new color scheme.
+
+This is what our website looks like now with all of our customizations and updates:
+
+.. figure:: img/advanced_improved_website1.png
+    :alt: Our customized website so far
+
+    Our updated and customized website so far
+
+And this is our CSS file at the moment:
+
+.. code:: CSS
+
+    /*Navbar */
+    .navbar .nav-link {
+        font-family: 16px;
+        text-transform: uppercase;
+    }
+
+    /* Custom CSS classes */
+    .cherry-links a {
+        color: #f75990;
+    }
+
+    .bg-lightyellow {
+        background-color: #fff685;
+    }
+
+    .bg-cherry {
+        background-color: #f75990;
+    }
+
+With the combination of using Bootstrap classes directly in the CMS and making our own classes, which we can use in the CMS
+and in custom templates, we can quickly update our site with our changes. There's more that we want to do, but now
+we have a good start on a beautiful, customized website!

+ 419 - 0
docs/advanced/advanced02.rst

@@ -0,0 +1,419 @@
+Custom Page Types
+=================
+
+In many cases, the built-in page types will be exactly what you need. There are, however,
+several reasons why you may need a custom page type. This tutorial will show you an example
+for creating a custom page type.
+
+Let's say that we need to make a special product page for all of our cupcakes. While our real bakery
+may have over 100 different types, we will limit this example to a small handful but enough to show
+how this works.
+
+Before we begin, you should have a general understanding of `Django models <https://docs.djangoproject.com/en/stable/topics/db/models/>`_
+and some Python skills. You can still follow along for an introduction to these concepts even without this knowledge.
+
+We are also going to be unable to cover every potential use case or scenario in this tutorial, but we hope that it will springboard
+any ideas that you have for your own website.
+
+Prep work for custom pages
+--------------------------
+
+We need to plan our page ahead of time. What fields will our custom page need, and what will we need our page
+to do? Take the time to write down the answer to these questions before you even touch the code. This is what
+we are writing down for Simple Sweet Dessert's custom cupcake page:
+
+**Our Prep Notes**
+
+1. We want our page to page to list the attributes and descriptions of individual cupcakes.
+
+2. We want to be able to display the cupcakes in cards automatically on a landing page.
+
+
+**Cupcake Page Fields:**
+
+* Name of cupcake (This could be the title of the page)
+
+* Photo of cupcake
+
+* Description of cupcake
+
+* Days when these cupcakes are made
+
+**Cupcake Landing Page Fields:**
+
+* Needs to be the parent page for the cupcake pages
+
+Setting up the page models
+--------------------------
+
+Just like in Django or Wagtail, you will need to set up your page models in the ``models.py`` file of your
+project. Navigate to ``mysite\website\models.py`` in your code editor and open up the ``models.py`` file.
+You should already see a few page models in there from CodeRed CMS, as well as imports at the top from the
+frameworks that we are using.
+
+.. code-block:: python
+
+    """
+    Creatable pages used in CodeRed CMS.
+    """
+    from modelcluster.fields import ParentalKey
+    from coderedcms.forms import CoderedFormField
+    from coderedcms.models import (
+        CoderedArticlePage,
+        CoderedArticleIndexPage,
+        CoderedEmail,
+        CoderedFormPage,
+        CoderedWebPage
+    )
+
+
+    class ArticlePage(CoderedArticlePage):
+        """
+        Article, suitable for news or blog content.
+        """
+        class Meta:
+            verbose_name = 'Article'
+            ordering = ['-first_published_at']
+
+        # Only allow this page to be created beneath an ArticleIndexPage.
+        parent_page_types = ['website.ArticleIndexPage']
+
+        template = 'coderedcms/pages/article_page.html'
+        amp_template = 'coderedcms/pages/article_page.amp.html'
+        search_template = 'coderedcms/pages/article_page.search.html'
+
+
+    class ArticleIndexPage(CoderedArticleIndexPage):
+        """
+        Shows a list of article sub-pages.
+        """
+        class Meta:
+            verbose_name = 'Article Landing Page'
+
+        # Override to specify custom index ordering choice/default.
+        index_query_pagemodel = 'website.ArticlePage'
+
+        # Only allow ArticlePages beneath this page.
+        subpage_types = ['website.ArticlePage']
+
+        template = 'coderedcms/pages/article_index_page.html'
+
+
+    class FormPage(CoderedFormPage):
+        """
+        A page with an html <form>.
+        """
+        class Meta:
+            verbose_name = 'Form'
+
+        template = 'coderedcms/pages/form_page.html'
+
+
+    class FormPageField(CoderedFormField):
+        """
+        A field that links to a FormPage.
+        """
+        class Meta:
+            ordering = ['sort_order']
+
+        page = ParentalKey('FormPage', related_name='form_fields')
+
+
+    class FormConfirmEmail(CoderedEmail):
+        """
+        Sends a confirmation email after submitting a FormPage.
+        """
+        page = ParentalKey('FormPage', related_name='confirmation_emails')
+
+
+    class WebPage(CoderedWebPage):
+        """
+        General use page with featureful streamfield and SEO attributes.
+        Template renders all Navbar and Footer snippets in existence.
+        """
+        class Meta:
+            verbose_name = 'Web Page'
+
+        template = 'coderedcms/pages/web_page.html'
+
+
+Before we begin adding our fields for our new page models, we should add the page class, meta class,
+and template information for our pages.
+
+* We our extending the ``CoderedWebPage`` model which is why it is wrapped in parentheses after we name our page model.
+
+* We are indicating that Cupcake pages are sub-pages of the Cupcake Landing Page.
+
+* We are specifying the template files that the page models should use, which should also be created in our ``templates\website\pages`` folder.
+
+Add this code below the other page models:
+
+.. code:: python
+
+    class CupcakesIndexPage(CoderedWebPage):
+        """
+        Landing page for Cupcakes
+        """
+        class Meta:
+            verbose_name = "Cupcakes Landing Page"
+
+        # Override to specify custom index ordering choice/default.
+        index_query_pagemodel = 'website.CupcakesPage'
+
+        # Only allow CupcakesPages beneath this page.
+        subpage_types = ['website.CupcakesPage']
+
+        template = 'website/pages/cupcakes_index_page.html'
+
+
+    class CupcakesPage(CoderedWebPage):
+        """
+        Custom page for individual cupcakes
+        """
+
+        class Meta:
+            verbose_name = "Cupcakes Page"
+
+        # Only allow this page to be created beneath an CupcakesIndexPage.
+        parent_page_types = ['website.CupcakesIndexPage']
+
+        template = "website/pages/cupcakes_page.html"
+
+
+At the top of each ``.html`` template page, we want to add these tags so that we have a basic functioning
+template prepared:
+
+.. code:: Django
+
+    {% extends "coderedcms/pages/web_page.html" %}
+    {% load wagtailcore_tags wagtailimages_tags coderedcms_tags %}
+
+
+Now we can turn our attention back to our page models, specifically the CupcakesPage.
+Since the name of the cupcake could just be the title of the page, we don't need to add a custom field
+for that information. We do, however, need a few fields.
+
+.. code:: python
+
+    # At top of the file, under the CodeRed CMS import, add these imports
+    from django.db import models
+    from wagtail.admin.edit_handlers import FieldPanel
+    from wagtail.core.fields import RichTextField
+    from wagtail.images import get_image_model_string
+    from wagtail.images.edit_handlers import ImageChooserPanel
+
+
+    class CupcakesPage(CoderedWebPage):
+        """
+        Custom page for individual cupcakes
+        """
+
+        class Meta:
+            verbose_name = "Cupcakes Page"
+
+        # Only allow this page to be created beneath an CupcakesIndexPage.
+        parent_page_types = ['website.CupcakesIndexPage']
+
+        template = "website/pages/cupcakes_page.html"
+
+        # Cupcakes Page model fields
+        description = RichTextField(
+            verbose_name="Cupcake Description",
+            null=True,
+            blank=True,
+            default=""
+        )
+        photo = models.ForeignKey(
+            get_image_model_string(),
+            null=True,
+            blank=True,
+            on_delete=models.SET_NULL,
+            related_name='+',
+            verbose_name='Cupcake Photo',
+        )
+        DAYS_CHOICES = (
+            ("Weekends Only", "Weekends Only"),
+            ("Monday-Friday", "Monday-Friday"),
+            ("Tuesday/Thursday", "Tuesday/Thursday"),
+            ("Seasonal", "Seasonal"),
+        )
+        days_available = models.CharField(
+            choices = DAYS_CHOICES,
+            max_length=20,
+            default=""
+        )
+
+        # Add custom fields to the body
+        body_content_panels = CoderedWebPage.body_content_panels + [
+            FieldPanel("description"),
+            ImageChooserPanel("photo"),
+            FieldPanel("days_available"),
+        ]
+
+
+**What's happening?**
+
+Okay, we had to add some imports at the top to be able to use these field types in our model.
+If we try to makemigrations/migrate without having these imported, it will show an error.
+
+Next, we added the fields we need with the field types that tell it how to function. Our description
+will be a RichTextField which is essentially a text box that allows formatting. Then our photo needs to be
+able to be associated with the page as well as be uploaded via an ImageChooserPanel -- the popup we get when
+we want to add a photo in the CMS.
+
+Finally, we added a field for choosing which days the cupcake is available and we made this a dropdown choice
+panel. We had to set the choices first, then include the choices in our field selector.
+
+At the bottom of our model, we are telling it to allow for the standard CMS page builder blocks as well as our custom
+fields.
+
+Now we can run ``python manage.py makemigrations website`` and ``python manage.py migrate`` to test our work.
+It should migrate successfully. (If not, read what the error says and fix it. A typo can cause huge problems!)
+
+Run the server again with ``python manage.py runserver`` to see how it looks in your CMS admin.
+
+You should now see Cupcake Landing Page as a child page choice under Home page. Choose this, add a title and
+publish it. The page does not have a template made; however, it uses the basic CodeRed Web Page so it will display
+something.
+
+Now you can add Cupcake Pages, which are sub-pages of the Cupcake Landing Page. While the fields for this page
+do not currently show up on the published page, you can add content in the editor mode.
+
+.. note::
+    We have to create a custom page template to display the custom fields on the published page.
+
+
+Building our custom page templates
+----------------------------------
+
+Since our models are working and we can add content to the fields, we can begin creating our custom page
+template. Navigate to the ``cupcakes_page.html`` file in your project's templates folder. We added the basic
+page tags at the top of the page earlier. In case you need to add them, they are:
+
+.. code::
+
+    {% extends "coderedcms/pages/web_page.html" %}
+    {% load wagtailcore_tags wagtailimages_tags coderedcms_tags %}
+
+Now we want to tell the page to not display the page's title where the cover image would be if there is no cover
+image (because we plan to use the page's title aka the cupcake name elsewhere on the page).
+
+The standard CodeRed Web Page template has an ``{% if %} {% else %}`` statement regarding cover images that says to show the page title when a cover image
+is not available. We will add that same code to our page but remove the ``else`` statement so that it does nothing when a cover image is not available.
+
+We will also set up the basic layout for our page: a two half-sized columns in a row. To pull in our field data,
+we reference the page and then the field, like this ``{{page.title}}`` or ``{{page.description}}``.
+
+For the image, we specify what size it should be and give it a shorter reference name for the variable.
+
+We added a few Bootstrap classes and custom classes to change the padding a little and some text colors, as well
+as add a border around the image that is centered within the column.
+
+**Our template code:**
+
+.. code:: Django
+
+    {% extends "coderedcms/pages/web_page.html" %}
+    {% load wagtailcore_tags wagtailimages_tags coderedcms_tags %}
+
+    {% block content_pre_body %}
+        {% if self.cover_image %}
+        {% image page.cover_image fill-2000x1000 as cover_image %}
+        <div class="jumbotron jumotron-fluid" style="height:400px;background-image:url({{cover_image.url}});background-repeat:no-repeat; background-size:cover; background-position:center center;">
+        </div>
+        {% endif %}
+    {% endblock %}
+
+
+    {% block content_body %}
+    <div class="block-row">
+        <div class="container-fluid">
+            <div class="row m-4">
+                <div class="col-lg-6">
+                    {% if page.photo %}
+                    {% image page.photo fill-300x300 as cupcake %}
+                    <div class="text-center">
+                        <img class="border-cherry" src="{{cupcake.url}}" alt="photo of {{page.title}}">
+                    </div>
+                    {% endif %}
+                </div>
+                <div class="col-lg-6">
+                    <div class="py-lg-5">
+                        <h2>{{page.title}}</h2>
+                        <lead class="text-cherry">{{page.days_available}}</lead>
+                        {% if page.description %}
+                        <p>{{page.description|richtext}}</p>
+                        {% endif %}
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    {% endblock %}
+
+
+We added some content for a cupcake page in the CMS and published it.
+
+Let's take a look.
+
+.. figure:: img/cupcake_page_published.png
+    :alt: Our customized cupcake page so far
+
+    Our customized cupcake page so far
+
+
+It works! Continue to add cupcake pages until you have a decent amount of them --
+five or so would be good.
+
+Building the Cupcake Landing Page
+---------------------------------
+
+While we could simply use the the default "Show Child Pages" option for the page, a list of links
+is rather boring. We also want the page to automatically update whenever we add a new cupcake to save us lots of time
+and trouble. How can we dynamically update our Cupcake Landing Page?
+
+.. code:: Django
+
+    {% extends "coderedcms/pages/web_page.html" %}
+    {% load wagtailcore_tags wagtailimages_tags coderedcms_tags %}
+
+    {% block index_content %}
+    <div class="container">
+        <div class="row d-flex">
+            {% for cupcake in page.get_children.specific %}
+            <div class="col m-3">
+                <div class="card border-cherry" style="width: 18rem;">
+                    {% if cupcake.photo %}
+                    {% image cupcake.photo fill-300x300 as cupcake_photo %}
+                    <a href="{{cupcake.url}}">
+                        <img class="card-img-top w-100" src="{{cupcake_photo.url}}" alt="{{cupcake.title}}">
+                    </a>
+                    {% endif %}
+                    <div class="card-body">
+                    <div class="card-text">
+                        <h3><a class="text-cherry" href="{{cupcake.url}}">{{cupcake.title}}</a></h3>
+                        <p class="lead">{{cupcake.days_available}}</p>
+                    </div>
+                    </div>
+                </div>
+            </div>
+            {% endfor %}
+        </div>
+    </div>
+    {% endblock %}
+
+
+**What's happening?**
+
+We are using a ``{% block index_content %}`` and a ``{% for cupcake in page.get_children.specific %}`` loop that pulls
+in content from the child/sub-pages. Our new variable for the sub-pages is ``cupcake``, so we reference the fields like so:
+``{{cupcake.title}}``. In the CMS we want to make show that "Show Child Pages" is NOT selected because it will just show
+the list of page links in addition to our custom cards. This is what our published landing page looks like now:
+
+.. figure:: img/cupcake_landing_published.png
+    :alt: Our customized landing cupcake page so far
+
+    Our customized cupcake landing page dynamically pulling in child pages as cards
+
+
+Now we can keep customizing our templates until we get the design that we want.

BIN
docs/advanced/img/advanced_customcss1.png


BIN
docs/advanced/img/advanced_folder_structure1.png


BIN
docs/advanced/img/advanced_footer_front.png


BIN
docs/advanced/img/advanced_footer_overall_padding.png


BIN
docs/advanced/img/advanced_improved_website1.png


BIN
docs/advanced/img/advanced_two_tiered_navbar.png


BIN
docs/advanced/img/cupcake_landing_published.png


BIN
docs/advanced/img/cupcake_page_published.png


+ 8 - 0
docs/advanced/index.rst

@@ -0,0 +1,8 @@
+Advanced Tutorial
+=================
+
+.. toctree::
+    :maxdepth: 1
+
+    advanced01
+    advanced02

+ 22 - 2
docs/features/page_types/form_pages.rst

@@ -30,9 +30,29 @@ Content Tab
 * **Reply-to Address**: The reply-to address you want the email to contain.
 * **Subject**: The subject you want the email to use.
 
-**Confirmation Emails**
+.. _confirmation-emails:
+
+Confirmation Emails
+-------------------
+
+Click the "Add Confirmation Emails" button to add additional emails you want to send out when a form is submitted.
+
+You can reference your form fields in the Confirmation Email's fields using Django bracket notation. For example, for the
+**To Addresses:** you could reference your form field Email by using ``{{email}}``. 
+
+The Django variable tags are generated automatically from the form fields that you create and are in lowercase letters, with any spaces indicated by an underscore.
+If you had a form field with the label "Number of Cupcakes," the Django tag would be ``number_of_cupcakes`` which you would place in
+curly brackets when referencing it in the Confirmation Email fields.
+
+In the **Body** of the email, you can use HTML to design it as you like. Reference the form fields with Django tags to personalize it. See an example below:
+
+.. figure:: img/confirmation_email.png
+    :alt: Our confirmation email setup
+
+    Our confirmation email is referencing the form fields that we created on a Custom Cupcake Order page. Review the full page
+    to identify the references.
+
 
-Click the "Add Confirmation Emails" button to add additional emails you want to sent out when a form is submitted.
 
 Settings Tab
 ~~~~~~~~~~~~

BIN
docs/features/page_types/img/confirmation_email.png


+ 18 - 6
docs/getting_started/customize_design.rst

@@ -10,6 +10,8 @@ This is shown by default in the navbar, and also added to the title attribute of
 This can be changed in Settings > Sites > localhost. Hostname and port only need to be changed
 when running in  production.
 
+:ref:`site-name`
+
 Site settings
 -------------
 
@@ -23,31 +25,41 @@ Logo & icon
 The logo that appears in the navbar, the wagtail admin, and your favicon can be set in
 Settings > Layout. Here you can also change navbar settings (based on Bootstrap CSS framework).
 
+:ref:`logo`
+
 Menu / navigation bars
 ----------------------
 
 Navbars are top navigation elements that create a "main menu" experience. Navbars are managed
 as snippets. They render from top down based on the order they were created in.
 
+:ref:`navbar-global`
+
+:ref:`navbar`
+
 Footers
 -------
 
 Similar to Navbars, footers are also managed as snippets and also render top down based on
 the order they were created in.
 
+:ref:`footer`
+
 Custom CSS
 ----------
 
-A django app called ``website`` has been created to hold your custom changes. In website/static/
+A Django app called ``website`` has been created to hold your custom changes. In website/static/
 there are custom.css and custom.js files that get loaded on every page by default. Adding
 anything to these files will automatically populate on the site and override any default styles.
 By default, Bootstrap 4 and jQuery are already included on the site.
 
+.. note::
+    You can also use Bootstrap color and utility classes in the **Custom CSS** fields on your pages in CMS.
+    Sometimes you may need more customization than Bootstrap classes can provide, in which case you can
+    create your own custom classes in your CSS files and use them in your templates and in the CMS.
+
 Custom HTML templates
 ---------------------
 
-The templates directory inside the ``website`` app is empty by default. Any templates you put
-in here will override the default coderedcms templates if they follow the same name and directory
-structure. This uses the standard Django template rendering engine. For example, to change the
-formatting of the article page, copy ``coderedcms/templates/coderedcms/pages/article_page.html``
-to ``website/templates/coderedcms/pages/article_page.html`` and modify it.
+To learn how to create custom HTML templates, see the advanced tutorial:
+:doc:`/advanced/advanced01`.

+ 0 - 57
docs/getting_started/customize_develop.rst

@@ -1,57 +0,0 @@
-Developing your website
-=======================
-
-
-Page models
--------------
-
-The django app ``website`` has been created with default models based on pre-built abstract
-CodeRed CMS models. You can use these as-is, override existing fields and function, and add
-custom fields to these models. After making a change to any of these models, be sure to run
-``python manage.py makemigrations website`` and ``python manage.py migrate`` to apply the
-database changes.
-
-
-Hooks
------
-
-Building on the concept of wagtail hooks, there are some additional hooks in CodeRed CMS
-
-is_request_cacheable
-^^^^^^^^^^^^^^^^^^^^
-
-This hook is provided by `wagtail-cache <https://github.com/coderedcorp/wagtail-cache>`_.
-The callable passed into this hook should take a ``request`` argument, and return a ``bool``
-indicating whether or not the response to this request should be cached (served from the cache
-if it is already cached). Not returning, or returning anything other than a bool will not
-affect the caching decision. For example::
-
-    from wagtail.core import hooks
-
-    @hooks.register('is_request_cacheable')
-    def nocache_in_query(request, curr_cache_decision):
-        # if the querystring contains a "nocache" key, return False to forcibly not cache.
-        # otherwise, do not return to let the CMS decide how to cache.
-        if 'nocache' in request.GET:
-            return False
-
-
-Default Language
-----------------
-
-To adjust the default language of a project, navigate to Project_Name/Project_Name/settings/base.py. Change both the
-LANGUAGE_CODE setting and the LANGUAGES setting. For example::
-
-        LANGUAGE_CODE = 'es'
-
-        LANGUAGES = [
-            ('es', _('Spanish'))
-        ]
-
-Note that these settings are both in use to communicate to the users' browser about the default language of the project.
-This ensures that users requiring assistive technology have a smooth experience using the site. These settings do not,
-on their own, translate or enable multiple languages on the project.
-
-`For a full list of language codes, see this list from W3 Docs. <https://www.w3docs.com/learn-html/html-language-codes.html>`_
-
-

BIN
docs/getting_started/img/tutorial__form_edit.png


BIN
docs/getting_started/img/tutorial_basic_pagelist_published.png


BIN
docs/getting_started/img/tutorial_blank_article.png


BIN
docs/getting_started/img/tutorial_blog_admin_view.png


BIN
docs/getting_started/img/tutorial_blog_classifiers1.png


BIN
docs/getting_started/img/tutorial_blog_landing_edit1.png


BIN
docs/getting_started/img/tutorial_blog_landing_layout_tab.png


BIN
docs/getting_started/img/tutorial_blog_landing_published.png


BIN
docs/getting_started/img/tutorial_blog_post_edit.png


BIN
docs/getting_started/img/tutorial_blog_post_published.png


BIN
docs/getting_started/img/tutorial_contact_us_edit.png


BIN
docs/getting_started/img/tutorial_contact_us_published.png


BIN
docs/getting_started/img/tutorial_dark_navbar.png


BIN
docs/getting_started/img/tutorial_edit_classifiers.png


BIN
docs/getting_started/img/tutorial_edit_home1.png


BIN
docs/getting_started/img/tutorial_edit_home2.png


BIN
docs/getting_started/img/tutorial_example_classified_by.png


BIN
docs/getting_started/img/tutorial_footer_edit1.png


BIN
docs/getting_started/img/tutorial_footer_edit2.png


BIN
docs/getting_started/img/tutorial_footer_edit3.png


BIN
docs/getting_started/img/tutorial_footer_previews.png


BIN
docs/getting_started/img/tutorial_form_published.png


BIN
docs/getting_started/img/tutorial_front_home1.png


BIN
docs/getting_started/img/tutorial_front_home2.png


BIN
docs/getting_started/img/tutorial_home_child_edit1.png


BIN
docs/getting_started/img/tutorial_home_child_edit2.png


BIN
docs/getting_started/img/tutorial_imagelink_example.png


BIN
docs/getting_started/img/tutorial_images_editor.png


BIN
docs/getting_started/img/tutorial_images_upload_admin.png


BIN
docs/getting_started/img/tutorial_latest_pages_blank.png


BIN
docs/getting_started/img/tutorial_latestpages_classifiers_example.png


BIN
docs/getting_started/img/tutorial_logo.png


BIN
docs/getting_started/img/tutorial_logo_front.png


BIN
docs/getting_started/img/tutorial_navbar_add_item1.png


BIN
docs/getting_started/img/tutorial_navbar_front1.png


BIN
docs/getting_started/img/tutorial_new_classifier.png


BIN
docs/getting_started/img/tutorial_new_form_page.png


BIN
docs/getting_started/img/tutorial_new_nav_edit1.png


BIN
docs/getting_started/img/tutorial_page_seo_options.png


BIN
docs/getting_started/img/tutorial_password_protect_edit1.png


BIN
docs/getting_started/img/tutorial_password_protect_options.png


BIN
docs/getting_started/img/tutorial_settings_seo_global.png


BIN
docs/getting_started/img/tutorial_sitename.png


BIN
docs/getting_started/img/tutorial_web_page_edit.png


BIN
docs/getting_started/img/tutorial_web_page_published.png


+ 8 - 3
docs/getting_started/index.rst

@@ -5,9 +5,14 @@ Getting Started
     :maxdepth: 1
 
     install
+    customize_design
     tutorial01
     tutorial02
     tutorial03
-    customize_design
-    customize_develop
-    django_settings
+    tutorial04
+    tutorial05
+    tutorial06
+    tutorial07
+    tutorial08
+    tutorial09
+    tutorial10

+ 30 - 0
docs/getting_started/install.rst

@@ -5,6 +5,36 @@ Installation
 Basic Installation
 ------------------
 
+#. Make a directory (folder) for your project.
+#. Create a virtual environment. 
+    **Not sure how to create a virtual environment?**
+    Creating a virtual environment for your project only involves a few commands.
+    See below:
+
+    **Windows (PowerShell):**
+
+    .. code-block:: ps1con
+
+        PS> python -m venv .\venv\
+        PS> .\venv\Scripts\Activate.ps1
+
+    **macOS, Linux:**
+
+    .. code-block:: console
+
+        $ python -m venv ./venv/
+        $ source ./venv/bin/activate
+
+    You can name your virtual environment anything you like. It is just for your use
+    on your computer. 
+
+    Learn more about virtual environments by visiting the `Python documentation on virtual
+    environments here <https://docs.python.org/3/tutorial/venv.html>`_.
+
+    .. note::
+        You will need to be in the directory (folder) of your CodeRed CMS project and have your
+        virtual environment activated to install dependencies and run your site.
+
 #. Run ``pip install coderedcms``
 #. Run ``coderedcms start mysite --sitename "My Company Inc." --domain www.example.com``
 

+ 11 - 8
docs/getting_started/tutorial01.rst

@@ -1,5 +1,5 @@
-Your First CodeRed Website: Part 1
-==================================
+Tutorial Part 1: Site Name, Logo, and Basics
+============================================
 
 After :doc:`install`, you are greeted with a bare-bones website.
 Let's start filling things out.
@@ -13,13 +13,14 @@ Logging in
 Navigate to http://localhost:8000/admin/ and log in with the username
 and password you created with the ``python manage.py createsuperuser`` command.
 
-After logging in, you will be taken to the admin dashboard, also known as the "Wagtail Admin".
+After logging in, you will be taken to the admin dashboard - also known as the "Wagtail Admin".
 
 .. figure:: img/tutorial_admin.png
     :alt: The admin dashboard.
 
     The admin dashboard.
 
+.. _site-name:
 
 Changing your site name
 -----------------------
@@ -34,7 +35,7 @@ To change the name, go to **Settings > Sites**, and click on the site that is th
     is for use with multi-sites. For example, if you have a parent company that operates many separate
     brand websites within one CMS, then ``WAGTAIL_SITE_NAME`` would be the name of the parent company.
 
-For my website, I'm going to change **Settings > Sites > Site name** to "Contoso Building Solutions".
+For my website, I'm going to change **Settings > Sites > Site name** to "Simple Sweet Desserts".
 
 .. figure:: img/tutorial_sitename.png
     :alt: Changing the site name.
@@ -43,11 +44,12 @@ For my website, I'm going to change **Settings > Sites > Site name** to "Contoso
 
 And edit ``mysite/settings/base.py`` by changing ``WAGTAIL_SITE_NAME`` as so::
 
-    WAGTAIL_SITE_NAME = 'Contoso Ltd.'
+    WAGTAIL_SITE_NAME = 'Simple Sweet Desserts Ltd.'
 
-Now the admin dashboard and login page show "Contoso Ltd.", and the Home page at http://localhost:8000/
-will show "Contoso Building Solutions".
+Now the admin dashboard and login page show "Simple Sweet Desserts Ltd.", and the Home page at http://localhost:8000/
+will show "Simple Sweet Desserts".
 
+.. _logo:
 
 Adding your logo
 ----------------
@@ -80,6 +82,7 @@ logo and favicon show up everywhere on your site.
 
     The logo on our website.
 
+.. _navbar-global:
 
 Changing navbar and global site colors
 --------------------------------------
@@ -107,5 +110,5 @@ setting, click "Save", and view your site. Pick one that looks best to you. If y
 doing a lot of heavy CSS customization, you might want to stick with the default to ensure
 compatibility with the Bootstrap documentation.
 
-For my website, I'm going to change the navbar color scheme back to "Light", CSS class to ``bg-light``,
+For our website, we are going to change the navbar color scheme back to "Light", CSS class to ``bg-light``,
 and leave the theme variant at the default.

+ 8 - 8
docs/getting_started/tutorial02.rst

@@ -1,5 +1,5 @@
-Your First CodeRed Website: Part 2
-==================================
+Tutorial Part 2: Adding Content
+===============================
 
 Now let's start adding some content to our site.
 
@@ -8,7 +8,7 @@ Adding a hero unit to the home page
 -----------------------------------
 
 In the admin dashboard, select **Pages >**. This will open a tree-style view of all the pages
-on our site. For now, the only page is Home Page. Click end pencil icon to edit the page, or click
+on our site. For now, the only page is Home Page. Click the pencil icon to edit the page, or click
 "Home Page" and then the "Edit" button.
 
 Here in the body section is where we can add our content. Each component in this section is called
@@ -19,11 +19,11 @@ on the visitor's screen size.
 First, let's make a big flashy hero unit. A hero unit in CodeRed CMS is a block that allows for
 a full-width background image or background color, and has lots of padding by default.
 
-Select the **Hero Unit** block. Next set a background image or color - I'm going to download and use
-`this image <https://unsplash.com/photos/jwhqbR3clzQ>`_ from `Unsplash <https://unsplash.com>`_.
+Select the **Hero Unit** block. Next set a background image or color - we are going to download and use
+`this image <https://pixabay.com/photos/cupcake-bakery-dessert-sweet-4457880/>`_ from `Pixabay <https://pixabay.com>`_.
 
 Now to add content to our hero unit, under the Content field select **Responsive Grid Row** and then
-a **Column**. Inside my column I'll add **Text** and format it.
+a **Column**. Inside our column, we will add **Text** and format it.
 
 Next, click the small "+" icon directly below the text field. This will let you add another block
 directly below the text, but still in the same column.
@@ -51,7 +51,7 @@ Great success!
 Adding cards to the home page
 -----------------------------
 
-Next, let's say my company offers three different services, and I'd like to add three
+Next, let's say our company offers three different baked goods, and we would like to add three
 uniformly-sized cards on the home page representing that. Go back to the tab with the home page
 editor. All the way at the bottom of the page, click the "+" icon directly below the "Hero Unit" block.
 This will add a new block directly below the hero unit.
@@ -61,7 +61,7 @@ Select the **Card Grid** block. The select **Card** to add the first card. Now f
 
 Next add and fill out two more cards by clicking the "+" icon directly below our current card block.
 
-My editing page now looks like this (ignore the misplaced side menu, that is just a result of the screenshot):
+The editing page now looks like this (ignore the misplaced side menu, that is just a result of the screenshot):
 
 .. figure:: img/tutorial_edit_home2.png
     :alt: The home page editor after adding a card grid with three cards.

+ 135 - 5
docs/getting_started/tutorial03.rst

@@ -1,8 +1,138 @@
-Your First CodeRed Website: Part 3
-==================================
+Tutorial Part 3: Navbar & Footer
+================================
 
-Coming soon: navigation and footer customization.
+Let's begin to work on our navigation and footer setup.
 
-Coming soon: using custom page types to build a blog.
+.. _navbar:
 
-Coming soon: customizing the CSS and HTML templates.
+Customizing the navigation
+--------------------------
+
+The general layout of your navbar can be found in the **Settings > Layout**
+section of the Wagtail Admin. We previously discussed choosing a dark or
+light navbar and adding Bootstrap classes, but you can also add/remove the
+Search bar, set it to fixed (stays at the top even when you scroll) or full-width,
+decide on which screen size it will collapse into a menu hamburger, and whether to
+center the logo at the top or keep it toward the left-hand side.
+
+.. note::
+    In Layout, we added the Bootstrap background color class ``bg-warning`` but you can choose whatever
+    you like for your site. We also decided to remove the Search Bar from the Navbar by de-selecting the
+    option to show the Search Bar. It's recommended to review all of the available settings, and go ahead
+    and play around with them!
+
+Create your menus
+-----------------
+
+Your navbar will have links to your other pages or external content that you want
+to share. To build your menu, go to **Snippets > Navigation Bars**.
+
+In the top right-hand corner is a button that says **Add Navigation Bar**.
+Click on this button to start! (Alternatively, you can also click on the link that says "Why not add one?")
+
+.. figure:: img/tutorial_new_nav_edit1.png
+    :alt: The edit screen for adding a navbar.
+
+    The edit screen for adding a new navbar
+
+Name your navbar. In this case, this will be our main navigation bar so we have simply named it
+Main Nav.
+
+There are three types of links that you can add to your navbar. Let's briefly describe each one:
+
+* **Page link with sub-links** - Add links to pages from within your website. Add sub-links for dropdown items.
+
+* **External link with sub-links** - Add external links from other websites to your site, as well as sub-links.
+
+* **Document link with sub-links** - Add document links with sub-links to your navbar.
+
+We don't have any other pages set up yet, but we can still create our menu. For now, we will just link to
+the Home page and update it once we have more pages.
+
+.. figure:: img/tutorial_navbar_add_item1.png
+    :alt: Adding a menu item with page link.
+
+    The edit screen with our first navbar item.
+
+Continue to add as many navbar items as you want for your website. You can always edit your menu and add more
+top-level items or dropdowns as you make more pages. We are going to start with our three most important ones
+for our sweets shop!
+
+.. figure:: img/tutorial_navbar_front1.png
+    :alt: Our menu added to the navbar - front view.
+
+    The website with our menu added. Also note that we are using some Bootstrap colors on the site.
+
+.. _footer:
+
+Customizing the Footer
+----------------------
+
+Now, let's head down to work on the footer, which is another menu of links. You can add more links in the footer
+that maybe won't belong in the main navigation but are still important. Go to **Snippets > Footers** to begin
+working on the footer. In the top right-hand corner is a button that says **Add Footer**. Click on this button to start!
+(Alternatively, you can also click on the link that says "Why not add one?")
+
+Give your footer a name. We choose Main Footer since this will be the main footer for our site.
+
+Let's get some practice with Responsive Grid Rows and Columns! We want to make a 4-column footer with our logo in the
+first column, our sub-page links in the second column, our main page links in the third column, and contact
+information in the fourth column. Don't worry - This is actually going to be easy!
+
+.. note::
+    To keep up with our color scheme, we have also added a Bootstrap background color class to the
+    Attributes section. See `Bootstrap color utilities <https://getbootstrap.com/docs/4.3/utilities/colors/#background-color>`_.
+
+.. figure:: img/tutorial_footer_edit1.png
+    :alt: Getting started on our footer.
+
+    The edit screen as we prepare to begin adding the layout for the footer.
+
+To set up our 4-column footer, choose **Responsive Grid Row** from the layout choices at the bottom. Now click on
+**Add Column**. You can specify the column size in the dropdown that says **Column size**. Since we want to have
+four evenly sized columns, we are going to choose a 1/4 Column size.
+
+.. note::
+    Bootstrap uses a 12-column grid, and our footer is going to span the entire 12 columns. To figure out
+    how to size our columns, we do some math. We are slicing up the 12-column grid into fourths to have four columns,
+    so our columns need to be 1/4 each. Read more about Bootstrap grids and columns here: `Bootstrap Grid <https://getbootstrap.com/docs/4.0/layout/grid/>`_.
+
+From within the Responsive Grid Row block, keep selecting the + sign below your **Column** until you have all of
+the columns that you need. Then remember to make sure to choose the size of the column if you have a particular
+layout in mind. Otherwise, it will automatically size on its own.
+
+.. figure:: img/tutorial_footer_edit2.png
+    :alt: Our Responsive Grid Row and Columns set up.
+
+    The edit screen as we set up our layout for the footer.
+
+Add Content to the Footer
+-------------------------
+
+Now that we have our layout, let's begin adding content! You see that there are several different choices for content
+available within the column block.
+
+1. We're going to choose the **Image Link** block in the first column so that we can add
+our logo and link to the Home page.
+
+    .. figure:: img/tutorial_imagelink_example.png
+        :alt: Our logo added as an image, the Home page linked, and Alt Text added.
+
+        The edit screen for the Image Link block in our first column.
+
+2. In the second through fourth columns, we are going to choose the Text block and list the Pages that we want to
+link to and our contact information. You can add links in the text block by highlighting the text and selecting the chain-link icon,
+then choosing which page or external link you want. See our example below:
+
+    .. figure:: img/tutorial_footer_edit3.png
+        :alt: Our footer with our text blocks and page links added.
+
+        The edit screen for our footer with our content added.
+
+3. Once you're happy with your Footer, hit **Save**. Let's see what it looks like!
+
+    .. figure:: img/tutorial_footer_previews.png
+        :alt: What our footer looks like on the website.
+
+        What our footer looks like on the website.
+        Remember, we have done minimal styling on the site.

+ 162 - 0
docs/getting_started/tutorial04.rst

@@ -0,0 +1,162 @@
+Tutorial Part 4: Creating a Blog
+================================
+
+We want to add a blog to our site, so let's get some practice with Article Pages!
+Then we will get some practice building a basic web page as well.
+
+Adding articles to the site
+---------------------------
+
+Okay, Articles will be child pages (also known as sub-pages) for the **Article Landing Page**. This
+is important to remember because sub-pages can be accessed by the parent page (also known as the
+landing page).
+
+.. note::
+    Before we can add any Articles, we have to create the Article Landing Page.
+
+Click on **Pages > Home** to get to the screen that will allow you to create child pages under the Home page.
+It looks like this:
+
+.. figure:: img/tutorial_home_child_edit1.png
+    :alt: Screen for adding pages under the Home page.
+
+    The admin screen for adding pages under the Home page.
+
+Click on the button that says **Add Child Page**. Because we are still using the built-in page types, you should
+only see three types of pages available for now:
+
+* **Article Landing Page** - The landing page for articles, blog posts, etc.
+
+* **Form** - A page type for building forms.
+
+* **Web Page** - A basic page type for building any type of web page.
+
+.. figure:: img/tutorial_home_child_edit2.png
+    :alt: Screen for Home page sub-page types.
+
+    The admin screen for choosing sub-page types under the Home page.
+
+Select the **Article Landing Page** to begin. For now, we will keep this particular page simple.
+Just give it a title of Blog. Add a cover image if you would like one. Now **Publish** it. We will
+come back to it later on in this tutorial.
+
+Go back to the admin screen for adding pages under the Home page. You should now see the Article Landing
+Page listed that we named Blog. Hover over it to reveal more options for Blog, and you should see the options
+to add child pages to the Blog page. We want to add a few posts, so select **Add Child Page**. This will
+take you to the Article page type for editing!
+
+.. figure:: img/tutorial_blank_article.png
+    :alt: A fresh article page in edit mode.
+
+    The edit screen for a fresh article page.
+
+The anatomy of an Article Page
+------------------------------
+
+The Article Page has several built-in fields to make it easy to publish an article, or blog as in our
+case. We will want to fill in the following:
+
+* **Title** - Title of the article or blog
+
+* **Cover Image** - Not required but can add interest to your page
+
+* **Caption** - The sub-title for the article or blog
+
+* **Publication Info** - Here we add the author, the display name for the author if different, and the Publication date
+
+* **Body** - Content for our article or blog
+
+Let's write a short blog about the story of our cupcakes. Once we fill in the information we want to add above, we
+can select what we want to add to the body of the blog post. We will choose a **Text** block.
+
+After we add our Content in the Text block, we can add other types of content if we like. How about a button?
+Select the + sign under the Text block, then choose **Button Link**. Continue to add different content blocks
+as you see fit for the blog post.
+
+.. figure:: img/tutorial_blog_post_edit.png
+    :alt: The edit screen for our first blog post.
+
+    The edit screen for our first blog post.
+
+Now publish it and see what it looks like! This is what our blog post looks like:
+
+.. figure:: img/tutorial_blog_post_published.png
+    :alt: Our first published blog post.
+
+    Our first published blog post.
+
+Add a few more blog posts to get some practice, then we will return to our Blog landing page.
+
+Completing our Blog landing page
+--------------------------------
+
+On the admin page, we can select to edit the main Blog page. Click the **Edit** button that is under the
+word **Blog**. Alternatively, you can find the Blog page in the Home page admin view or by clicking on Pages.
+
+.. figure:: img/tutorial_blog_admin_view.png
+    :alt: Admin view to edit our pages.
+
+    The admin view to edit our blog posts and our Blog landing page.
+
+Just like on the other pages, we can add a cover image and build the layout. Let's do that! We will use
+Responsive Grid Row and just one full-width column for an introduction. Then we will show you the different
+ways to display your sub-pages on the landing page.
+
+.. figure:: img/tutorial_blog_landing_edit1.png
+    :alt: The edit screen showing our intro on Blog page
+
+    The edit screen showing the introduction on our Blog landing page.
+
+Publish and see what happens!
+
+.. figure:: img/tutorial_blog_landing_published.png
+    :alt: Our published Blog page
+
+    The published Blog landing page.
+
+Whoa! The blog posts are already showing up! What is this magic? Well, remember that this is a parent page type
+and the blog posts were children of this page. The option to "show children" is already pre-selected in the edit mode
+for the landing pages. We should go take a look at that now.
+
+Ways to display sub-pages on a landing page
+-------------------------------------------
+
+Go back into the editor for the Blog landing page. You should see the following tabs at the top:
+
+* **Content**
+
+* **Classify**
+
+* **Layout**
+
+* **SEO**
+
+* **Settings**
+
+We want the **Layout** tab. Click on that tab and you'll see something like this:
+
+.. figure:: img/tutorial_blog_landing_layout_tab.png
+    :alt: The Layout tab for the Blog landing page
+
+    The Layout tab for the Blog landing page.
+
+We are using the default template, so skip over that for now. The sections titled
+**"Show Child Pages"** and **"Child Page Display"** contain the settings for whether or not
+the sub-pages (blogs in this case) are automatically pulled onto the page, how many
+of them to show, and what fields or pieces of them to show as a preview.
+
+.. note::
+    The "Show Child Pages" setting in Layout is the simplest and easiest way to display
+    your sub-pages on a landing page.
+
+But we said that there are other ways to do this! Well, yes, there are. De-select "Show Child Pages"
+in Layout so that we can try the other way of displaying your sub-pages. Then go back to the Content area.
+
+You can add more content below the Text block with our introduction, or make a new column for content, or start
+a new Responsive Grid Row to add a column with content.
+
+What we want to look at is the **Latest Pages** block. The Latest Pages block is extra powerful because you can access
+the sub-pages of **any landing page on the site**! You can look at it for now, but we are going to just use the "Show Child Pages"
+in Layout after all. We will go into more depth about this block and other content blocks in the future.
+
+Remember to re-select "Show Child Pages" in Layout before publishing it.

+ 29 - 0
docs/getting_started/tutorial05.rst

@@ -0,0 +1,29 @@
+Tutorial Part 5: Web Page
+=========================
+
+Another page type that you will use to build your site in the CMS is the **Web Page**.
+The Web Page is a general-purpose page type which contains a big dynamic
+StreamField enabling the editor to add grids, cards, and all kinds of content to
+the page dynamically without requiring code. Let's use a Web Page to make a page
+about our Mini Cupcakes.
+
+Go back to the admin where you can add a child page to the Home page. This time, choose
+Web Page. Building the page involves using the Layout blocks that we discussed earlier. Play
+around with the layout in the Content tab, adding different types of content. This is what we
+decided to do for our Mini Cupcakes page:
+
+.. figure:: img/tutorial_web_page_edit.png
+    :alt: Editing our web page layout.
+
+    The edit screen for our web page - You can design your layout how you like.
+
+Let's publish this page and see what it looks like:
+
+.. figure:: img/tutorial_web_page_published.png
+    :alt: Our published web page.
+
+    Our published web page.
+
+Wow! Our site is really coming together! We should finishing adding some of our other pages, like
+Cupcakes, Mini Cookies, and About Us. Take the time to make the rest of these pages and then add the
+updated page links in the Navigation Menu and in the Footer.

+ 105 - 0
docs/getting_started/tutorial06.rst

@@ -0,0 +1,105 @@
+Tutorial Part 6: Create Categories with Classifiers
+===================================================
+
+Now we actually want to go back to our blog posts and organize them. We can do
+that by adding **Classifiers** to our pages so that we can access them via their
+category.
+
+What are Classifiers?
+---------------------
+
+Classifiers are essentially categories that you give to an item. For our sweets shop,
+classifiers that we might use could be something like:
+
+* **Flavors:** Strawberry, Vanilla, Chocolate, etc.
+
+* **Types of baked goods:** Cupcakes, Cookies, Muffins, Cinnamon Rolls, etc.
+
+* **Types of content:** News, Press, Interviews, Recipes, etc.
+
+Adding Classifiers in the CMS
+-----------------------------
+
+You can start adding Classifiers by going to **Snippets > Classifiers**. Select that you want to add a new
+Classifier, and you would do this for each Classifier that you want to add.
+
+For the purposes of this tutorial, we are going to add a Content Types classifier and a Baked Goods
+classifier.
+
+.. figure:: img/tutorial_new_classifier.png
+    :alt: Screen for adding a new Classifier.
+
+    The admin screen for adding a new Classifier.
+
+The first Classifier we are adding is the Baked Good ones. For Name, we would put Baked Goods because this is the
+generalized heading for the category. Then we would click the **Add Classifier Terms** button to begin adding the
+sub-categories below that main term.
+
+.. figure:: img/tutorial_edit_classifiers.png
+    :alt: The Classifiers that we added.
+
+    The edit screen for the Classifiers that we added.
+
+However, we realize that you could decide that you want to add Classifiers in the middle of building your pages.
+If you have not already added Classifiers in Snippets, you can click the Classify tab in the page editor and
+select that you want to create Classifiers. It will take you to the Snippets editor for Classifiers to do so.
+
+Selecting Classifiers for your pages
+------------------------------------
+
+Okay, now we have some Classifiers to work with. Let's head back to our blog posts and start categorizing them.
+The Classify tab in our blog posts now show the Classifiers! Take a look at ours:
+
+.. figure:: img/tutorial_blog_classifiers1.png
+    :alt: The Classifiers are visible in blog pages now.
+
+    The edit screen for the Classifiers that we can choose from in a blog post.
+
+You can choose as many Classifiers as you think make sense. For our blog on The Story Behind Our Cupcakes, we
+are going to choose Cupcakes (beneath Baked Goods) and News (beneath Content Type).
+
+Using Classifiers across the site
+---------------------------------
+
+One of the places where you might use the Classifiers is in a **Latest Pages** content block. For practice and
+to see this in action, let's add a Latest Pages to our Home page. Make sure to add Classifiers to each of your
+blog posts first.
+
+.. figure:: img/tutorial_latest_pages_blank.png
+    :alt: The Latest Pages content block.
+
+    The Latest Pages content block.
+
+We could **Choose a Page**, like the Home page and get every sub-page pulled in, or the Blog page and pull in the
+sub-pages under Blog. Then we can filter by the Classifiers in the **Classified by** setting. There will be a dropdown
+of available Classifiers to choose from.
+
+In this example, we are going to choose the Blog as our **Parent Page** and choose **Content Type > News** for our Classifier.
+
+.. figure:: img/tutorial_example_classified_by.png
+    :alt: Latest Pages with Parent Page and Classifier filter selected
+
+    The Latest Pages with Parent Page and Classifier filter selected
+
+We can choose to also **Show Body Preview** of the pages and the number of pages in this category to show.
+
+When we publish the page, the pages that we selected will show as a list on the page where we added the Latest
+Pages block. This is useful for creating a list that automatically updates content if you write more posts with
+the Classifier filter that you used.
+
+.. figure:: img/tutorial_basic_pagelist_published.png
+    :alt: Latest Pages that are published on a web page
+
+    The Latest Pages published on a web page
+
+You can also use Classifiers on an Article Landing Page. If we go to our Blog page and look at the Layout tab in
+editor mode, we can see our Classifiers in the **Show Child Pages** setting. If we only only wanted to show blog
+posts that were under the Baked Goods classifier, for example, we could select that and then the front page for
+Blogs would only list our child pages (blog posts) that have been marked as a Baked Goods category.
+
+.. note::
+    If you're coming from WordPress, you can think of Classifiers as equivalent to WordPress Categories
+    and Classifier Terms as equivalent to WordPress Taxonomies.
+
+
+For more info on classifiers, see: :doc:`/features/snippets/classifiers`.

+ 104 - 0
docs/getting_started/tutorial07.rst

@@ -0,0 +1,104 @@
+Tutorial Part 7: Forms & Contact Pages
+======================================
+
+Now we need a way for our customers to contact us. We could just make a simple
+web page with our address, phone number, and email, but we want to make some forms
+that specify what our customers are looking for. Good thing there is a special page type
+just for forms!
+
+Adding a Form page to your site
+-------------------------------
+
+Just like before, we will go to the admin to make a new page under Home page. This time we are
+going to select **Form** for our page type. This is what a new Form page looks like:
+
+.. figure:: img/tutorial_new_form_page.png
+    :alt: A new Form page.
+
+    A new Form page ready for us to build.
+
+Creating the Form page
+----------------------
+
+1. Give your form a name.
+
+2. Add a cover image if you want to include one.
+
+3. Begin adding your fields. Select the **Add Form Fields**.
+
+4. **Label** and **Field Type** are required, while the others are optional.
+
+5. Make a field required or not. Some fields that should be required are Name, Phone, Email, and Message.
+
+6. The **Field Types** available include: Text, Choice, Date & Time, File Upload, and Other.
+
+7. For fields like Name, you would choose **single-line text**.
+
+8. For fields like Message, you would choose **multi-line text.**
+
+9. Custom field types such as **Email** and **URL** are available.
+
+10. After you build the Form Fields, you can add more page content.
+
+11. In **Form Settings**, you can select a Thank You page (if you've made one).
+
+12. Choose the **Button Text** and **Button Style**.
+
+13. In **Form Submissions**, add the email address (or addresses) where you want the submissions to go. You can also add a prepared subject line here.
+
+14. Save and/or publish the form.
+
+.. figure:: img/tutorial__form_edit.png
+    :alt: Our form with fields.
+
+    A Form page with fields and settings.
+
+Then this is what the form looks like on the frontend:
+
+.. figure:: img/tutorial_form_published.png
+    :alt: A form that has been published.
+
+    Our published form page.
+
+For practice, make a few more forms. We probably need some Forms for General Inquiries,
+Career Interest, Special Event Requests, etc.
+
+Setting up Confirmation Emails
+------------------------------
+
+Confirmation emails would be a good way to provide great customer service. So, we have decided to also add a Confirmation
+email after someone fills out the Custom Cupcake Order form. Scroll down to the last field on the Form Page in editor
+mode for the **Confirmation Emails** section.
+
+Our From Address will be our email address that is designated for orders with a BCC to our bakery owner. We've added the
+subject line "Order Received!" and a message that says "Thank you for your order! We have received it and will contact
+you within 24 hours for more details and to arrange payment!"
+
+Confirmation Emails uses Django template language and HTML for best results. To learn more, read :ref:`confirmation-emails`.
+
+.. note::
+
+    By default when running locally, confirmation emails are not sent, but are
+    instead printed to the command line.
+
+Creating our Contact Us page
+----------------------------
+
+You could use a single form as your Contact Us page, but we want to show you that you can add several forms
+to your Contact Us page. We are going to add three forms to our contact page.
+
+First, make a Web Page under Home page that has the title of Contact Us. Add a title, cover image, and a Responsive
+Grid Row. Once we get to the content blocks, select the Text block and add the titles of your web forms, then link to
+their pages. You can continue to add content to this page as you'd like. This is what we did:
+
+.. figure:: img/tutorial_contact_us_edit.png
+    :alt: Edit mode for our Contact Us page.
+
+    The edit screen for our Contact Us page.
+
+Publish the page and see the result. This is how our Contact Us page looks so far:
+
+.. figure:: img/tutorial_contact_us_published.png
+    :alt: The published Contact Us page.
+
+    The published Contact Us page. We will customize the style later on.

+ 55 - 0
docs/getting_started/tutorial08.rst

@@ -0,0 +1,55 @@
+Tutorial Part 8: SEO Metadata
+=============================
+
+CodeRed CMS includes all of the technical tools you need to populate your site
+with good SEO data.
+
+
+Enabling SEO Metadata
+---------------------
+
+To enable or disable different types of metadata, go to **Settings > SEO**. This
+will take you to the SEO settings.
+
+.. figure:: img/tutorial_settings_seo_global.png
+    :alt: Settings admin for SEO.
+
+    The Settings admin for SEO.
+
+SEO settings for best practices are already selected for you, but you can change this if you would like.
+
+
+Adding SEO metadata to your pages
+---------------------------------
+
+Now you will want to add SEO metadata to your pages in the CMS. This can be easily done from the page editor.
+In the admin, navigate to the page that you want to add SEO, click the Edit option, and go to the **SEO tab**
+at the top of the page editor. These are the options that you will see in the page-level SEO editor for Home page:
+
+.. figure:: img/tutorial_page_seo_options.png
+    :alt: Page options for SEO.
+
+    The page options for SEO in the Home page.
+
+The most important section to fill out is the **Page Meta Data**.
+
+* **Slug**: This is part of the URL. For example, it would be yoursite.com/home, with the "home" being the slug.
+
+* **Page Title**: You could just use your actual page title, but if you want something more specific or search-engine detailed, you can add one specifically for SEO.
+
+* **Search Description**: This is a tagline or brief description of what the page is about. It should contain the most important keyword/s.
+
+* **Open Graph Preview Image**: If people share your page on social media sites, this sets a small photo to display with the page link.
+
+* **Structured Data**: These are a set of fields pertaining to your
+  organization, such as open hours, address, organization type, etc., which
+  search engines use for pulling up company information to display in search
+  results or in maps. Structured Data fields should be added on the Home page,
+  and also on any page representing a physical location For example, if we had
+  additional branch locations of our cupcake shop, we would want to add the
+  relevant structured data on each branch's page.
+
+To save, just **Publish** the page as normal.
+
+For information about metadata best practices, see the `SEO Starter Guide from
+Google <https://support.google.com/webmasters/answer/7451184?hl=en>`_

+ 70 - 0
docs/getting_started/tutorial09.rst

@@ -0,0 +1,70 @@
+Tutorial Part 9: Images
+=======================
+
+The Media you add to your site in the CMS is an important part of your page design. Images catch people's eyes,
+and good images make good impressions. Let's go over some ways that you can optimize your images for
+your CodeRed CMS website.
+
+Preparing your images for upload
+--------------------------------
+
+The CMS will accept the following file types for images:
+
+* **GIF**
+
+* **JPEG/JPG**
+
+* **PNG**
+
+* **WEBP**
+
+If your image is not saved in any of these formats, you need to convert your image or save your image again
+in one of these formats.
+
+To keep your website fast, large image files should never be uploaded. If your
+image file exceeds **10.0 MB**, it will not be able to be uploaded. You will
+need to decrease the file size. This can be done using an editing program, like
+Photoshop or `GIMP (free) <https://www.gimp.org/>`_. You can also use sites like
+`BeFunky <https://www.befunky.com/>`_ to re-size your images. Make them smaller
+by changing the dimensions of the image.
+
+.. note::
+
+    Photos should ideally be no larger than around 200KB to 300KB. A file size
+    that is too large will slow down your site. Ideally, images published on a
+    website should not be more than 2,000px for the width or the height. Check
+    out this awesome tutorial on `Image Sizes from Shutterstock
+    <https://www.shutterstock.com/blog/common-aspect-ratios-photo-image-sizes>`_
+    to learn more.
+
+In some cases, you may want to crop your image so that the part that you want to
+focus on is more in the frame.
+
+Ways to upload your images
+--------------------------
+
+While you have already practiced uploading images from within the page editors, you can also upload images in bulk.
+Go to **Images** from the admin bar. There, you will be able to either drag and drop your images into the upload area,
+or upload them from your computer using the upload button. Use descriptive names and/or image tags for the images so
+that you can easily search for them and use them in your pages. These tags are for admin use only --- they do not appear
+anywhere to visitors of your website.
+
+.. figure:: img/tutorial_images_upload_admin.png
+    :alt: Upload admin for Images.
+
+    The upload admin for Images.
+
+CMS editing tools for images
+----------------------------
+
+While the majority of your image editing should be done in an actual image editor, Wagtail does provide some tools to help you
+optimize your images for your site.
+
+.. figure:: img/tutorial_images_editor.png
+    :alt: CMS editor for Images.
+
+    The CMS editor for Images.
+
+The title can either be the name of the image or a custom title. You can also add tags to your images for easy searching in the CMS.
+The **Focal Point** is optional, but it defines the image's most important region. Move your cursor over the image while you see a + sign,
+then release your cursor or mouse when you have finished defining the focal point.

+ 43 - 0
docs/getting_started/tutorial10.rst

@@ -0,0 +1,43 @@
+Tutorial Part 10: Password-Protected Pages
+==========================================
+
+Finally, let's talk about how to **password-protect** pages that you only want those with proper
+permissions to be able to access when they visit the website. You may want to hide a document page
+for special bulk pricing on custom cupcake orders or an information page for customers behind a password,
+and there is an easy way to do this from within the CMS.
+
+Navigate to the page that you want to add password-protection. You need to either save it as a draft or publish
+it before you can access the Password-Protect feature.
+Look up in the right-hand corner at the Privacy setting.
+
+.. figure:: img/tutorial_password_protect_edit1.png
+    :alt: Draft page with Publish options in right-hand corner.
+
+    Draft page with Publish options in right-hand corner.
+
+The default setting for **Privacy** is Public, which means that the page will be available to view for anyone
+who comes to the website once it has been published. You can change this by clicking on the word "Public" and revealing the pop-up that
+has more Privacy options, shown below.
+
+.. figure:: img/tutorial_password_protect_options.png
+    :alt: Privacy options pop-up.
+
+    The Privacy options pop-up screen.
+
+.. note::
+    Any privacy setting that you set on a parent or landing page is applied to all of the child or sub-pages as well.
+
+Select the level of privacy that you want.
+
+* **Private, accessible to logged-in users**: Only available to those who are logged into the CMS
+
+* **Private, accessible with the following password**: Only available from  the frontend with a password that you set
+
+* **Private, accessible to users in specific groups**: Only available to groups that you set in the CMS, like Moderators or Editors
+
+For a simple way to protect content on your site from unauthorized readers, select **Private, accessible with the following password**
+and choose a password. If the page doesn't contain any sensitive information, the password doesn't necessarily need to be
+super-complex.
+
+You can set up password-protected pages for sales presentations, for example, or to share private or specialized,
+but not sensitive, information.

+ 24 - 0
docs/how_to/translation.rst

@@ -2,6 +2,30 @@ Translation & Multi-Language Support
 ====================================
 
 
+Default Language
+----------------
+
+To adjust the default language of a project, navigate to
+``projectname/settings/base.py``. Change both the ``LANGUAGE_CODE`` setting and
+the ``LANGUAGES`` setting. For example:
+
+.. code-block:: python
+
+    LANGUAGE_CODE = 'es'
+
+    LANGUAGES = [
+        ('es', _('Spanish'))
+    ]
+
+Note that these settings are both in use to communicate to the users' browser
+about the default language of the project. This ensures that users requiring
+assistive technology have a smooth experience using the site. These settings do
+not, on their own, translate or enable multiple languages on the project.
+
+`See a full list of language codes from W3.
+<https://www.w3docs.com/learn-html/html-language-codes.html>`_
+
+
 Translate the UI
 ----------------
 

+ 2 - 0
docs/index.rst

@@ -26,7 +26,9 @@ Contents
    :titlesonly:
 
    getting_started/index
+   advanced/index
    features/index
    how_to/index
+   reference/index
    contributing/index
    releases/index

+ 0 - 0
docs/getting_started/django_settings.rst → docs/reference/django_settings.rst


+ 7 - 0
docs/reference/index.rst

@@ -0,0 +1,7 @@
+Technical Reference
+===================
+
+.. toctree::
+    :maxdepth: 1
+
+    django_settings

+ 1 - 1
docs/releases/v0.15.0.rst

@@ -8,7 +8,7 @@ New features
 * NEW Stream Forms for doing advanced multi-step forms with conditional logic!
   See :doc:`/features/page_types/stream_forms`.
 * NEW optional environment specifier banners! See CODERED_BANNER settings in
-  :doc:`/getting_started/django_settings`.
+  :doc:`/reference/django_settings`.
 * NEW documentation for built-in page types! See :doc:`/features/page_types/index`.
 * NEW tutorial! See :doc:`/getting_started/tutorial01`.
 * Upgraded Wagtail to version 2.5. Now supports Django versions 2.0, 2.1, and 2.2.

+ 1 - 1
docs/releases/v0.16.0.rst

@@ -19,7 +19,7 @@ Bug fixes
 
 * Improved HTML5 validity by removing space within tags and ``href`` attributes.
 * Improved accessibility by adding title attribute to embedded iframes.
-* Specify language in HTML tag. See :doc:`/getting_started/customize_develop`.
+* Specify language in HTML tag. See :doc:`/how_to/translation`.
 * The commonly crawled URL ``/favicon.ico`` now issues a redirect to the Favicon
   set in Layout Settings.
 

+ 9 - 0
tutorial/mysite/.gitattributes

@@ -0,0 +1,9 @@
+# Explicitly declare text files that should always be normalized and converted
+# to unix line endings, to reduce cross-platform development issues.
+*.py text eol=lf
+*.html text eol=lf
+*.js text eol=lf
+*.css text eol=lf
+*.json text eol=lf
+*.md text eol=lf
+*.rst text eol=lf

+ 399 - 0
tutorial/mysite/.gitignore

@@ -0,0 +1,399 @@
+# Created by https://www.gitignore.io, modified for use with CodeRed CMS.
+
+#######################################
+### Editors
+#######################################
+
+
+### Emacs ###
+
+# -*- mode: gitignore; -*-
+*~
+\#*\#
+/.emacs.desktop
+/.emacs.desktop.lock
+*.elc
+auto-save-list
+tramp
+.\#*
+
+# Org-mode
+.org-id-locations
+*_archive
+
+# flymake-mode
+*_flymake.*
+
+# eshell files
+/eshell/history
+/eshell/lastdir
+
+# elpa packages
+/elpa/
+
+# reftex files
+*.rel
+
+# Flycheck
+flycheck_*.el
+
+# server auth directory
+/server/
+
+# projectiles files
+.projectile
+
+# directory configuration
+.dir-locals.el
+
+# network security
+/network-security.data
+
+
+### KomodoEdit ###
+
+*.komodoproject
+.komodotools
+
+
+### PyCharm ###
+
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Sonarlint plugin
+.idea/sonarlint
+
+
+### SublimeText ###
+
+# Cache files for Sublime Text
+*.tmlanguage.cache
+*.tmPreferences.cache
+*.stTheme.cache
+
+# Workspace files are user-specific
+*.sublime-workspace
+
+# Project files should be checked into the repository, unless a significant
+# proportion of contributors will probably not be using Sublime Text
+# *.sublime-project
+
+# SFTP configuration file
+sftp-config.json
+
+# Package control specific files
+Package Control.last-run
+Package Control.ca-list
+Package Control.ca-bundle
+Package Control.system-ca-bundle
+Package Control.cache/
+Package Control.ca-certs/
+Package Control.merged-ca-bundle
+Package Control.user-ca-bundle
+oscrypto-ca-bundle.crt
+bh_unicode_properties.cache
+
+# Sublime-github package stores a github token in this file
+# https://packagecontrol.io/packages/sublime-github
+GitHub.sublime-settings
+
+
+### TextMate ###
+
+*.tmproj
+*.tmproject
+tmtags
+
+
+### Vim ###
+
+# Swap
+[._]*.s[a-v][a-z]
+[._]*.sw[a-p]
+[._]s[a-rt-v][a-z]
+[._]ss[a-gi-z]
+[._]sw[a-p]
+
+# Session
+Session.vim
+
+# Temporary
+.netrwhist
+# Auto-generated tag files
+tags
+# Persistent undo
+[._]*.un~
+
+
+### VisualStudioCode ###
+.vscode/
+
+### VisualStudioCode Patch ###
+# Ignore all local history of files
+.history
+
+
+
+#######################################
+### Django/Python Stack
+#######################################
+
+
+### Django ###
+
+*.log
+*.pot
+*.pyc
+__pycache__/
+local_settings.py
+db.sqlite3
+
+# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/
+# in your Git repository. Update and uncomment the following line accordingly.
+# <django-project-name>/staticfiles/
+
+
+### Django.Python Stack ###
+
+# Byte-compiled / optimized / DLL files
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+
+### OSX ###
+
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+
+
+#######################################
+### Operating Systems
+#######################################
+
+
+### Windows ###
+
+# Windows thumbnail cache files
+Thumbs.db
+ehthumbs.db
+ehthumbs_vista.db
+
+# Dump file
+*.stackdump
+
+# Folder config file
+[Dd]esktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+
+
+#######################################
+### CodeRed CMS
+#######################################
+
+
+#### CodeRed CMS defaults ###
+
+# Cache
+cache/
+
+# File uploads from forms
+protected/
+
+# if you want to store original uploaded media files in version control,
+# replace "media/" with "media/images/"
+media/
+#media/images/

+ 38 - 0
tutorial/mysite/README.md

@@ -0,0 +1,38 @@
+# My Company Inc. website
+
+Code for site at: http://localhost
+
+
+## Getting started
+
+Make sure Python 3.5 or higher is installed on your system.
+Open this directory in a command prompt, then:
+
+1. Install the software:
+   ```
+   pip install -r requirements.txt
+   ```
+
+2. Run the development server:
+   ```
+   python manage.py runserver
+   ```
+
+3. Go to http://localhost:8000/ in your browser, or http://localhost:8000/admin/
+   to log in and get to work!
+
+## Documentation links
+
+* To customize the content, design, and features of the site see
+  [CodeRed CMS](https://docs.coderedcorp.com/cms/).
+
+* For deeper customization of backend code see
+  [Wagtail](http://docs.wagtail.io/) and
+  [Django](https://docs.djangoproject.com/).
+
+* For HTML template design see [Bootstrap](https://getbootstrap.com/).
+
+---
+
+Made with ♥ using [Wagtail](https://wagtail.io/) +
+[CodeRed CMS](https://www.coderedcorp.com/cms/)

+ 10 - 0
tutorial/mysite/manage.py

@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == "__main__":
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings.dev")
+
+    from django.core.management import execute_from_command_line
+
+    execute_from_command_line(sys.argv)

+ 0 - 0
tutorial/mysite/mysite/__init__.py


+ 0 - 0
tutorial/mysite/mysite/settings/__init__.py


+ 205 - 0
tutorial/mysite/mysite/settings/base.py

@@ -0,0 +1,205 @@
+"""
+Django settings for mysite project.
+
+Generated by 'django-admin startproject' using Django 3.0.10.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/3.0/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/3.0/ref/settings/
+"""
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+import os
+from django.utils.translation import gettext_lazy as _
+
+PROJECT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+BASE_DIR = os.path.dirname(PROJECT_DIR)
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
+
+
+# Application definition
+
+INSTALLED_APPS = [
+    # This project
+    'website',
+
+    # CodeRed CMS
+    'coderedcms',
+    'bootstrap4',
+    'modelcluster',
+    'taggit',
+    'wagtailfontawesome',
+    'wagtailcache',
+    'wagtailimportexport',
+
+    # Wagtail
+    'wagtail.contrib.forms',
+    'wagtail.contrib.redirects',
+    'wagtail.embeds',
+    'wagtail.sites',
+    'wagtail.users',
+    'wagtail.snippets',
+    'wagtail.documents',
+    'wagtail.images',
+    'wagtail.search',
+    'wagtail.core',
+    'wagtail.contrib.settings',
+    'wagtail.contrib.modeladmin',
+    'wagtail.contrib.table_block',
+    'wagtail.admin',
+
+    # Django
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'django.contrib.sitemaps',
+]
+
+MIDDLEWARE = [
+    # Save pages to cache. Must be FIRST.
+    'wagtailcache.cache.UpdateCacheMiddleware',
+
+    # Common functionality
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.common.CommonMiddleware',
+
+    # Security
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+    'django.middleware.security.SecurityMiddleware',
+
+    #  Error reporting. Uncomment this to recieve emails when a 404 is triggered.
+    # 'django.middleware.common.BrokenLinkEmailsMiddleware',
+
+    # CMS functionality
+    'wagtail.contrib.redirects.middleware.RedirectMiddleware',
+
+    # Fetch from cache. Must be LAST.
+    'wagtailcache.cache.FetchFromCacheMiddleware',
+]
+
+ROOT_URLCONF = 'mysite.urls'
+
+TEMPLATES = [
+    {
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
+        'APP_DIRS': True,
+        'OPTIONS': {
+            'context_processors': [
+                'django.template.context_processors.debug',
+                'django.template.context_processors.request',
+                'django.contrib.auth.context_processors.auth',
+                'django.contrib.messages.context_processors.messages',
+                'wagtail.contrib.settings.context_processors.settings',
+            ],
+        },
+    },
+]
+
+WSGI_APPLICATION = 'mysite.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.sqlite3',
+        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+    }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+    {
+        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+    },
+]
+
+# Internationalization
+# https://docs.djangoproject.com/en/3.0/topics/i18n/
+
+# To add or change language of the project, modify the list below.
+LANGUAGE_CODE = 'en-us'
+
+LANGUAGES = [
+    ('en-us', _('English'))
+]
+
+TIME_ZONE = 'America/New_York'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/3.0/howto/static-files/
+
+STATICFILES_FINDERS = [
+    'django.contrib.staticfiles.finders.FileSystemFinder',
+    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
+]
+
+STATIC_ROOT = os.path.join(BASE_DIR, 'static')
+STATIC_URL = '/static/'
+
+MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
+MEDIA_URL = '/media/'
+
+
+# Login
+
+LOGIN_URL = 'wagtailadmin_login'
+LOGIN_REDIRECT_URL = 'wagtailadmin_home'
+
+
+# Wagtail settings
+
+WAGTAIL_SITE_NAME = 'Simple Sweet Desserts Ltd.'
+
+WAGTAIL_ENABLE_UPDATE_CHECK = False
+
+# Base URL to use when referring to full URLs within the Wagtail admin backend -
+# e.g. in notification emails. Don't include '/admin' or a trailing slash
+BASE_URL = 'http://localhost'
+
+
+# Bootstrap
+
+BOOTSTRAP4 = {
+    # set to blank since coderedcms already loads jquery and bootstrap
+    'jquery_url': '',
+    'base_url': '',
+    # remove green highlight on inputs
+    'success_css_class': ''
+}
+
+
+# Tags
+
+TAGGIT_CASE_INSENSITIVE = True

+ 18 - 0
tutorial/mysite/mysite/settings/dev.py

@@ -0,0 +1,18 @@
+from .base import *  # noqa
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = 'abn^vwh^_m31u=sxw)+7ztc^ov&rpi2zc=1o54&m0r+(0m5s*i'
+
+ALLOWED_HOSTS = ['*']
+
+EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
+
+WAGTAIL_CACHE = False
+
+try:
+    from .local_settings import *  # noqa
+except ImportError:
+    pass

+ 79 - 0
tutorial/mysite/mysite/settings/prod.py

@@ -0,0 +1,79 @@
+from .base import *  # noqa
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = False
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = 'abn^vwh^_m31u=sxw)+7ztc^ov&rpi2zc=1o54&m0r+(0m5s*i'
+
+# Add your site's domain name(s) here.
+ALLOWED_HOSTS = ['localhost']
+
+# To send email from the server, we recommend django_sendmail_backend
+# Or specify your own email backend such as an SMTP server.
+# https://docs.djangoproject.com/en/3.0/ref/settings/#email-backend
+EMAIL_BACKEND = 'django_sendmail_backend.backends.EmailBackend'
+
+# Default email address used to send messages from the website.
+DEFAULT_FROM_EMAIL = 'My Company Inc. <info@localhost>'
+
+# A list of people who get error notifications.
+ADMINS = [
+    ('Administrator', 'admin@localhost'),
+]
+
+# A list in the same format as ADMINS that specifies who should get broken link
+# (404) notifications when BrokenLinkEmailsMiddleware is enabled.
+MANAGERS = ADMINS
+
+# Email address used to send error messages to ADMINS.
+SERVER_EMAIL = DEFAULT_FROM_EMAIL
+
+# DATABASES = {
+#     'default': {
+#         'ENGINE': 'django.db.backends.mysql',
+#         'HOST': 'localhost',
+#         'NAME': 'mysite',
+#         'USER': 'mysite',
+#         'PASSWORD': '',
+#         # If using SSL to connect to a cloud mysql database, spedify the CA as so.
+#         'OPTIONS': { 'ssl': { 'ca': '/path/to/certificate-authority.pem' } },
+#     }
+# }
+
+# Use template caching to speed up wagtail admin and front-end.
+# Requires reloading web server to pick up template changes.
+TEMPLATES = [
+    {
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
+        'OPTIONS': {
+            'context_processors': [
+                'django.template.context_processors.debug',
+                'django.template.context_processors.request',
+                'django.contrib.auth.context_processors.auth',
+                'django.contrib.messages.context_processors.messages',
+                'wagtail.contrib.settings.context_processors.settings',
+            ],
+            'loaders': [
+                ('django.template.loaders.cached.Loader', [
+                    'django.template.loaders.filesystem.Loader',
+                    'django.template.loaders.app_directories.Loader',
+                ]),
+            ],
+        },
+    },
+]
+
+CACHES = {
+    'default': {
+        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
+        'LOCATION': os.path.join(BASE_DIR, 'cache'),  # noqa
+        'KEY_PREFIX': 'coderedcms',
+        'TIMEOUT': 14400,  # in seconds
+    }
+}
+
+try:
+    from .local_settings import *  # noqa
+except ImportError:
+    pass

+ 37 - 0
tutorial/mysite/mysite/urls.py

@@ -0,0 +1,37 @@
+from django.conf import settings
+from django.urls import include, path, re_path
+from django.contrib import admin
+from wagtail.documents import urls as wagtaildocs_urls
+from coderedcms import admin_urls as coderedadmin_urls
+from coderedcms import search_urls as coderedsearch_urls
+from coderedcms import urls as codered_urls
+
+urlpatterns = [
+    # Admin
+    path('django-admin/', admin.site.urls),
+    path('admin/', include(coderedadmin_urls)),
+
+    # Documents
+    path('docs/', include(wagtaildocs_urls)),
+
+    # Search
+    path('search/', include(coderedsearch_urls)),
+
+    # For anything not caught by a more specific rule above, hand over to
+    # the page serving mechanism. This should be the last pattern in
+    # the list:
+    re_path(r'', include(codered_urls)),
+
+    # Alternatively, if you want CMS pages to be served from a subpath
+    # of your site, rather than the site root:
+    #    re_path(r"^pages/", include(codered_urls)),
+]
+
+
+if settings.DEBUG:
+    from django.conf.urls.static import static
+    from django.contrib.staticfiles.urls import staticfiles_urlpatterns
+
+    # Serve static and media files from development server
+    urlpatterns += staticfiles_urlpatterns()
+    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

+ 16 - 0
tutorial/mysite/mysite/wsgi.py

@@ -0,0 +1,16 @@
+"""
+WSGI config for mysite project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings.dev")
+
+application = get_wsgi_application()

+ 10 - 0
tutorial/mysite/requirements.txt

@@ -0,0 +1,10 @@
+coderedcms==0.20.*
+
+# django_sendmail_backend enables sending email from your web host server.
+# Remove this if using a different email backend.
+django_sendmail_backend
+
+# To use with MariaDB or MySQL, uncomment the line below:
+#mysqlclient
+# To use with PostgreSQL, uncomment the line below:
+#psycopg2

+ 0 - 0
tutorial/mysite/website/__init__.py


+ 5 - 0
tutorial/mysite/website/apps.py

@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class WebsiteConfig(AppConfig):
+    name = 'website'

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 32 - 0
tutorial/mysite/website/migrations/0001_initial.py


+ 55 - 0
tutorial/mysite/website/migrations/0002_initial_data.py

@@ -0,0 +1,55 @@
+
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django import VERSION as DJANGO_VERSION
+from django.db import migrations
+
+
+def initial_data(apps, schema_editor):
+    ContentType = apps.get_model('contenttypes.ContentType')
+    Page = apps.get_model('wagtailcore.Page')
+    Site = apps.get_model('wagtailcore.Site')
+    WebPage = apps.get_model('website.WebPage')
+
+    # Create page content type
+    webpage_content_type, created = ContentType.objects.get_or_create(
+        model='webpage',
+        app_label='website',
+    )
+
+    # Delete the default home page generated by wagtail,
+    # and replace it with a more useful page type.
+    curr_homepage = Page.objects.filter(slug='home').delete()
+
+    homepage = WebPage.objects.create(
+        title = "Home",
+        slug='home',
+        custom_template='coderedcms/pages/home_page.html',
+        content_type=webpage_content_type,
+        path='00010001',
+        depth=2,
+        numchild=0,
+        url_path='/home/',
+    )
+
+    # Create a new default site
+    Site.objects.create(
+        hostname='localhost',
+        site_name='My Company Inc.',
+        root_page_id=homepage.id,
+        is_default_site=True
+    )
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('coderedcms', '0001_initial'),
+        ('wagtailcore', '0002_initial_data'),
+        ('website', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.RunPython(initial_data),
+    ]

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 28 - 0
tutorial/mysite/website/migrations/0003_auto_20200909_1259.py


+ 18 - 0
tutorial/mysite/website/migrations/0004_auto_20200909_1428.py

@@ -0,0 +1,18 @@
+# Generated by Django 3.0.10 on 2020-09-09 18:28
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('website', '0003_auto_20200909_1259'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='cupcakespage',
+            name='days_available',
+            field=models.CharField(choices=[('Weekends Only', 'Weekends Only'), ('Monday-Friday', 'Monday-Friday'), ('Tuesday/Thursday', 'Tuesday/Thursday'), ('Seasonal', 'Seasonal')], default='', max_length=20),
+        ),
+    ]

+ 0 - 0
tutorial/mysite/website/migrations/__init__.py


+ 151 - 0
tutorial/mysite/website/models.py

@@ -0,0 +1,151 @@
+"""
+Creatable pages used in CodeRed CMS.
+"""
+from modelcluster.fields import ParentalKey
+from coderedcms.forms import CoderedFormField
+from coderedcms.models import (
+    CoderedArticlePage,
+    CoderedArticleIndexPage,
+    CoderedEmail,
+    CoderedFormPage,
+    CoderedWebPage
+)
+from django.db import models
+from wagtail.admin.edit_handlers import FieldPanel
+from wagtail.core.fields import RichTextField
+from wagtail.images import get_image_model_string
+from wagtail.images.edit_handlers import ImageChooserPanel
+
+
+class ArticlePage(CoderedArticlePage):
+    """
+    Article, suitable for news or blog content.
+    """
+    class Meta:
+        verbose_name = 'Article'
+        ordering = ['-first_published_at']
+
+    # Only allow this page to be created beneath an ArticleIndexPage.
+    parent_page_types = ['website.ArticleIndexPage']
+
+    template = 'coderedcms/pages/article_page.html'
+    amp_template = 'coderedcms/pages/article_page.amp.html'
+    search_template = 'coderedcms/pages/article_page.search.html'
+
+
+class ArticleIndexPage(CoderedArticleIndexPage):
+    """
+    Shows a list of article sub-pages.
+    """
+    class Meta:
+        verbose_name = 'Article Landing Page'
+
+    # Override to specify custom index ordering choice/default.
+    index_query_pagemodel = 'website.ArticlePage'
+
+    # Only allow ArticlePages beneath this page.
+    subpage_types = ['website.ArticlePage']
+
+    template = 'coderedcms/pages/article_index_page.html'
+
+
+class FormPage(CoderedFormPage):
+    """
+    A page with an html <form>.
+    """
+    class Meta:
+        verbose_name = 'Form'
+
+    template = 'coderedcms/pages/form_page.html'
+
+
+class FormPageField(CoderedFormField):
+    """
+    A field that links to a FormPage.
+    """
+    class Meta:
+        ordering = ['sort_order']
+
+    page = ParentalKey('FormPage', related_name='form_fields')
+
+
+class FormConfirmEmail(CoderedEmail):
+    """
+    Sends a confirmation email after submitting a FormPage.
+    """
+    page = ParentalKey('FormPage', related_name='confirmation_emails')
+
+
+class WebPage(CoderedWebPage):
+    """
+    General use page with featureful streamfield and SEO attributes.
+    Template renders all Navbar and Footer snippets in existence.
+    """
+    class Meta:
+        verbose_name = 'Web Page'
+
+    template = 'coderedcms/pages/web_page.html'
+
+
+class CupcakesIndexPage(CoderedWebPage):
+    """
+    Landing page for Cupcakes
+    """
+    class Meta:
+        verbose_name = "Cupcakes Landing Page"
+
+    # Override to specify custom index ordering choice/default.
+    index_query_pagemodel = 'website.CupcakesPage'
+
+    # Only allow CupcakesPages beneath this page.
+    subpage_types = ['website.CupcakesPage']
+
+    template = 'website/pages/cupcakes_index_page.html'
+
+
+class CupcakesPage(CoderedWebPage):
+    """
+    Custom page for individual cupcakes
+    """
+
+    class Meta:
+        verbose_name = "Cupcakes Page"
+
+    # Only allow this page to be created beneath an CupcakesIndexPage.
+    parent_page_types = ['website.CupcakesIndexPage']
+
+    template = "website/pages/cupcakes_page.html"
+
+    # The name of the cucpake will be in the page title
+    description = RichTextField(
+        verbose_name="Cupcake Description",
+        null=True,
+        blank=True,
+        default=""
+    )
+    photo = models.ForeignKey(
+        get_image_model_string(),
+        null=True,
+        blank=True,
+        on_delete=models.SET_NULL,
+        related_name='+',
+        verbose_name='Cupcake Photo',
+    )
+    DAYS_CHOICES = (
+       ("Weekends Only", "Weekends Only"),
+       ("Monday-Friday", "Monday-Friday"),
+       ("Tuesday/Thursday", "Tuesday/Thursday"),
+       ("Seasonal", "Seasonal"),
+    )
+    days_available = models.CharField(
+        choices=DAYS_CHOICES,
+        max_length=20,
+        default=""
+    )
+
+    # Add custom fields to the body
+    body_content_panels = CoderedWebPage.body_content_panels + [
+        FieldPanel("description"),
+        ImageChooserPanel("photo"),
+        FieldPanel("days_available"),
+    ]

+ 26 - 0
tutorial/mysite/website/static/website/css/custom.css

@@ -0,0 +1,26 @@
+/*Navbar */
+.navbar .nav-link {
+    font-family: 16px;
+    text-transform: uppercase;
+}
+
+/* Custom CSS classes */
+.cherry-links a {
+    color: #f75990;
+}
+
+.text-cherry {
+    color: #f75990;
+}
+
+.border-cherry {
+    border: 10px solid #f75990;
+}
+
+.bg-lightyellow {
+    background-color: #fff685;
+}
+
+.bg-cherry {
+    background-color: #f75990;
+}

+ 0 - 0
tutorial/mysite/website/static/website/js/custom.js


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است