Eager-loading of matrix field with getPage

Update after Brad's comment since the with part seems to be ok - by the way thank you, it is another good example that you never stop learning.

I never saw that with attribute in a ElementCriteriaModel and after several searches I could not find any use of that attribute in craft (Please correct me if I'm wrong) the rest should be fine.

Instead of the .limit(1) you could do the following

{% set content = entry.contentBuilder.type('copy').first() %}

The getPage() function only exists in the class RichTextData maybe you have a different fieldType? Otherwise you could just do {{ content.copy }} as well to display the text in that field.

All in all it would be a good idea to tell us a little bit more about your goal, your fields and your errors. Your description is a little bit insufficient in my opinion


Is it possible to set a hashed password programatically for a user?

There’s no API for it; you would need to save it to the database directly.

If any of the passwords are known to you, you should probably start by manually pasting that hashed password into your account’s password column, and verify that it’s actually going to work. Even if the old site was also using mcrypt, it’s still pretty unlikely that they get hashed the exact same way (different salts, etc.).

If it doesn’t work out, and you really don’t want to require everyone to reset their passwords, you could save all of your hashed passwords in a separate table, and write your own "login" controller action using a plugin. That controller action could:

grab the user by their given username/email

$loginName = craft()->request->getPost('loginName');
$user = craft()->users->getUserByUsernameOrEmail($loginName);

see if that user has a row in your old hashed passwords table
if so, fetch their password from post...

$password = craft()->request->getPost('password');

hash that password using the old site’s exact hashing method
if the hashed password matches the one in the table...
save the posted password on the user account

$user->newPassword = $password;
craft()->users->changePassword($user);

delete the user’s row in the old hashed passwords table (so we're only doing this once per user)
log the user in

craft()->userSession->login($loginName, $password);

(See craft/app/controllers/UsersController.php - actionLogin() for a full code example of login().)


If you just want to set the active class on static nav then you can just create a conditional using any defining attribute (i.e. title, slug, id, uri-segment, etc). Here is an example using the uri-segment:

{% set uriSegment = craft.request.segment(1) %}

About

Projects

News

    {li}etc

For more dynamic nav:

Singles are not particularly good for creating dynamic nav because there is no built in order or relationship between the items or even a way to identify if they are pages vs some other miscellaneous content. So you will generally have to employ some other strategy instead of, or in addition to, your singles.

If you want to create a more dynamic nav, then there are a few ways to go:

Create a separate structure (named 'primary-nav' for example) that links to the corresponding singles via an entries field (set to limit 1). See this question for an example.
Instead of singles, opt to use a structure (named 'pages'  for example) with different Entry Types defined for each of your page layouts. You can then use entry.type or craft.request.segment(1) in your template to set the 'active' class and load the appropriate sub-template.
Use one of the navigation plugins designed specifically to create page navigation, like a&m navigation or craft nav.


Short answer: I'd lean towards a structure section. Matrix is a close second.

Long answer:
When I'm faced with this an information architecture decision, I look at a couple things:

How "reusable" is the solution? (is content only stored in one place?)
Is it easy for the content author?

What's great about Craft is it generally makes both relatively easy.  What you don't want is to duplicate content in more than one section because it creates multiple sources of truth.

I typically reach for Matrix fields when I need to mix/match content on a single page.
Entries/Structures are better when you need to build content that could potentially be brought in from any area of the site.
Categories are usually "global" in scope. They also wouldn't be the right choice here. You'd end up creating too many of them and you'd eventually want to create a category set for each course to keep everything straight.

Matrix

Let's look at the workflow for doing it the Matrix way. If you want to create a new lesson, you need to define it in two places: the Lesson entry itself and the Section/divider entry (and then tell Craft which section the Lesson entry goes).

It's also going to be harder to see from the CP how many lessons are in the section.

I find Matrix fields tougher to template as well. If you use Matrix for navigation, you're going to have to iterate over all of them to see which one you're currently on. Because you're relating the entry, you're also going to have to do a "reverse" lookup.

Structures

That said, Structures bring their own set of problems and solutions. I like structures because you can easily move them up and down in the hierarchy. If a content author messed up and put a lesson in the wrong section, it's an easy drag/drop.

I also find templating a bit easier too. Want to get your current section you're in? Just get its parent:

{% set courseSection = entry.parent %}

Then you can spit out its children:

{% nav %}

 {{ entry.title }}

{% endnav %}

URLs

When you create a parent/child relationship in a structure section, the parent is going to create a new URL as well. That might not be ideal if you have thin content in the divider like you mentioned.

So your URL might look like this:

Course / Section / Lesson
 url.com/craft-cms/twig/intro-to-twig

If you use a Matrix field:

Course / Lesson
 url.com/craft-cms/intro-to-twig

That "thin" content is going to live at twig for example. I don't necessarily see that as  bad thing but keep that in mind.

Although you might not use the section/divider for much content now, you may end up needing it in the future. Every slug in that course has to be unique now as well because you're not dividing it up. You wouldn't be able to do this with a matrix field:

Course / Section / Lesson
 url.com/craft-cms/twig/intro
 url.com/craft-cms/twig/filters

If you use a Matrix field, it would have to be something like:

Course / Lesson
 url.com/craft-cms/intro-to-twig
 url.com/craft-cms/twig-filters

That's a little harder to keep consistent from a content authoring perspective as well.

I see it as a "table of contents" for the section. In a traditional book, it might be an introduction to what you're about to learn in each section. Otherwise you'd need to create another lesson called "Introduction" for example.

So to sum it up, a structure with 3 entry types is what I'd use followed by Matrix.  I don't think could go wrong with either solution though.


You can always check the craft_assetfolders table in the database, find the folder name you're looking for and grab its id.

And it's probably just a typo in your original code, you're setting the folder ID to a variable named folder_id, but you're passing id into .folderId(id).


How do I pass variables to loops within includes?

You can't reference a variable (photo) created inside the partial loop outside the partial (and loop) – it doesn't exist yet – so what you're trying to achieve isn't possible.

What you could do, is to abstract the important bits, namely the field and transform handles:

{% set vars = {
    photos: projectEntries,
    photoField: 'projectPhotos_photo_image',
    photoTransform: 'projectThumbnail'
} %}
{% include "_partials/photo-tile.html" with vars %}

And inside your partial:

{% for photo in photos %}

{% endfor %}

If that doesn't cut it, you'll probably want to use a macro:

{# Your macro file, e.g. /templates/_macros/photoTile.html #}
{% macro src(photo) %}
    {{ photo.projectPhotos_photo_image.first().getUrl('projectThumbnail') }}
{% endmacro %}

{# Inside your partial #}
{% from '_macros/photoTile' import src %}
{% for photo in photos %}

{% endfor %}

(If you're wondering about the {{- -}} syntax in the above example, the dashes are just to remove whitespace from the rendered src string – you also wrap the code inside the macro in {% spaceless %}{% endspaceless %} tags.)


Untested, but should be fairly straightforward.

{% if craft.locale == 'de' %}
    {% set template = '_layout_de.html' %}
{% else %}
    {% set template = '_layout.html' %}
{% endif %}
{% extends template %}

or

{% extends craft.locale == 'de' ? '_layout_de.html' : '_layout.html' %}

or using a locale folder (thank josh baker)

{% extends craft.locale ~ '/_layout' %}


How to use a Structure including a homepage

You can place your homepage entry in a Structure by setting its slug to __home__.

Doing so causes the entry to answer for the / (empty) URI, and it even places the little "home" icon in place of the Entry's slug in the CP.

However, if you do this, its best not to nest pages under the homepage, because then their URIs would be of the form: __home__/subPageSlug

In other words, taking the pages from your example, it's best if your structure can be:

Homepage         (site.com/)
Subpage 1        (site.com/subpage-1)
Subpage 2        (site.com/subpage-2)
Subpage 3        (site.com/subpage-3)
About            (site.com/about/)
    Subpage 4    (site.com/about/subpage-4)
    Subpage 5    (site.com/about/subpage-5)
Services         (site.com/services/)
    Subpage 6    (site.com/services/subpage-6)
    Subpage 7    (site.com/services/subpage-7)

If you want the benefit of placing the homepage in the Structure, but you need to organize some pages as descendants of the homepage, you could, in theory, rig it up... But it'd get pretty janky:

Give the homepage the special __home__ slug.
Build an index template to answer for the descendant pages by finding the intended entry, setting a entry variable, and extending your regular Page template.
Create an .htaccess rule to remove the __home__ segment from a URL if anybody accidentally lands on it, to prevent duplicate content from appearing at multiple URLs.

However, there are major drawbacks to this second approach: First, you won't be able to use your entries' url() method... or, you'll have to somehow filter out the offending __home__/ segment out of the URL any time you loop through entries or use the {% nav %} tag to generate your site nav. Also, this alternative option also foils Craft's built-in slug-uniqueness checking, so if you're not careful you could end up with duplicate slugs for some pages. In general, I don't recommend it... but it's a fun thought exercise.


Amending a lightswitch field value inside a matrix, from a plugin?

You have to do:

$matrixBlock->getContent()->setAttribute('secondLightswitch', '1');

You can only get attributes via magic methods but you can't set them


Registering a class library within a plugin

Through the magic of PHP namespacing, all plugins fall under the Craft parent class by default.

Since you're accessing a library outside of the Craft scope, you'll need to prepend a backslash to your library's class name:

$app = new \fSDK;


Get email address from registration form

Why does getBodyParam('email') always return empty here?

Because that method is looking for data in POST, and after the redirect has happened, it's a new request, and POST data is lost.

If you want to do what you're looking for, the easiest way is to pass the email address along as a query string param (i.e. ?email=foo@bar.com), then the template can do craft.app.request.getQueryParam('email').


What do I use for the Path to the Craft folder?

You will definitely want to put it above the root even if it's an add-on site, in which case the proper setup would be '../../../../craft' but this would generate a conflict with the main site craft install since there would be two folders with the same name above /public_html, so you could rename the add-on site craft folder to craftaddon and than the path would be '../../../../craftaddon'.

In case there's a really good reason for leaving it below the root, you would just use '../../../craft' but that does come with security risks that are pretty much not worth taking.


How to set multi-lingual image paths in a css file for different environments?

The easiest option is probably to use inline styles in your markup for the relevant element(s):

{% set sitePath = craft.config.environmentVariables.sitePath %}


How to write query with startdate = now?

ElementCriteriaModel parameters always add up to further filter down the results, which means an element has to be truthy for each one of them to be returned.

So your params basically look right for what you're trying to achieve. The only thing that might mess with the results is the for me unusual use of the w3c methods on the DateTime objects, which might output in a format not supportet by the criteria model.

Try one of the following variants instead:

"<= " ~ now.iso8601()
"<= " ~ now|date('c')
"<= " ~ now|date('U')

If you're not interested in ouputting the time, you could also just use:

"<= " ~ now

which outputs the same as "<= " ~ now|date('Y-m-d').


Figured out a way to do this if anyone who has the same problem.

    {% if year is defined and month is defined %}
    {% set archiveDate = year ~ '-' ~ month ~ '-01' %}

Archive for {{ archiveDate|date('F') }} - {{ year }}

    {% endif %}


How can I get a lightswitch to work with order() in craft.entries?

Instead of using .first() try using .limit():

craft.entries.section('section').lightSwitchField('1').order('RAND()').limit(1)

I have just ran a test and this is working fine for me.

EDIT

I am using this code without any errors:

{% set entry = craft.entries.section('lorem').lightSwitchField('1').order('RAND()').first %}

{% if entry|length %}
    {{ entry.title }}
{% endif %}


What's the best way to make sure external URLs aren't interpreted as relative links?

Using Craft, you could go two ways:

Make your own field-type, that handles the url in PHP and appends http:// if needed (Create a plugin for that)
Check the url for 'http' in your template, and if needed prepend it:

{% set url = entry.url | slice(0,4) == 'http' ? entry.url : 'http://' ~ entry.url %}

Be sure to use the {% cache %} tag if you use option 2, so the check only has to be done once.

Edit: You could use this plugin to pre-validate your urls.


Override SuperTable reverse related entries limit

Figured it out - I needed to remove the limit earlier in the process: adding 'limit' => null after line 72 of SuperTableVariable.php did the trick.

I'll submit a pull request to that effect as soon as I figure out how to do that.


Submitting checkbox data from a front-end form for a 'Categories' Field Type

I just tried your code and it worked.

Is your entry getting saved at all? If not I assume there might be another error. Add this to your code to output all form errors:

{% if entry is defined %}
    {{ dump(entry.getErrors()) }}
{% endif %}

Although it didn't made a difference in my test, you should remove the space to be sure:

value="{{ category.id }}"


Frontend form to change Craft Commerce user's password?

The code you are currently using is for the Set Password form that is used when a user forgets their password and you send them a Password reset email as documented at https://docs.craftcms.com/v3/dev/examples/set-password-form.html.

Here is what I'm using to allow users to change their passwords on demand. It is based on the User Profile Form documented at https://docs.craftcms.com/v3/dev/examples/user-profile-form.html

<form method="post" accept-charset="UTF-8">
    {{ csrfInput() }}
    <input type="hidden" name="action" value="users/save-user">
    {# Change to suit your needs #}
    {{ redirectInput('users/'~currentUser.username) }}
    {# Get logged-in user's ID #}
    <input type="hidden" name="userId" value="{{ currentUser.id }}">

    {% macro errorList(errors) %}
        {% if errors %}

                {% for error in errors %}

{{ error }}

                {% endfor %}

        {% endif %}
    {% endmacro %}

    {% from _self import errorList %}

    {# Enter current password #}

Current Password

    <input id="password" type="password" name="password">

    {% if account is defined %}
        {{ errorList(user.getErrors('password')) }}
    {% endif %}

    {# Enter new password #}

New Password

    <input id="newPassword" type="password" name="newPassword">

    {% if account is defined %}
        {{ errorList(user.getErrors('newPassword')) }}
    {% endif %}

    <input type="submit" value="Submit">
</form>

UPDATE: updated form to include error handling.


I suppose in your example codePoints is the actual Table field.

In order to output the table rows, the template should look like this:

{% if block.codePoints | length %}

    {% for row in block.codePoints %}
         {# Assuming 'text' is the column handle of the text field #}

{{ row.text }}

    {% endfor %}

{% endif %}

You get a double output because every row contains an array containing each table field twice, it looks like this:

array(2) { ["col1"]=> string(4) "Some" ["text"]=> string(4) "Some" }

That's why when loop over items you get every text twice.

I hope this helps.


How to auto obfuscate email addresses in rich text field

I wrote a really quick Plugin for you to use that uses the _encodeStringRot13 function from the Sprout guys to use on any variable you want in Craft. What the Plugin does is to give you a new Twig filter that you can apply like this {{ entry.body|protectEmails }} and voila! - all <a href="mailto:"> will be encoded in ROT13 (reference: http://snipplr.com/view/6037/) on output.

Download it here: http://www.naboovalley.com/craft/toolkit.rar


Can I use Rich Text field on frontend safely?

All data that goes to the database is properly parameterized by Craft / Yii and ultimately PDO to prevent against SQL Injection attacks.

For obvious reasons, the Rich Text Field is the only field type that Craft will return the "raw" content for, meaning exactly what was saved in the database.  All other field types will get automatically encoded by Twig on output.

If you're accepting guest input from a Rich Text Field on the front-end, you'll probably want to have it post to a plugin and run it through CHtmlPurifier to remove any malicious looking bits before getting saved to the database.

$purifier = new \CHtmlPurifier();
$purifier->purify($html)


Smart Map with linked SVG icons for markers

Turns out, there was a bug in Smart Map which made this impossible. Fortunately, it's now fixed!
As of Smart Map v2.4.2, it is possible to build more elaborate markers using a nested syntax for the markerOptions value. Try something like this...
{% set options = {
    markerOptions: {
        icon: {
            url: '/path/to/svg/file',
            scaledSize: 'new google.maps.Size(50,50)'
        }
    }
} %}


Create a plugin (https://docs.craftcms.com/v2/plugins/introduction.html,  https://pluginfactory.io/)
Create a Variable class with a log function (https://docs.craftcms.com/v2/plugins/variables.html)
Pass data from getFlashes to your function from within the template like e.g. craft.yourPluginName.yourVariableFunctionName(craft.session.getFlashes)

Tip: Use YourPluginName::log('blabla' . $string); to log anything to /storage/runtime/logs/yourpluginname.log from within your Plugin


Craft is using the default Yii queryCache component, which is set to the file system cache by default (i.e., what's in storage/runtime/cache.

There's no way to clear specific items in that cache, but you can clear all of it with Craft::$app->getCache()->flush().


How to load entries via ajax when a filter is clicked?

There's a ton of ways to pull this off, but in my opinion setting up pages/URLs for each category is probably a good idea, for SEO and sharing reasons. It's not something that requires a lot of work and would make implementing the AJAX part a breeze. Another win is that you're going to have a solution which will actually work without AJAX or JavaScript, too – which is always a plus :)

To start, make sure the template path for your category group points to the same template that you use for your work index listing page (e.g. work/index), and that the URL pattern is work/{slug}.

Then, amend the listing template like this – the idea is to add the category filter to the craft.entries query only when one of the category URLs are requested.

{# Your basic work entries query #}
{% set query = {
    section : 'work',
    limit : null
} %}

{% If a category URL is requested, Craft will have populated your template with a global `category` variable #}
{% if category is defined %}
    {% set query = query|merge({
        search : 'categories:'~category.slug
    }) %}
{% endif %}

{# Fetch entries #}
{% set entries = craft.entries(query) %}

        {% for entry in entries %}

                ...

        {% endfor %}

For the AJAX part, here's a super simple implementation – this example uses jQuery, and the concept is basically that we'll have the category URLs load using AJAX, and then just swap out the contents of the .projects DOM element with the returned HTML – no need for a separate AJAX template, JSON or even a craft.request.isAjaxRequest test. It's probably also a good idea to use the HTML5 History API to update the browser's address bar:

// Check if the browser supports HTML5 history
var historySupport = !!(window.history && history.pushState);

// Add an event listener for filter clicks
$(function () {
    $('body').on('click', '.filters a', onFilterClick);
});

// Event handler for the filter click
function onFilterClick (e)
{
    e.preventDefault();
    var $filter = $(e.currentTarget);
    var href = $filter.attr('href');
    if (historySupport) {
        // Update the browser's address bar
        history.pushState(null, null, href);
    }
    $.ajax($filter.attr('href), {
        dataType : 'html',
        success : function (response) {
            refreshProjects(response);
        }
    });
}

function refreshProjects (html)
{

    // Update the <title> tag
    document.title = $(html).filter('title').text();

    // Update the .projects DOM element with new HTML
    var $html = $('
').append(html);
    $('.projects').html($html.find('.projects').html());

}


Plugin that lets user select focal point/cropped area

With Craft CMS 3, focal points are built into the Image Editor.

  To launch the Image Editor, double-click on an image (either on the Assets page or from an Assets field) and click on the “Edit” button in the top-right of the image preview area in the HUD. Alternatively, you can select an asset on the Assets page and then choose “Edit image” from the task menu (gear icon).

more info

Here's how you could use the asset's focal point in your code:

Check if image has a user-defined focal point:
{% if image.hasFocalPoint %}

Get the focal point values:
{{ image.focalPoint.x }} / {{ image.focalPoint.y }}

Get the focal point values as CSS (e.g. for use in the object-position value):
{{ image.getFocalPoint(asCss=true) }}

I think in Craft CMS 2, these two plugins were widely used:

Focal Point Field
Focus Point


First of all to use Craft you need a server and a database - e.x. Apache and MySQL so it's not just PHP. Assuming you will get your hands on pre-installed craft instance basic configuration is pretty straightforward. Also you need to understand craft concepts of sections, fields, relations. Then you can setup blog or portfolio. Next you need to create views (TWIG language).

There are different plugins to help you with your content. Like this one (blog). Installing plugin is as simple as copy folder and then hit install button in the CP.

Read this answer where I included some resources to get you going with Craft.


Is there any way of specifying a default category for a category field?

You could output the categories in a way that makes them look like they are from a specific category when they don't have any categories assigned to them.

When you're outputting any of the entries, just add a custom link if there isn't a category assigned:

{% if entry.categories|length %}
    {% for category in entry.categories %}
        {{ category.title }}
    {% endfor %}
{% else %}
    Default Category Title
{% endif %}

Create a route that points "/blog/category/default-category-slug" to your filtered listing template (/blog/index, /blog/category etc.).

On the filtered listing template check if the default category slug is in the URL:

{% if craft.request.getSegment(3) == 'default-category-slug' %}

If that evaluates to true, you can now get the entries without any categories assigned to them and loop through them, see this question: How to find entries with no category:

{% set uncategorized = craft.entries.section('blog').search('-categories:*') %}
{% for entry in uncategorized %}
    {# show entry #}
{% endfor %}

Any other times you need to get the entries that "have" the default category, to loop through them, use .relatedTo on etc., instead of using:

{% set entriesWithDefaultCategory = craft.entries.section('blog').relatedTo('the-default-category') %}

Use this like on the filtered listing above:

{% set uncategorized = craft.entries.section('blog').search('-categories:*') %}


Is there a way to detect if a action is triggered from a control panel form?

If anyone comes here looking for this answer for Craft 3 the function you are looking for is Craft::$app->getRequest()->getIsCpRequest()


I tend to design my matrix block at a slightly higher level. I would have a text block with the rich text editor that allows you to enter a <hr/> tag. You can obviously also use this for all other text on the page, no need for multiple text style blocks.

You would add new block types for rich media components like galleries, videos, widgets, etc.

I know this is not exactly what you are looking for, maybe someone else will have an approach that works for your scenario.


Creating default object from empty value - Sprout Email

This error can be triggered when you try to use a variable name in your Sprout Email template or fields that is not present in the submitted Form data.

One example where this can occur is if you try to reuse the example Welcome Notification email provided in Sprout Email and don't update the {email} or {username} values in the HTML and Text body fields.

I'll add it to our list to revisit the error thrown here, as it's not clear at all what is happening from the error provided in the message you received above.


How to modify and save a field in entry on EVENT_AFTER_SAVE in a plugin?

The accepted answer works but it's for elements in general, of which an entry is just one. Instead, you can skip checking if the element is an entry (if ($event->element instanceof Entry)) and just use the Entry class itself (it extends Element) like so:

use craft\elements\Entry;
use craft\events\ModelEvent;

Event::on(
    Entry::class,
    Entry::EVENT_AFTER_SAVE,
    function(ModelEvent $event) {
        $entry = $event->sender;
        $isNew = $event->isNew;

        if ($isNew) {
            // do your thing
        }
    }
);


My solution is to setup a dedicated "Menu" section and use an entries field type for the links.  This allows you to pull together entries from multiple sections into a single menu.

My normal setup is to have to custom fields

relatedEntry - Entries field allowing you to select any other entry
customURL - text field for custom url input

The idea being that you could fill in either or and have a dynamic menu with links to entries or custom links.

Then on the template side you simple would do this

{% set menu = craft.entries.section('menu') %}

{% nav link in menu %}

        {% if link.relatedEntry|length %}
                {{ link.title }}
        {% else %}
                {{ link.title }}
        {% endif %}

        {% ifchildren %}

                {% children %}

        {% endifchildren %}

{% endnav %}

I hope that helps


I'll focus on the "sending an activation email from the front end" part of your question, since that seems to be the crux of it:

You'd have to write a very simple, custom plugin. For instant success, scaffold your plugin using the Plugin Factory. Under Plugin Components, enable Controllers.

Unzip and install your plugin.

In the Controller class, add something like the following method:

public function actionSendActivationEmail()
{

    // Get the user from the `id` URL parameter
    $user = craft()->users->getUserById(craft()->request->getParam('id'));

    if ($user) {
        // Send the activation email
        craft()->users->sendActivationEmail($user);
    }

    // Redirect back to the page we came from
    $this->redirect(craft()->request->getUrlReferrer());

}

To create a link to this controller action in your template, do something like this:

Send activation email


How to get instance of DiscountModel in Commerce 2?

$discount = new \craft\commerce\models\Discount();


How do I nest multiple templates while keeping a wrapper for some pages

In my experience, this is the type of situation where you may want to consider having a second layout rather than opting for a more complicated inheritance scheme. If your layouts are somewhat complex and you want to keep your markup DRY I would suggest moving the more complex components of your layout into includes.

Also, when I get beyond the Layout » Template relationship, instead of defining blocks and extending the Template I opt for includes there as well. This makes my workflow efficient because I always consider the Template to be the base point, inheriting up into the Layout and inheriting down into any includes.

layout_1col.html

<!DOCTYPE html>
{% include 'head' %}

  {% include 'header' %}

    {% block 'main' %}{% endblock %}

  {% include 'footer' %}

layout_2col.html

<!DOCTYPE html>
{% include 'head' %}

  {% include 'header' %}

    {% block 'main' %}{% endblock %}

    {% block 'sidebar' %}{% endblock %}

  {% include 'footer' %}

MyTemplate.html

{% extends 'layout_1col' %}
{% block 'main' %}

My content

  {% include 'mywidget' %}
{% endblock %}

By letting your layouts rely heavily on includes you can let them vary only where needed but keeping your inheritance logic simple and easily extended.


How do I know if a plugin supports Craft 3.1's project config?

The best I could find was searching thru a plugin's changelog in the Craft Plugin Store for something like "Added support for Craft 3.1 project config."

Super Table version 2.1.1:

Added support for Craft 3.1 project config.

Redactor version 2.2.0:

Redactor for Craft CMS now requires Craft 3.1.
Improved Project Config compatibility.


Twig Cycle - how to show different html based on cycle

Based on the docs:

{% for event in events %}
    {{ cycle(['odd', 'even'], loop.index0) }}
{% endfor %}

or (achieves the same thing):

{% for event in events %}
    {% set oddOrEven = cycle(['odd', 'even'], loop.index0) %}
    {{ oddOrEven }}
{% endfor %}

So, for different HTML:

{% for event in events %}
    {% set oddOrEven = cycle(['odd', 'even'], loop.index0) %}
    {% if oddOrEven == 'odd' %}

Odd

    {% else %}

Even

    {% endif %}
{% endfor %}


How to display in the CP only the current user's entries?

Craft currently doesn't have the concept of "read" permissions for elements (entries, tags, categories, etc.)... technically any user that has access to the Control Panel has read access to every Craft element whether there is a nice UI way to access them or not.

Feel free to comment/vote on this feature request though, which would enable what you're looking for: https://github.com/craftcms/cms/issues/887


How do I set up PhpStorm for plugin development

I point File->Open Directory at craft/.., and PhpStorm pick up everything for me. You probably have to set up path mappings to make debugging work properly, but PhpStorm will alert you to that and launch the mapping UI.

I have a sandbox Craft install running at local.sandbox.dev and I create a git repo in the plugins directory, and develop the plugin in there. That way I can have multiple plugins in this sandbox, all with different repos, whereas the Craft install itself is not version controlled. Makes it easy also to dump the entire installation and replace it whenever the database becomes too mangled.


How to utilize unique slugs for plugin elements that extend the BaseElement class

Brad, I realize my initial question is a bit vague, oops! I did however find a solution to why my localized slugs for my plugin element weren't being saved as a unique string.

I traced through ElementHelper::setUniqueUri() and figured out I was missing the getUrlFormat() function. Also to make sure I include {slug} in my urlFormat string in this particular case.


I believe you're getting that error because you're supplying an array ([]) for the mother field and the only value in that array would be an empty string ("") if they select the There is no mother option. So what Craft is attempting to save as a relation is [""]. Instead of an array of integer ID numbers, it's getting an empty string which isn't a valid value.

Even if you remove the value attribute of the option tag for the There is no mother option, the field will use the inner text of the tag as the value, so this does not solve your problem either.

One suggestion would be to use radio buttons instead and do the following:

<input type="radio" name="" value=""> There is no mother
{% for mother in mothers %}
    <input type="radio" name="fields[mother][]" value="{{ mother.id }}"> {{ mother.name }}
{% endfor %}
{% for user in users %}
    <input type="radio" name="fields[mother][]" value="{{ user.id }}"> {{ user.name }}
{% endfor %}

This will keep the field empty if someone selects the There is no mother option.


Any documentation about the elementindex template available?

Your best bet on learning element type templating is to look at Craft template itself. Element types use the following template for controlling the layout:

craft/app/templates/_layouts/elementindex.html

However, its important to know that you should only be using the elementindexif you are creating a custom element type.

As far as the element index, a good portion of the options are actually set through Javascript by Craft using Garnish. If you look at the following code, you can see that the status, template side, is set via Garnish.

{% block initJs %}
Craft.createElementIndex('{{ elementTypeClass }}', $('#main'), {
    context:        '{{ context }}',
    showStatusMenu: {{ showStatusMenu is defined ? showStatusMenu|json_encode|raw : "'auto'" }},
    showLocaleMenu: {{ showLocaleMenu is defined ? showLocaleMenu|json_encode|raw : "'auto'" }},
    storageKey:     'elementindex.{{ elementTypeClass }}',
    criteria:       { localeEnabled: null }
});
{% endblock %}

You can set custom statuses on your element type, if that is the route you are looking to travel. I have dug into element types and custom statuses on these posts:

How to integrate custom statuses in a workflow style custom element type?
Best way to use custom enums in my plugin templates?
Best way to implement my own statuses on my custom element type?

As for Craft documentation, they are working on it still and the only thing available right now is this:

Creating new Element Types


Redirect Manager 301 results in "Entry DNE" error

Turns out that I was right on the money with my plugin configurations, however earlier I had incorrectly tried to solve the problem using the route below, which was still in place and scuppering my subsequent good work!


It sounds like delegating the import to a Task would be the best way to implement this. More info in this answer:

Does Craft have a server-side queuing system?


How do I pass a user's first name and last name from a user profile page to the title in _layout?

Since you're just expecting one, you should only look for one. Then you don't have to use a for loop. Plus, fullName is already an attribute of user models. So you can do this for the title:

{% set thePartner = craft.users.username( craft.request.getSegment(2) ).first() %}
<title>{{ thePartner.fullName }} | {{ siteUrl }} </title>

If you're still having trouble, it may be with what segments you are pulling from the URL.


Filtering entries by year with pagination example:

{% set query = craft.request.getQuery() %}
{% set selectedYear = query.year is defined ? query.year|abs : FALSE %}

{% paginate craft.entries({
   section: 'news',
   postDate: '>=' ~ selectedYear,
   postDate: '<' ~ (selectedYear + 1)
}).limit(12) as pageInfo, newsEntries %}


What variables are available to redirectToPostedUrl?

When you take a deeper look into redirectToPostedUrl you'll see these lines. All they do is convert the Object into an array, so they fetch every property of the object and pass those to the template to use them directly. You have everything the Object has.

You can access those attributes via short syntax {title} which is the same as {{ object.title }}.

For example if you have an yii/model/MyFancyModel with the following attributes

[
    'id' => 4,
    'title' => 'foo',
    'someRelation => ['foo' => 'bar']
]

Craft will merge this array with ['object' => $object] and you have access to { id }, { title }, { someRelation.foo } as well as {{ object.id }} (and all others) as well as all other variables passed via variables the third attribute of the function, since redirectToPostedUrl doesn't pass a third argument these additional attributes are an empty array.

In your case { siteUrl } is nothing else than {{ object.siteUrl }} which is basically {{ entry.siteUrl }} that means the siteUrl of your Element. When you do { type.handle } (with an Entry)  it will render the handle of your EntryType. When your Object is a user you can do { email } to display his/her email.

One more note: The attributes of the Model are fetched via Arrayable Trait if it has it. So it grabs all fields and extraFields gets those attributes. I can provide further explanations about fields and how they work exactly in detail if you like


Updating the postDate field from a plugin?

$timeslot isn't formatted correctly to be used as the postDate. I'd create a field that takes a date and a time and then use DateTimeHelper::formatTimeForDb() to format for use as postDate.

You can't modify the postDate until after the entry has been saved - so will need to resave the entry with the newly set postDate. More info as to why you have to do this here.

craft()->on( 'entries.onSaveEntry', function( Event $event ){

  // Grab the entry from post request
  $entry = $event->params['entry'];

  // Get logged in user
  $user = craft()->userSession->getUser();

  if ( $user && $user->admin ) {
    $timeSlot = $entry->getContent()->assignedTimeslot;

    // If the postDate and Timeslot don't match (stops infinite loop)
    if ( !( $entry->postDate == $timeSlot ) ) {

        // Set postDate to timeSlot date
        $entry->postDate = DateTimeHelper::formatTimeForDb( $timeSlot );

        // Resave entry
        craft()->entries->saveEntry( $entry );
    }
  }
});


Make sure you are using

.limit(null)

In your element criteria model


How can I get all child categories - of a child category based on url segment?

There are a couple of things I would do differently here. The first is to check the Categories in this group have their own URLs box in the Category Group settings. Set the url to {slug}, and you will have category defined in the template without needing:

  {% set categoryGroup = craft.categories.group('Sections')
  .level(1)
  .slug(craft.request.getSegment(1))
  .first() %}

The second problem is that once you have your category, what you want are the children, not the ancestors:

{% set theChildren = category.children %}

{% if theChildren|length %}
  {% for cat in theChildren %}
    {{ cat.title }}
  {% endfor %}
{% else %}
  NOTHING
{% endif %}


Craft 2: craft.request.getSegment(2), see Craft docs

Craft 3: craft.app.request.getSegment(2)


Is there an easy way to reset user permissions back to usergroup settings?

I found that turning on Admin (and saving) and then turning it off will reset the user's permissions to their group defaults.  It's not the fastest, but faster than going through all the checkboxes.


Is it possible to increase the Title character limit?

The title column in the craft_content database table has the column type VARCHAR, which is limited to 255 characters. There's no setting that'll change the column type for you – you can always use a tool like phpMyAdmin or Sequel Prop to change it to TEXT in order to increase the limit and it'll probably work, though it seems like a bit of a risk.

Edit: Brought to my attention by the OP in the comments below that both the actual input field and possibly some validation functionality is also limiting the title field to 255 characters. My revised TLDR answer: Nope, don't bother trying :)

In my opinion, the following would probably be a safer/better way to solve your issue:

Add a PlainText field to your Entry Type (give the handle text or the like). Consider making it multiline, since there's a fair amount of text for each entry.
Pop into the Entry Type's settings (under CP -> Settings -> Sections -> [entry type], and uncheck the Show the Title field checkbox.
In the Title Format field that appears, add something like this:

{{ object.text | length > 252 ? object.text | slice(0, 252) ~ '...' : object.text }}

With the above in place, your content editor(s) will still only have to edit a single field (it'll just be called Text instead of Title), and the contents of the "Text" PlainText field will be copied over to the actual Title field when the entry is saved. For the few entries that have more than 255 characters, the title will be truncated to the first 252 characters, suffixed w/ ... – those 252 characters should probably be enough to identify each entry inside the CP (you might want to add fuzzy searching, btw), and the dots look nicer than just cutting the text off. The text field will contain the full, un-truncated text.

Obviously, in your templates you'll need to use {{ entry.text }} instead of {{ entry.title }} to get the full text.


Creating a slideshow with dots navigation

First, store your slides in a variable when you fetch them using craft.entries. Then, you can use the length property of that variable (which will be equal to the number of slides) to output your dots/navigation.

Full example:

{# Get the slides, store in variable called "slides" #}
{% set slides = craft.entries.section( 'yourSlideSection' ).limit( 3 ) %}

{% if slides %}

    {# Output slides, using the same "slides" variable #}
    {% for slide in slides %}

[Your slide content here]

    {% endfor %}

    {% if craft.entries.section('handle').lightswitchHandle('1') is defined %}
    {# Output navigation, check length of "slides" variable #}

         {% for i in 0..slides | length - 1 %}

         {% endfor %}

    {% endif %}

{% endif %}

What the inner navigation loop does here, is to increment the variable i by one, each time the loop runs, until i is equal to the number of slides (slides | length). This means you'll always have exactly the same number of dots as slides. Inside the loop, the variable i is also used for the data attribute.

More on the Twig loop function here


'Could Not Find Your Craft/ Folder' After Updating

Actually, the permissions have been 774, not 775 as mentioned in my post. I think that was messed up somehow during the upload, and I missed that it wasn't the correct setting. I had also cleared my firewall cache earlier and it hadn't worked. When I cleared again just now after resetting permissions, everything seems ok.


Twig Templates : Include dynamic data when using set

The main thing to remember about Twig... You never need to nest tags within other tags. So putting {{ }} within {% %} is never going to work.

To concatenate a string in Twig, use the ~ character...

{% set email = "" ~ contactInfo.contactEmail ~ "" %}


FeedMe shows you what the import trigger endpoint that you can use with curl in the feed configuration.


Lookup row in matrix field by "Name" column?

According to this answer the only ways to filter matrix blocks are by type, or by position. So you need to use the if condition on the twig for tag.

{% for m in entry.myMatrix if m.theName == nameImLookingFor %}
  {% if loop.index == 1 %}
    got the first one, it is {{m.theName}}
  {% endif %}
{% endfor %}

If you don't want to loop over all of the blocks, you can also install the mnbreakandcontinue plugin and break out of the loop after the first match:

{% for m in entry.myMatrix if m.theName == nameImLookingFor %}
  got the first one, it is {{m.theName}}
  {% break %}
{% endfor %}


How to set the commerceCurrency filter in an European style

The current formatter looks at the currency's format and the current locale of the user. What locale are you set to?

You can drop the zeros with the stripZeros param in the currencyConvert filter. See docs here: https://craftcommerce.com/docs/twig-filters


CSRF Token not verified with actual gateway in Craft Commerce

Welp... I feel like an idiot. It wouldn't let it through because I didn't set the endpoints found at https://craftcommerce.com/docs/payment-gateways


How do I set the Post field after manipulation

If you're just looking to update a custom field on the user, something like this should do it:

craft()->on('users.onBeforeSaveUser', function(Event $event) {

    if(craft()->request->isSiteRequest())
    {
        $companyId = craft()->request->getPost('email');
        $event->params['user']->getContent()->companyId = $companyId;
    }

});


What is "Temp Uploads Location" in Craft 3.2.10

That setting is basically saying, "where do you want your Assets to be stored while the related Entry is still being processed?"

Take a practical example... You are editing an Entry, and want to upload an Asset to a specific field in your entry. Click-click-click, you've added the Asset. But until you've saved the Entry, this will be considered a temporary Asset. After all, if you abandon your changes to the Entry, is it still worth saving the newly uploaded Asset?

"In the local temp folder" will drop those temporary assets into the Temporary Assets folder. That folder is exactly what it says... a temporary location for uploaded assets. Once you've properly saved your Entry, the new Asset will be moved to the appropriate location.

It's worth noting, Assets stored in the Temporary Assets folder are real assets. You may not have a front-end path to reach them, but by all other measures they are real Assets as far as Craft is concerned.


Search across Entries and Assets and paginate combined results

You're getting that error because as soon as you call find(), you're converting the ElementCriteriaModel into an array of actual fetched elements and the {% paginate %} tag requires an ElementCriteriaModel object to be passed in.

In order to pull off what you're looking for, you'd need to ability to search across multiple element types in one query, which is currently not something Craft supports.

Consider voting for this feature request, which would enable what you're trying to do.


How can I tell if a variable is an array or an entry/element query?

you can use the instance of twig test here.

You want to flip your logic, so test for Query object first else array stuff but this should work I think.

To get the specific class just {% dd props.cards %} in the template for ease.


Issues migrating Craft site to a new host

Sounds like the database you restored on the new server isn't matching the files that are in place on that server.

Check the craft/app/Info.php file's CRAFT_BUILD and CRAFT_VERSION numbers and make sure they match what's in the version and build in the craft_info table in the database.

If you need to download a previous version of Craft to get a different build/version of the files, you can do so like this.


Only display entries based on a field conditional

You could do something like this:

{# Grab all entries with a body > 100 %}
{% for entry in craft.entries.section('artists').order('RAND()').find() if entry.body|length > 100 %}

{# Limit output to the first 4 #}
{% if loop.index1 <= 4 %}
        {{ entry.id }}'s body field has a length greater than 100!

    {% endif %}
{% endfor %}

Keep in mind that if entry.body is a Rich Text field than any HTML markup (
, , etc.) will be included in that length count as well.

Twig doesn't have a break or continue tag natively, but if you install the MN Break and Continue plugin, you can make it a bit more efficient:

{# Grab all entries with a body > 100 %}
{% for entry in craft.entries.section('artists').order('RAND()').find() if entry.body|length > 100 %}
    {% if loop.index1 > 4 %}
        {% break %}
    {% endif %}

    {{ entry.id }}'s body field has a length greater than 100!

{% endfor %}


Set execution order of plugins listening to same event

Not really – there's no priority system built into events for Craft or Yii.

The easy way out is taking advantage of the fact that Craft actually loads plugins alphabetically, by name (i.e. the string returned by the plugins' getName() method). This means that if your plugins are in fact named "Plugin A" and "Plugin B", then Plugin A will be loaded before Plugin B and you can be sure that its event listener is also attached earlier, meaning that – in theory, I haven't tested this – it's event listener should also be called before Plugin B's event listener.
Edit: This doesn't actually appear to work, at least not reliably.

Of course, the correct way to solve the issue is to write your code in a way that negates the need for sequentially dependent event handlers. One way to do this is to use custom events – for instance, you could have Plugin A listen to the native entries.saveEntry event, but have Plugin B listen to some custom event instead, where Plugin A fires the custom event after completing its work inside the saveEntry handler.

You could also consider dropping the event listener altogether for Plugin B, and just call one of its service methods directly from Plugin A's event listener (you can even pass in the event object if you need it):

// Plugin A
craft()->on('entries.saveEntry', function (Event $event)
{
    ...
    // Stuff happens, then let Plugin B do its thing
    $pluginB = craft()->plugins->getPlugin('pluginB');
    if ($pluginB) {
        craft()->pluginB->someMethodName($event);
    }
}

Beyond this, its hard to advise without seeing some code examples or a more elaborate use case.


if isAjax not working or not detecting ajax request in template

You're bumping into a Twig gotcha: you can't conditionally extend a template. Either a template extends another template (i.e. it has an {% extends %} tag in it) or it doesn't. It doesn't matter if the {% extends %} statement is inside an {% if %} statement.

The solution is to create an additional layout template – e.g. _ajax.html – and use a ternary operator to have your entry template extend one or the other, before putting the conditional that loads either the content or the call to entryCount.increment inside the {% block content %}. Note that for your purposes, the _ajax.html template can be completely blank, except of course for the {% block content %}{% endblock %}). Also note that since we now need to test if the request is an Ajax request twice, it makes sense to cache the test to a variable isAjax:

{% set isAjax = craft.request.isAjax and not craft.request.isLivePreview %}
{% extends not isAjax ? '_layout' : '_ajax' %}
{% block content %}
    {% if not isAjax %}
        {# CONTENT GOES HERE #}
    {% else %}
        {% do craft.entryCount.increment(entry.id) %}
    {% endif %}
{% endblock %}

Not very elegant, is it? A better option might be to create a different endpoint for incrementing the counter entirely, negating the need to create an additional layout template and to wrap most of your content in a conditional. To create a dedicated endpoint for incrementing the counter, you can create a dynamic route. Make sure the route contains a <number> token, which will hold your entry ID (the route could just be count/<number>, for instance). Have the route point to a new template called _count.html or the like, and put the following in that template:

{% do craft.entryCount.increment(number) %}

You'll have to expose the current entry's ID to your JavaScript somehow, but that's easily done by setting a data attribute somewhere in your markup – e.g.

<body data-entryid="{{ entry.id }}">

Then, you just need to use jQuery or the like to issue a request to http://yourwebsite.com/count:

$.ajax('/count/'+$('body').data('entryid'));

Closing thought: So long as you "don't need to actually pickup any data or show it", I'm curious why you couldn't just request the basic template as-is. As long as the template contains the call to entryCount.increment somewhere inside the {% block content %} block, does it really matter if it loads the full layout behind the scenes? Sure, there's a little overhead, but it's way less work and probably doesn't matter that much in the scheme of things.


Hacksaw has an allow parameter where you specify which HTML tags you want it to pass through.

You might want to try something like:

{{ workItem.summary | hacksaw(words='75', append='...', allow='

') }}

That allows p, br, strong, and em tags to pass through untouched. If you need to allow others, just add 'em to the list.


Check if there is a discount and, is yes, how much

Something like this?

  {% if item.discount %}

    Your discount is {{ item.discount|commerceCurrency( currency ) }}

  {% endif %}


Eager Loading Image Transforms In Plugin

I came across this post while searching for the same answer. Figured it out eventually. For future reference, the correct syntax in a (Craft 2) plugin would be:

$criterea->with = [
    ["coolImage", ["withTransforms" => ["transform"]]],
    "otherAssetField",
    "someCategoryField"
];


Craft Commerce - Edit Complete Order Address from frontend

When the order is completed a copy of the address is made which is created for that specific order, that explains why it doesn't show up in the customers_addresses table.

This is so that the address is unique to that order and can be edited by an admin without affecting the customers address book. Are you wanting customers to be able to edit that address after the order is complete?


{{ category.title }} error with category groups

You should replace postCategories with whatever the handle of the category field is for your entry.


Any code fixes for "ini_set() has been disabled for security reasons"

Well, the code fix is to put an @ sign before every call to ini_set that Craft makes and all of Craft's dependencies in craft/app/vendor suppressing the error message @ini_set().

But I definitely wouldn't recommend that as you'll have to maintain some 40+ hacks across nearly as many files that could get blown away during any auto-update.


I solved the problem and am writing it down for future people encountering the same problem.

Add the following configuration to the your craft/config/general.php config file:

'omitScriptNameInUrls' => true

URLs will start to work fine.


Out of the box, Craft doesn't support sending with multiple email addresses unless you change the email settings each time you need to send from the respective email address.

Craft does allow plugins to do this though. I know of two to consider, and present them in alphabetical order:

Postmaster - Objective HTML
Sprout Email - Barrel Strength Design


Pushing additional key values without overwriting existing key values in an array

This should do it for you:

{% set myArray = {
    myKey: [
        'value1',
    ]
} %}

{% set myArray = myArray|merge({myKey: myArray.myKey | merge(['value2']) }) %}


Checking if Matrix fields are empty or not?

You can get a dropdown field's selected value by using entry.fieldhandle.value. So if entry.fieldhandle.value|length should do the trick. I think you can even omit the length filter in this case, as if you do it with the plain text field. Both an empty string and the length of an empty string resolve to false.


How can I prevent CMYK image colours being shifted when importing into Assets?

It is necessary to add the following lines to your config

'preserveImageColorProfiles' => true,
'preserveCmykColorspace' => true

This will ensure that the image colours are retained when imported to Assets. You should also ensure that the images are converted to RGB for output. I do this with the Imager plugin and specify the image should be converted to RGB in my transform options.

Also, ensure that you are using ImageMagick for any transformations by installing it on your server and adding the following to your config.

'imageDriver' => 'imagick',


How to redirect requests from root to subfolder (if they exist)?

There's a plugin to set up custom routes: Reroute by Trevor Davis, but this would require you to set them all up manually. If there's lots and lots of blog entries, you would probably want to avoid this.

As you said your slugs do match, you could just set up an ElementCriteriaModel with the slug parameter set to the relevant URI segment and see if there's an entry for that; and if that's the case redirect to that entry.

You would do this with this simple PHP code form a custom plugin. Set up a plugin and place the snippet in the init() method of your primary plugin class:

if (craft()->request->isSiteRequest())
{
    $inRoot = ((craft()->request->getSegment(2) === null) && (craft()->request->getSegment(1) !== null));

    if ($inRoot)
    {
        $criteria = craft()->elements->getCriteria(ElementType::Entry);
        $criteria->section = 'blog';
        $criteria->slug = craft()->request->getSegment(1);
        $entry = $criteria->first();

        if ($entry)
        {
            craft()->request->redirect($entry->url, true, 301);
        }
    }
}


First you'll need to get your homepage entry:

{% set homepage = craft.entries.slug('homepage').first() %}

Then, you can call the field you need from homepage:

{{homepage.entry_icon}}


Loading dynamically-named classes in a plugin's service

Rather than assuming that the providers will live in a specific location, I'd be inclined to implement a custom hook, which allows third party plugins to register a new provider.

This also allows third parties to do any initialisation of their provider, prior to handing it to you.

For example, your plugin could do something like this:

$providers = craft()->plugins->call('registerProviders');

And a third party could then do something like this, in its main plugin file:

public function registerProviders()
{
    $instance = new MyProvider('custom', 'dependencies');

    return ['myProvider' => $instance];
}

Greatly simplified, but hopefully you get the idea.


Starting & Ending Loops with Eager Loaded Elements

Found this nugget about Iterating over a Subset in the Twig docs about slice:

{% for client in clients|slice(0, 8) %}
    ...
{% endfor %}

{% for client in clients|slice(8) %}
      ...
{% endfor %}

More details about slice.


You could achieve this using a tool like schematic https://github.com/nerds-and-company/schematic

This allows you to generate all your fields and sections from a file without content. Combine this with a migration to seed dummy data (if you need that)

However, craft 3.1 will ship with a Project config which will do the same thing.


Nothing around trial usage has changed between Craft 2 and Craft 3, so as long as you follow this, it should work:

https://craftcms.com/support/try-craft-client-pro

Just keep in mind (because it sounds like you're swapping license keys around) that license.key info is cached for 24 hours at a time, so be sure and clear craft/storage/runtime/cache in whenever you do something like that to get accurate results and hit the updates page if you need to force a call home to Craft's web services.


Future me, looks like you forgot your password again and locked yourself out of Craft. You also made your way back to this Stack Exchange question with @chris' perfect answer. Good! And to make your life really easy this time around, I've already generated a password/hash combos for you that works:
|--------------|---------------------------------------------------------------|
|  *Password*  |                        *Resulting Hash*                       |
|--------------|---------------------------------------------------------------|
|  password    | $2y$13$i1fEVeKiboWR/Hx07N9JtuSZj46KNueAg0IgpwL2TId0sXN.oyibC  |
|--------------|---------------------------------------------------------------|
|  NewPassword | $2y$13$YA.7RIgllODUDcmQPf/.FuXjOmKJYot5QxpFhhf4og9fdJWsIPWK6  |
|--------------|---------------------------------------------------------------|
|  admin       | $2y$13$Nlvh.kEu8FLIITusfjzQgOIIDryqLnJ3TsV/1UINRCFLfVnjJtILK  |
|--------------|---------------------------------------------------------------|

Update: The hashing algorithm didn’t change in Craft 3, so the above combo still works.


Element API with multiple categories gives back error 500

You may want to try further limiting what you're returning from the API call.

The server may just have a low PHP memory size limit set. There are many answers to fix the PHP memory size bytes exhaustion error. Here's a few:

https://stackoverflow.com/questions/415801/allowed-memory-size-of-33554432-bytes-exhausted-tried-to-allocate-43148176-byte
https://stackoverflow.com/questions/561066/fatal-error-allowed-memory-size-of-134217728-bytes-exhausted-codeigniter-xml

That is a PHP ini setting. If you don't have access to the php.ini file, you have to call ini_set()
 somewhere in your source code.

This statement sets no memory limit, although I do not recommend using this: ini_set('memory_limit','-1');

Try the lowest amount that you can afford before deploying application, as this can cause server issues if too much memory is allocated to by a bad PHP script.


What is the advantages/disadvantages of separating macro imports?

This is definitely not a great answer, but I'm not sure anyone's going to be able to really answer this. You'd have to set up some sort of unit tests or something. And it will probably depend a lot on your server environment. But think of all the class files that need to get loaded just to handle a simple request. Personally, I think that the performance hit on an import statement is going to be pretty tiny regardless. I would opt for importing them in whatever way makes the most sense from a development/organizational perspective.


Commerce Discount: spend $X, get product free

I don't think avoiding an adjuster or plugin approach here really gains you anything much and it probably creates potential issues - it will likely just make the discount rules confusing as you can't really document the special conditions anywhere on those rules etc (and experience shows over time editors are likely to forget the special conditions and make mistakes with these sorts of hidden logic approaches).

Personally I would approach this by listening to onAddToCart and onRemoveFromCart

https://craftcommerce.com/docs/events-reference#commerce_cart.onaddtocart
https://craftcommerce.com/docs/events-reference#commerce_cart.onremovefromcart

In each of these I would call a function that inspects the order total and either adds the free item (if not already in the cart) if the total is high enough, or removes it if it is present but the order total slips below the desired total.  And you'd want to look at the item total, not the cart total presumably.

To make it editor friendly, I would also add a control panel page that allows the editors to set the cart total threshold and the free product they get if the threshold is exceeded.


Possible to set Forgotten Password path in config?

I think that this is because Craft never needs to get there by itself.  It's a page you will always link to in one of your templates.  So in theory, you can simply link directly to your Forgotten password template, like you did already.


Should the timezone in general settings effect the output of $time = date("g:ia");?

Yes, Craft calls date_default_timezone_set('UTC'); when initializing, so PHP will output all times in UTC by default.

If you want to output a time using the timezone that Craft has been set to in General Settings, you can do that with a DateTime object.

$now = new DateTime();
$time = $now->format('g:i a');


Something like this should work:

// Generate name and handle.
$globalSetName = "My Global Set";
$globalSetHandle = lcfirst(str_replace(" ","", ucwords($globalSetName)));

// Create a global set
$globalSet= new GlobalSetModel();
$globalSet->name = $globalSetName;
$globalSet->handle = $globalSetHandle;

// get all the fields from  fieldgroup
$fields = $fieldGroup->getFields();

// Get ids of the fields.
$fieldIds = array();
foreach ($fields as $field)
{
    $fieldIds[] = $field->id;
}

// Assemble the field layout
$globalSetLayout = craft()->fields->assembleLayout(
    array(
        'Content' => $fieldIds,
    )
);

// Set the field layout type.
$globalSetLayout->type = ElementType::GlobalSet;

// Set field layout on global set.
$globalSet->setFieldLayout($globalSetLayout);

// Save global set.
craft()->globals->saveSet($globalSet);


Is there a way to require the Expiration date

You could do this with a little custom plugin. All you need to do is to listen to onBeforeSaveEntry events
and check if there's an expiryDate submitted.

craft()->on('entries.onBeforeSaveEntry', function(Event $event)
{
    $entry = $event->params['entry'];

    if($entry->section['handle'] == 'news' && $entry->type['handle'] == 'news')
    {
        if ($entry->expiryDate === null)
        {
            $event->params['entry']->addError('expiryDate', Craft::t('Expiration Date cannot be blank.'));
            $event->performAction = false;
        }
    }
});


How to get all entries posted within a specific year?

This should do what you're looking for:

{% set event = craft.entries({
    section: 'events',
    startDate: 'and, >= ' ~ formYear ~ ', < ' ~ (formYear + 1)
}).one() %}


Yes and no.
Yes it is possible to include as many additional segments to selected routes and it's even possible to achieve what you want but it might become resource heavy and you would need to handle the entire routing on your own.

Channels

If it's for a channel with a set URI format like foo/{slug} you can implement a route like

Event::on(
    UrlManager::class,
    UrlManager::EVENT_REGISTER_SITE_URL_RULES,
    function(RegisterUrlRulesEvent $event) {
        $event->rules[] = [
            'pattern'  => 'foo/<uri:\S+>/<additionals:\S+>',
            'route'    => 'your-module/your-controller/route',
            'defaults' => [
                'additionals' => ''
            ]
        ];
    }
}

So all your urls like foo/{slug} as well as foo/{slug}/bar/whatever  will be routed to your controller YourController::actionRoute with the parameters

public function actionRoute(string $uri, string $additionals = null)
{
    $element = Craft::$app->getElements()->getElementByUri($uri);
    $template = (new Query())->select('template')
        ->from('sections_sites')
        ->where(['=', 'siteId', $element->site->id])
        ->andWhere(['=', 'sectionId', $element->sectionId])
        ->scalar();

    return $this->renderTemplate($template, ['entry' => $element]);
}

Note keep in mind this will only work if the uri format is rather simple like foo/{slug} it won't really work for things like foo/{author}/{category.id}/{slug}/{title} you'll need the rule mentioned in "structures" for it

Singles

If it's for singles you can do it dynamically

try {
    $uris = (new Query())
        ->select('uriFormat')
        ->from('sections_sites')-
        ->where(['=', 'siteId', Craft::$app->getSites()->getCurrentSite()->id])
        ->andWhere(['=', 'sectionId', [array of your section ids])
        ->column();
} catch (Exception $exception) {
    $uris = [];
}

if (empty($uris) === false) {
    $event->rules[] = [
        'pattern'  => '<uri:(' . implode('|', $uris) . ')>' . '/<additional:\S+>',
        'route'    => 'module/controller/action',
        'defaults' => [
            'additional' => ''
        ]
    ];
}

Structures

For structures it's not that easy... You would need to recursively remove one segment and try to search for a matching route if there is one, use it, otherwise remove the next one.

Attention pseudocode

$path = get your full path
while($element === null){
    $path = $path - lastSegment;
    $element = Craft::$app->getElements()->getElementByUri($path);
}
// attach the route `path` as you can see above

However I would not suggest the code above since it will search for a matching element for each segment for every request. I would highly recommend to include many conditions around it like Craft::$app->getRequest()->isSiteRequest() === true and $request->isAjaxRequest() === false and so on to reduce the amount of queries as much as possible


Craft 3 Element API: Query the "parent" entry of a "child" entry with Matrix blocks connected by an 'Entries' field

$page = Entry::find()
    ->relatedTo([
        'targetElement' => $article,
        'field'         => 'articleSections.articles'
    ])
    ->section('page')->all();

Please read the docs about ElementQueries and relations

Note: the Element API Creates an ElementQuery from your criteria property.

criteria => [
    'sectionId' => 4,
    'typeId'    => 1
]

Is the same as

Entry::find()->sectionId(4)->typeId(1)


Updating the cart with a different variant after a variant is in the cart

Probably easiest to show all the other variants available on the cart page next to the line item, then use ajax to remove the current line item, and add the new variant (with same line item options like qty, notes and options).

Hope that makes sense.


Using pagination with Ajax load.. help need on JS

Could you just append a new "load more" button to the page as part of the requested AJAX template and remove the old one when it's successfully loaded?

Each load more button might look something like this:

{% if paginate.nextUrl %}
  Load More
{% endif %}

Then in your isotopeLoadMore() function, you can remove the load more button that was clicked on if you get a successful response and replace it with a button from the AJAX response. Something like this:

/* isotope load more function
------------------------------------------------*/
function isotopeLoadMore(grid,el,url,datas) {

  // create a var for the button's parent so we can reuse it
  var loadIsotope = el.parent(".load-isotope")
  loadIsotope.addClass('loading');

  if (url === '#' || !url) { url = srvars.ajaxurl }
  var addData = ''; if (datas) { addData = { action:'sr_load_more', o:datas }; }
  jQuery.ajax({
    type:'POST',      // this might lead to issues for html template
    url:url,
    data: addData,
    dataType:"html",
    error: function () {
      loadIsotope.addClass("disabled");
    },
    success: function(response) {
      //console.log(response);
      if (response) {
        setTimeout(function(){
          var items = jQuery( jQuery(response).find('#'+grid.attr('id')).html());
          // Find the new Load More button in the response
          var loadMode = jQuery( jQuery(response).find('.load-isotope').html());
          items.imagesLoaded(function(){
            grid.append( items ).isotope( 'appended', items);
            // add the new Load More button
            loadIsotope.append( loadMode );
            // remove the original Load More button
            el.remove();
            animateOnScroll(false);
            // init video bg for appended items
            if(jQuery().phatVideoBg) { grid.find('.videobg-section').phatVideoBg(); }
          });
          loadIsotope.removeClass('loading');
        },500);
      } else {
        loadIsotope.addClass("disabled");
      }
    }
  });

}

But you'll have to attach your 'click' handler a little differently to make sure the dynamically loaded buttons will fire the same click function.

So instead of using...

var loadMore = jQuery('.load-isotope:not(.disabled) a');

loadMore.click(function(){ ...

That code will only attach the click function once when the page loads to the first button, but not any buttons that are dynamically added to the page thru your AJAX call.

Here's an example JSFiddle of a script that creates buttons and an alert. Only the original button works. New buttons don't do anything.

https://jsfiddle.net/alexroper/0aup8e5d/

But this JSFiddle uses delegated events like this...

$('.load-isotope').on('click', '.sr-button' ,function(event){ ...

... to attached click events to any $('.sr-button') element that's a child of $('.load-isotope'):

https://jsfiddle.net/alexroper/uq613627/1/

It's a similar problem to this Stack Overflow question:
Jquery event handler not working on dynamic content

So here's a stab at what that might look like in your code. I'm not totally sure what everything in your code does, so you still may have to tweak it.

$('.load-isotope').on('click', '.sr-button' ,function(event){
  event.preventDefault();
  var el = $(this);
  var related = $('#' + el.data('related-grid'));
  var href = el.attr('href')
  var datas = '';
  if ( ! el.parents('.load-isotope').hasClass('disabled') ) {
    isotopeLoadMore(related,el,href,datas);
  }
});


If you’re getting the {success: true} response, then the user is getting logged in successfully, and the cookie would have actually been created by that response.


Multiple Images/Assets from Super Table?

Its hard to see without the full context of field setup, but as you state, I believe its {% set image = subsection.previewImage.previewImageFile.one() %} that's the issue.

I can see further down you're correctly looking through subsection.previewImage, which are Super Table blocks. Like so:

{% for block in subsection.previewImage %}
   {% set image = block.previewImageFile.one() %}

The issue is that you're trying to call previewImageFile on the Super Table block element query, which isn't going to work.

Maybe you're trying to just look at the first block available and get the image from that? If so, you could do:

{% set image = subsection.previewImage[0].previewImageFile.one() %}


Use a custom Element Type without sources?

Element Types, Custom Fields, and Sources can work closely together, but how you structure that relationship has a lot of flexibility.

Sources are optional.  They are a convenient way to group and filter Elements, but they vary in the way that they group those Elements – Globals use Global Sets, Categories use Category Groups, Entries use Sections – and if you don't need them, you should be able to just leave them out altogether.

One place, where sources aren't completely non-existent, but where you will see the Craft user interface present an Element Type without any sources is if you restrict an Asset field to a single folder or an Entry Relations field to a single Section.  When you trigger the field modal to select the related Assets or Entries, you will not see any sources in the sidebar, because all the Elements fall into that singular container that you set in the settings.

Building your custom Element without sources would behave in a similar way. Your Element index page and your Element Field Type will expand to full width and your user will just see your content however you wish to present it.

Update

To your question in the comments: What should be an Element Type?

I'm sure this is a much longer discussion, but I will volunteer a vague one sentence answer!:  when the benefits of using the extendable features of Element Types (sources, search, relations, etc.) outweigh the costs of developing more specific custom solutions for your needs.


When looping over the letters in the range, you should be able to use the keys filter to check if the current letter is in the entriesByGroup array. If it is, you can link it or add a class, etc.
{% set letterArray = 'A'..'Z' %}
{% set entries = craft.entries.section('myEntries').orderBy('title asc').all() %}
{% set entriesByGroup = entries|group('title[:1]') %}

{% for letter in letterArray %}
   {% if letter in entriesByGroup|keys %}
      {# this letter has at least one entry, anchor link, add a class #}
   {% endif %}
{% endfor %}

{% for firstLetter, entriesInGroup in entriesByGroup %}
   {# your alphabetical entry listing %}
{% endfor %}

I do something similar here on the CraftQuest Archive page but with a slightly different approach (here's a video on it).


Tie two select fields together based on category and subcategory?

You would need to implement a front-end solution of some kind using jquery and ajax, that listens to the .on('change') event on the select fields and loads the corresponding data from a template (i.e. '_cityState.html') using the selected city or state as post parameters; and then repopulate the other select field's options dynamically by setting the html of the select field to the return results.

Have a look at jquery's .on('change') event and $.ajax() and .html() methods for more information on the jQuery part.

In your ajax only '_cityState.html' template you would want something like this: (note: this assumes that cities and states have a 'code' field that will represent the drop-down option value, but modify as needed):

{% if craft.request.isAjax %}

    {# retreive the passed city or state code #}
    {% set city = craft.request.getParam('city') %}
    {% set state = craft.request.getParam('state') %}

    {% if city or state %}

        {% if city %}

            {# get all states; set the selected state to parent of 'city' #}
            {% set entries = craft.categories.group('locationCategories').limit(null).level(1) %}
            {% set selected = craft.categories.group('locationCategories).code(city).first().parent %}

        {% else %}

            {# get all cities that are a decendent of 'state'; set selected to first city #}
            {% set entries = craft.categories.group('locationCategories').limit(null).code(state).first().decedents(1) %}
            {% set selected = entries.first() %}

        {% endif %}

        {# build the return html #}
        {% for entry in entries %}
            <option value={{ entry.code }} label="{{ entry.title }}" {% if entry == selected %}selected{% endif %}/>
        {% endfor %}

    {% endif %}

{% endif %}

Not tested. But should be pretty close. If anyone sees any errors, please edit or leave a comment.


Calls to /actions return 400 Bad Request

You're close. Just a couple minor syntax things:

remove the colon (:) before :data-fileID
$.post has 4 parameters, the dataType (in this case 'json') goes as the last parameter.
Set the url parameter to the action.

This worked for me:

Delete


Execute code before plugins are executed

You could put that code in index.php, before the require_once line. That’s about as early in the request as you can get ;)


If this were PHP, you'd need to run that through html_entity_decode to get it to convert.
I don't think there's an equivalent way to do that from Twig, but you could write a simple plugin that added an htmlentitydecode Twig filter to pull it off.


The code above is correct and working properly. There was a conflict with a masonry js file making the Craft ordering not work. Big thanks to @Anubarak for testing the code on their side.


Database Exception with Sprout Forms after updating to Craft 3

This issue is often caused if you don't first update Sprout Forms to v2.5.1 before the upgrade to Craft 3.

If something goes wrong with a plugin installation you can usually disable or remove it in the plugins table in the db. To disable it you can set the column plugins.enabled to 0 in the row for the plugin you wish to disable.

Going a step farther you can delete the plugin's row from the plugins table and remove any related tables in the database that relate to that plugin. Be sure to backup your database before editing it directly.

After that, be sure to reach out to support for the respective developer and let them know what steps they can take to recreate the problem. You can contact Sprout support at: sprout@barrelstrengthdesign.com


Opening and closing table within a switch

I think the opening and closing tags in the table are in the wrong spot. Try opening and closing the table inside the event case.

{% for block in entry.scheduleMatrix %}

{% switch block.type %}

{% case 'day' %}

{{ block.day.format('l - F j, Y') }}

{% case 'event' %}

{{ block.eventTime }}
            {{ block.eventName }}

{% endswitch %}

{% endfor %}


using craft.request.getParam to filter by relations

Wow, ok so I spent all day on this, I seem to have gotten it to work, but to be honest, I'm not 100% sure why/how this works. Anyways, I altered the code in the answer given here: Searching a specific section by four different types of parameters?

And ended with this:

{% set zoekschip = craft.request.getParam('zoekschip') %}

 {% set params = {
section:        'tours',
limit:      null
} %}
                   {% set relatedParams = ['and'] %}

{# plaats #}
{% if craft.request.getParam('zoekplaats') %}
{% set plaats = craft.request.getParam('zoekplaats') %}
{% set params = params|merge({'startloc':plaats}) %}
{% endif %}

{# Schip #}
{% if craft.request.getParam('zoekschip') %}
{% set zoekschip = craft.entries.section('ships').shipName(craft.request.getParam('shipName')).first %}
{% set relatedParams = relatedParams|merge([{ targetElement:zoekschip }]) %}
{% endif %}

                        {# add relatedParams to params #}
{% if relatedParams|length > 1 %}
{% set params = params|merge({'relatedTo':relatedParams}) %}
{% endif %}

{# perform search #}
{% set searchParams = craft.request.getParam('q') %}
{% set entries = craft.entries(params).search(searchParams|trim) %}

                            {% for entry in entries %}
..output..

{% endfor %}

Now, this works, it's pretty awesome, and after examining I understand it, and have a better understanding of how the

  relatedTo: {targetElement:  }

works :)

My next challenge, is to add another search param, regarding the dates.
The tours section currently has a matrix field which has one block, called 'vertrekdatum'. (departuredate) How I add the date to the param, and check whether any tour has that date in their blocks, and output if so..?

Thanks heaps in advanced!


The Craft global variable is available to any Javascript running in the backend/Control Panel, without including anything.

It's not possible to include, reference or use the global for any code running in the frontend.

EDIT:

To provide access to a controller action for frontend Javascript, I'd recommend setting up a site route in your plugin's main class. The following will route the URL http://yourbaseurl/myplugin/foobar/add to ExampleController:

public function registerSiteRoutes()
{
    return array(
        'myplugin/foobar/add' => array('action' => 'myPlugin/example/add'),
    );
}

As for the ExampleController, be sure to set the $allowAnonymous class variable to true. This allows visitors that aren't logged in to Craft access (beware that this will make all your controller´s actions accessible without login):

class MyPlugin_ExampleController extends BaseController
{
   protected $allowAnonymous = true;
   public function actionAdd()
   {
       // Your code here
   }
}


Craft 2: Is there a hook for Craft Commerce Orders admin page?

Ok, I got a solution. In my plugin's init function I've done the following hook:

craft()->templates->hook('cp.commerce.order.edit.main-pane', function (&$context) { ... }

If there is more 'elegant' solution, please shoot.
Cheers.


Plugin development - Querying related data

I think this works but is it an acceptable solution:

$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section = 'checkin';

$criteria->relatedTo = array(
     'targetElement' => $entry,
     'field' => $field
);

$checkin = craft()->elements->findElements($criteria);


It can be done manually with Redactor Limiter javascript plugin that would be side-loaded to CP with, i.e., Control Panel JS plugin.

Alternatively, Redactor Extras plugin for Craft can be used, that contains and loads Redactor plugins itself.


I haven't tested this, but it should be a good starting point, at the very least.

{# Determine the number of days in the month #}
{% set daysInMonth = "now"|date("t") %}

{# Determine the date range spanning the month #}
{% set firstDayOfMonth = "now"|date("Y-m-01") %}
{% set firstDayOfNextMonth = "now"|date_modify("first day of next month")|date("Y-m-01") %}
{% set postDateParam = "and, >= " ~ firstDayOfMonth ~ ", < " ~ firstDayOfNextMonth %}

{# Create our parameters object #}
{% if (category is defined) and (category is not empty) %}
    {% set params = {section: 'calendar', postDate: postDateParam, status: null, order: 'postDate', relatedTo: category} %}
{% else %}
    {% set params = {section: 'calendar', postDate: postDateParam, status: null, order: 'postDate'} %}
{% endif %}

{# Retrieve all of the events for the month, and group them by day #}
{% set groupedEvents = craft.entries(params)|group('postDate|date("Y-m-d")') %}

{# Set a shortcut for the YYYY-MM portion of the current month #}
{% set yearMonth = "now"|date("Y-m") %}

{# Loop through all of the days in the month #}
{% for day in range(1, daysInMonth) %}
    {% set formattedDay = "%02d"|format(day) %}
    {% set dayOfMonth = yearMonth ~ "-" ~ formattedDay) %}

    {# If the current day is a key in our groupedEvents array, we have events #}
    {% if dayOfMonth in groupedEvents|keys %}
        {{ dayOfMonth }}

            {% for event in groupedEvents[dayOfMonth] %}
                {{ event.title }}
            {% endfor %}

    {% endif %}
{% endfor %}

As I said, I haven't tested the above code, but the basic principle works (I've used it for grouping people by surname, and so forth).

Let me know if anything is unclear, I realise it's quite the chunk of Twig.

Stephen


FreeForm: Accessing a fields customAttributes

You'll need to access the properties individually like this, assuming you've set them on the Form object:

{{ form.customAttributes.rowClass }}
{{ form.customAttributes.columnClass }}
{{ form.customAttributes.inputClass }}
Etc...

https://solspace.com/craft/freeform/docs/form/#prop-custom-attributes


Send e-mail only to users related to entry with Postmaster/Sprout

If I'm correct in thinking that you want users who have been added to a relation field on an entry to receive an email, then the following will work.

You will have to write a plugin to listen for the onSaveEntry event. You can then loop through any users added to the custom field of the entry and send them an email.

The code would look something like the following:

craft()->on( 'entries.onSaveEntry', function( Event $event ){

    $entry = $event->params['entry'];
    // The users field returns user id's
    $userIds = $entry->getContent()->users;

    // Grab the user models using the id's from the entry field
    $criteria = craft()->elements->getCriteria( ElementType::User );
    $criteria->id = $userIds;
    $users = $criteria->find();

    // If we have users
    if ( $users ){
        // For each user
        foreach ( $users as $user ){
            // Builds and sents the email
            $email = new EmailModel();
            $email->toEmail = $user->email;
            $email->subject = "You've been added to an entry";
            // Use this for a plain text email body
            $email->body = '';
            // This uses a html body from a twig template, you can pass the entry to it to access the entries fields
            $email->htmlBody = craft()->templates->render( 'pluginname/_emails/email-template-name', array(
                'entry' => $entry
            ) );
            craft()->email->sendEmail( $email );
        }
    }
});


Getting a new cart after adding the product in decoupled frontend

UPD: after some hours of research I found the solution in this topic:
CORS preflight check failing for AJAX login form on different domain
Also I had to pass the orderNumber parameter with the value of cart number in payload.
However I have a different issue now. First I call ?action=commerce/cart/load-cart&note=from+ajax&number={number} to load my stored card into the session. Then I call action=commerce/cart/get-cart&note=from+ajax to get the content of the cart I loaded in step one, but it returns me a new empty cart. I suppose there is something to deal with the CraftSessionId in headers, am I right?


Outputting structured product attributes in JSON-LD code with SEOMatic

Andrew will likely come along and give a better answer, but you can definitely extend the outputted JSON-LD in SEOMatic.  No need to copy any of the schema things over, I think.
Here's an example from a good while ago of adding brand, mpn, sku to the mainEntityOfPage i.e. your Product.

{% if not craft.app.request.isAjax and 'debug' not in craft.app.request.segment(1) %}

    {# Set the brand ... #}
    {% set mainEntity = seomatic.jsonLd.get('mainEntityOfPage') %}
    {% set brand = product.brand.one() ??? null %}

    {% if brand|length %}
        {% set productBrand = seomatic.jsonLd.create({
            'type': 'Brand',
            'name': brand.title,
            'url': brand.homepageUrl,
        }, false) %}
    {# If someone has left off the brand, let's just say it belongs to us... #}
    {% else %}
        {% set productBrand = seomatic.jsonLd.create({
            'type': 'Brand',
            'name': 'Store Brand',
            'url': 'https://yourstore.com',
        }, false) %}
    {% endif %}

    {% do mainEntity.brand(productBrand) %}
    {# We use the title here as the actual offers below have the real MPN/SKU #}
    {% do mainEntity.mpn(product.title) %}
    {% do mainEntity.sku(product.title) %}

{% endif %}

Here's an example dealing with offers, for the actual variants of that product (assuming these are variant products):

    {# We show out of stock offers even for discontinued products at the moment #}
    {% set offers = [] %}
    {% for variant in variations %}

            {% set offers = offers|merge([seomatic.jsonLd.create({
                'type': 'Offer',
                'name': variant.description,
                'description': variant.description,
                'url': product.url,
                'availability' : (variant.available and object.available and (variant.hasUnlimitedStock or variant.stock > 0)) ? 'http://schema.org/InStock' : 'http://schema.org/OutOfStock',
                'itemCondition' : 'https://schema.org/NewCondition',
                'mpn' : variant.mpn ??? "",
                'price' : variant.salePrice|number_format(2, '.', ''),
                'priceCurrency' : 'AUD',
                'priceValidUntil' : now | date_modify('+1 year') | atom,
                'offeredBy' : {"@id" : "https://yourstore.com/#identity"},
                'seller' : {"@id" : "https://yourstore.com/#identity"},
                'sku': variant.sku,
                'image' : (one(object.masterImage)|length) ?   { "@type": "ImageObject", "url" : "https://yourstore.com" ~ craft.imager.transformImage( one(object.masterImage), 'large' ).getUrl() } : "",
                'category' : (one(object.categories)|length) ? one(object.categories).title : "",
            }, false)]) %}

    {% endfor %}

    {% do mainEntity.offers(offers) %}

SEOmatic is really very well documented, you'd want to review (well, the whole Using SEOMatic section really!) - but more specifically:
https://nystudio107.com/docs/seomatic/Using.html#seomatic-variables
and
https://nystudio107.com/docs/seomatic/Using.html#json-ld-meta-object-functions-seomatic-jsonld


Good call Brad! Not sure why that didn't occur to me :)

Here's how that's done:

# Kill admin access
RewriteCond %{REQUEST_URI} ^(.*)/admin
RewriteRule ^(.*)$ - [F,L]


Entries not being searched in the control panel

Updating the search indexes was the solution here. In addition, I also enabled Fuzzy Searching for partial matches


Getting image url error code: Impossible to access an attribute ("url") on a null variable

For whatever reason, your site isn't able to find the image. And since your Twig code isn't being defensive, it's failing ungracefully.

{% set image = block.media.first() %}

This first part is fine... I'm assuming that media is an Assets relationship field. You're attempting to fetch the first asset, and set that to image. Here's the kicker... when no assets are found, image will be set to NULL.

This next part is where your problem is...

{{ image.url }}

That'll work great assuming an asset was found. But when no assets were found, this will trigger an error. Because image would be set to NULL, and NULL doesn't have an attribute of url. (This is exactly what the error message is telling you.)

Instead, you should write that line more defensively...

{{ image ? image.url }}

This technique uses the ternary operator to first check "if image is truthy" before attempting to output image.url. In other words, if image contains a valid asset, output the image URL.

That way, if no asset is found, you won't get a big nasty error message.

On a separate note... You seem to be expressing some urgency that your site has gone down. But the screenshot you showed is clearly a byproduct of being in devMode. For the record, you never want to have devMode enabled in a live production environment.


How to get first child URL within Craft/Twig Nav tags

In that case you can put this in the href value:

{{ entry.descendants.type('page').first.url ?? '' }}

(Replace page with the other entry type handle(s).)


That's because getSegments() returns an array. You can either get one of those segments by using:

{% set segments = craft.request.getSegments() %}
{{ segments[0] }}

Or loop through all returned segments:

{% for segment in craft.request.getSegments() %}
    {{ segment }}
{% endfor %}


This is how I would go about this (in a local or dev environment):
PHP
First, activate PHP 7.4 and check if the site still works as it should (frontend, backend). I don't know exactly if version 3.3.4.1 works with PHP 7.4, but it's easier to switch back to an older PHP-version than reverting a Craft upgrade.
Craft
After you've made sure that the site still works, you can start the upgrade to Craft 3.6.11.2. I would kindly but strongly suggest that you use Craft's command line commands for this. In our experience, this gives you more detailed error messages.

First, make a backup of both your files and database (create a server snapshot, or manually create a backup)
Now, open a terminal. Don't be scared, you'll love it. Or not, depending on the outcome of this experiment.
Navigate to your project's root folder.
Run ./craft update <-- This will run the craft script in the current folder (./) and then it tells Craft to run the update command. This command will only show you what needs to be updated, it will not update anything.
Now, you should see a list of updates of both Craft and plugins. I'd start by updating Craft itself. Baby steps, you know?
Run ./craft update craft <-- This tells Craft to update ... itself. In the background, composer.json will be changed and Composer will update Craft. If that fails, Craft will tell you why. If something goes wrong, Craft will ask you if you want the changes to composer.json reverted. If you choose to do this, you can then fix the problem and run the update again. If you don't revert the changes, you can fix the problem and run composer update. If you update Craft using Composer, you'd still have to run ./craft migrate/all to run any database migrations that come with newer versions.
If the update succeeds, you can then ./craft update all, to update all plugins. This, again, changes your composer.json file and runs Composer in the background.

Common pitfalls
File or folder permissions
Your vendor folder, your config/project folder ... Craft needs permission to change things in order to proceed with the update. Check your permissions and try again.
Composer mismatches
A failing update could be Composer throwing an error. For instance, if your composer.json file explicitly says "Use PHP 7.0", and Craft 3.6 requires PHP 7.2, you'd get an error. In this case, alter composer.json and try again.
Luck and common sense
Most of the times, Craft updates just work. If they don't, put on your smart hat and try to read the errors that Craft or Composer throws at you. Another great place to look for errors is Craft's log (storage/logs/web.log). It's much easier to come up with a solution if you know what the problem is. Good luck, and remember ... backup first!


How do I filter entries by month using custom Date/Time field and paginate them?

You won't be able to paginate messageList, because that's just an array... According to the official documentation on the {% paginate %} tag, only an ElementCriteriaModel can be paginated.

To see how to create an ElementCriteriaModel which has already been filtered by month, check out Solution #2 in this thread...

You'll end up with code that looks something like this:

{% set firstDayOfMonth = year ~ "-" ~ month ~ "-01" %}
{% set daysInThisMonth = firstDayOfMonth|date('t') %}
{% set lastDayOfMonth  = year ~ "-" ~ month ~ "-" ~ daysInThisMonth %}

{% set thisMonthsEntries = craft.entries.section('messages').messageDate('and', '>= ' ~ firstDayOfMonth, '<= ' ~ lastDayOfMonth) %}

{% paginate thisMonthsEntries as entriesOnPage %}
    {% for entry in entriesOnPage %}
        {# ... whatever your code does... #}
    {% endfor %}
{% endpaginate %}


$event->performAction = false; doesn't stop action

Turns out this was a bug in Craft that's been fixed for the next (post 2.3.2629) release.


Get entries by category value from within plugin

Here's another solution which feels more correct. It uses relations and the relatedTo parameter.

// First get the all CategoryModels
$colorCriteria = craft()->elements->getCriteria(ElementType::Category);
$colorCriteria->group = 'colors';
$colorCriteria->slug = array("white");
$colorCategories = $colorCriteria->find();

// Then get the entries
$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section = "houses";
$criteria->size = "big";
$criteria->relatedTo = $colorCategories;//<= Here's the fancy part.
$entries = craft()->elements->buildElementsQuery($criteria)->queryAll();

Hopefully that helps someone else.


HTTPs Site - Redirects Go to HTTP First & Then HTTPs

Think we figured out the root cause of this - we have a load balancer in front of our origin server and, long story short, that load balancer was communicating with our origin server via HTTP, causing the extra http redirect.

Fixing that issue would be a long and arduous process so, through some infrastructure updates, we'll be moving away from using the load balancer entirely.