When Craft is determining a matching element’s score, it will loop through each of the search terms, and for each one, loop through each of the element’s attributes, and add the following points to the element’s score:

If the attribute is an exact match of the search term, 100 points will be added
If the attribute contains a full-word match of the search term, 50 points will be added
If the attribute contains a partial match of the search term, 10 points will be added

If the term is part of an “OR” group, then its points will be divided by the total number of terms within that group. So for example, if searching for “gin OR tonic” and an exact match is found within one of the custom fields, rather than getting 100 points, the element would only get 50.

As of today’s 2.2.2582 release, if the attribute is the Title field, then the score will be multiplied by 5. For example, an exact match in the Title field would actually be 500 points, etc.


How can I delete a cookie from a plugin?

I wasn't able to find an answer for removing a cookie in Craft 3 so after plenty of time of trying to figuring it out, this is my conclusion.

First of all, I am setting the cookie using the following method.

$cookie = new Cookie(['name' => 'cookieName']);
$cookie->value = $data['accessToken'];
$cookie->expire = $data['expires'];
Craft::$app->getResponse()->getCookies()->add($cookie);

I kept running into a problem with the Cookies being set are read-only so in order to remove the cookie need to use response to change and remove cookies.

Craft::$app->response->cookies->remove('cookieName');


How to: Flexible Twig Templates in Craft

I'm not sure I understand your question 100%, but I'm assuming you're talking about a thoroughly modular approach to templating, and not about letting your end users/content editors actually edit the content model (i.e. create/edit Sections, fields, field layouts etc) – because the latter is not a good approach, in general.

Either way, this is a very open question, so this answer is kind of broad (or in any case, it just outlines one way to do it, focused on entries and fields).

Note that I haven't seen the Mijingo videos, but I think the answer to your use case is probably to go with a partial-heavy approach. Basically, a "partial" is an incomplete/modular template that you can include in another template.

First off, you might want to create a "catch-all" template (let's just assume your catch-all template is called templates/index.html). Be sure to add the path to that template (which would just be index) to the Entry Template setting for all relevant Sections, to make sure the same, catch-all template is always loaded for all entry URLs.

Then, assuming your site has three fields – heading, image and body – you'd create a partial template for each of these fields. It's a good idea to store your partials in a folder prefixed with an underscore, to make sure Craft doesn't include them whenever it maps URL routes to template paths (these templates aren't standalone and should never be rendered on their own). So for the three fields in our example, you'd create these three templates:

/templates/_partials/heading.html
/templates/_partials/image.html
/templates/_partials/body.html

Here's how the heading.html partial could look:

{% if element.heading %}

{{ element.heading }}

{% endif %}

Inside your catch-all template, you'd then need to {% include %} these partial templates, following some logic of your choice.

Here's an approach that basically loops through all fields for the current entry's field layout, attempting to include a partial template for each field:

{% extends '_layout' %}{# Assuming this template extends a basic layout template #}
{% block content %}

    {# Get all fields, indexed by field ID #}
    {% set allFields = craft.fields.getAllFields('id') %}

    {# Get the IDs for all fields in this entry's field layout #}
    {% set fieldIds = entry.getFieldLayout().getFieldIds() %}

    {# Loop through the entry fields' IDs; attempt to include template based on each field's handle #}
    {% for fieldId in fieldIds %}
        {% set field = allFields[fieldId] ?? null %}
        {% if field and entry[field.handle] %}
            {% include '_partials/'~field.handle ignore missing with { element: entry } %}
        {% endif %}
    {% endfor %}

{% endblock %}

A couple of things to note:

First, the above code builds the template path to each partial dynamically, by joining the root path ('_partials/') with each field's handle property (using the tilde operator ~). In other words, this solution hinges upon using the fields' handles for the partial templates' filenames. Note that its also possible to pass an array of template paths to the {% include %} tag, in which case Craft will attempt to load the next template in that array whenever it fails the load the former. Here's how that could look:

{% include ['_partials/matrix/'~field.handle, '_partials/fields/'~field.handle] ignore missing with { element: entry } %}`

With the above, Craft would first look for the template /templates/_partials/matrix/title.html, and if that file doesn't exist it'd look for /templates/_partials/fields/title.html (before failing silently due to the ignore missing directive).

Second, it might seem redundant to pull all fields from the FieldsService, but the alternative is to hit the database for every field in your entry's field layout, so this should actually be the most performant way to pull the current entry's actual FieldModels.

Third – the with statement for the {% include %} tag enables you to pass parameters to the included template. In this example, we're actually exposing the current entry to the included template as the more generic element variable. This is just future proofing in case we want to use the same partials for other element types, e.g. categories (in which case you'd use with { element: category }) – notice that in the example heading.html template above, element.heading is used over entry.heading.

If you want to avoid variable pollution, you might pass the only directive aswell, in which case only whatever parameters passed with with will be made available to the included statement, nothing else:

{% include '_partials/'~field.handle with { element: entry } only %}

Of course, you can include other stuff in the object passed to with, as well. For instance, you might want to render stuff differently if the current field is either first or last in the loop:

{% include '_partials/'~field.handle with { element: entry, isFirst: loop.first, isLast: loop.last } %}

{# In heading.html #}

{{ element.heading }}

Going further; talking about Matrix fields and alluding to the fact that putting Matrix field partials in a separate templates folder might be a good idea – if you're going fully modular it might make sense to create separate templates for each Matrix block type, as well. Tons of ways to skin this cat, but one way to do it is to add a sub folder for every Matrix field, containing partials for each of the field's block types. For example, if you've got a Matrix field called contentBlocks with the block types images and text you might structure it like this:

templates/_partials/contentBlocks.html (the partial for the Matrix field itself)
templates/_partials/contentBlocks/images.html (the partial for the images block type)
templates/_partials/contentBlocks/text.html (the partial for the text block type)

Then, inside the contentBlocks.html template, you could do something like this:

{% for block in element.contentBlocks %}
    {% include '_partials/contentBlocks/'~block.type ignore missing with { block: block } only %}
{% endfor %}

In fact, you might not even need the contentBlocks.html field template, and just do something like this in index.html:

{% if field.type == 'Matrix' %}
    {# Attempt to include the blocks for this Matrix field #}
    {% for block in entry.field %}
        {% include '_partials/'~field.handle~'/'~block.type ignore missing with { block: block } only %}
    {% endfor %}
{% else %}
    {# Non-Matrix fields #}
    {% include '_partials/'~field.handle ignore missing with { element: entry } %}
{% endif %}

One final thing to note – with the above solution, your entries' fields' partials will be included in the order corresponding to the entry type's field layout (i.e. the first field in the layout will be included first). This may or may not be what you want (the order that makes sense inside the CP may not always correspond to what the design/front end should look like) but if you need more control over your fields' order, you could do something like this inside index.html:

{% set fieldsToInclude = ['image', 'heading', 'body'] %}
{% for fieldHandle in fieldsToInclude %}
    {% if entry['fieldHandle'] %}
        {% include '_partials/'~fieldHandle ignore missing with { element: entry ) %}
    {% endif %}
{% endfor %}

The above will actually be slightly more performant than the first example, because it avoids the few database queries involved in pulling the fields dynamically.

Of course, for optimal flexibility you'd probably go heavy on the Matrix fields, too – obviously, any Matrix block partials would render in their original order inside the Matrix fields, so with Matrix blocks your content editors will have complete control over where each piece of content actually renders.


Sprout Forms will be adding support for Project Config in Craft 3.1. At the time of this posting the Craft Project Config has not yet been released, the Project Config will likely give us a much better workflow to maintain plugin settings between environments.

While there is an alternative, the export/import path described below would be a bit tedious to maintain and could just be easier to do manually depending on how many Forms you need to migrate (as you will have to define those forms in the export JSON to get them exported).

Sprout Forms has a Sprout Import integration and supports importing Form and Form Entry Elements via the Sprout Import Element Importer API.

With the Sprout Forms/Sprout Import integration you could:

Create a Twig template or script that outputs your Forms (and/or Entries) to a JSON file
Create a Migration that grabs that JSON export and hands it off to Sprout Import to import.

This import can be triggered using the Sprout Import service layer or via a console command.

./craft sprout/import/run --file="@root/import.json"

More on importing forms using this API: https://sprout.barrelstrengthdesign.com/docs/forms/importing-data.html#forms


Create a Structure page with entries list

If your channel is products, you list them like this on their index page (which is presumably your '/products' page)

{% for p in craft.entries.section('products') %}
  {# p is our product. display it however #}
  {{p.title}}
{% endfor %}


If I understand the question properly, this should do it for you:

{% if entry.gallery|length %}

    {% for image in entry.gallery.all() %}

    {% endfor %}

{% endif %}


You need to tell Google that you have a new site or the best SEO in the world won't matter a jot; Google has no idea your site exists until you tell it.

There are 4 essential steps to getting your site indexed:

Add your URL – Submit your website for inclusion in Google's index.
App crawling – Get your app indexed by Google.
Search Console – Submit a Sitemap of your website to Google.
Structured data – Label your structured content to help users find pages relevant to their search.

These steps, and more, are detailed here.

Edit: I've taken another quick look at your site and I think you may be sending Google mixed signals about what to index.

You said your site is http://gastro-on-fire.be but that re-directs to https://gastro-on-fire.be -- These are two different sites.
Both sites are accessible also at the www subdomain, so you have actually 4 sites, which one do you want to index? Pick one, and follow Google's advice for that one. Add the others in Webmaster tools but set tell Google which is your preferred one, which one it should index.
Ensure your seo strategy is inline, and remains in line with that choice. Currently, the sitemap at https://gastro-on-fire.be/sitemap.xml gives all the site links as the www version; so you're telling Google to crawl the www site instead!!

Which one do you want to be indexed? Pick one, and ensure everything you tell Google backs up that choice.


Having issues looping through variants for Commerce 2 Products using Element API

You are setting the whole $variants variable to last item in the array instead of creating the $variants array variable and pushing items into it. Should be this:

'transformer' => function (Product $product) {
          $variants = [];

          foreach ( $product->getVariants() as $variant ) {
            $variants[] = [
              'type'          => $product->type->name,
              'title'         => $variant->title,
              'sku'           => $variant->sku,
              'price'         => $variant->price,
              'stock'         => $variant->stock,
              'intro'         => $variant->intro,
              'purchasableId' => (int) $variant->purchasableId,
              'status'        => $variant->status,
              'url'           => $variant->url,
              // 'productPhoto'  => $variant->productPhoto
            ];
          }

          return $variants;
        }


You can add a hidden field for your postDate to your GuestEntry form, e.g.

<input type="hidden" name="postDate" value="{{ now|date("Y-m-j H:i:s") }}" />

This adds the postDate using Craft's YYYY-MM-DD HH:MM:SS format.


Completely possible without any extra routing!
First you would need to make sure the relation fields are required to prevent any errors.
For the Country section, you would simply set up your section with the URI format { slug }
For Region you would set up the URI Format to grab the related Country's slug for the first segment, like this: { yourCountryFieldHandle.one().slug }/{ slug }
And for Town it would be { yourRegionFieldHandle.one().yourCountryFieldHandle.one().slug }/{ yourRegionFieldHandle.one().slug }/{ slug } which gets the related Region's Country for the first segment, then the related Region for the second.
You can then specify a different template for each section.


It doesn't really matter where you have the tags. Yes, you do save the overhead of the include by wrapping the tag, but the impact is minimal (not really measurable) and once compiled to PHP it's cached anyways.

I usually have the cache tags within my partials. It's more flexible, you can cache blocks of code separately and leave out certain parts. I also often use the globally flag and include a partial into multiple templates. Defining the cache tag within the partial makes sure I always use the right cache ID.


Graphql total results / pageinfo when searching with pagination

Try entryCount. You can also add arguments to this, such as section: entryCount(section:"news"), for example.


If you're using the nav on an entries page, this is how you'd do that:

You can check if an ElementCriteriaModel with the following criteria returns anything using the length filter. The ID of the entries must match your current entry's ID and they must be related to the currently looped category.

    {% set activeClass = craft.entries.id(entry.id).relatedTo(category)|length ? 'active' %}
    {{ category.title }}


Craft ships with Redactor’s Table plugin, but you must add it to your Redactor config yourself (in craft/config/redactor/).

{
    // ...
    plugins: ['table']
}

To determine which config file to place this in, go to your field’s settings in Settings → Fields → [your Rich Text field name], and check your “Redactor Config” setting.


If your Redactor config included a "formatting" value in the "buttons" array, you need to rename that to "format".

https://craftcms.com/help/redactor-ii-configs


Add, remove, and append entries to an entries field via frontend form

You guessed right, you have to set all already added entries again. To do this,
just have some Twig logic when outputting the fields:

{% for currentTeam in entry.tournamentTeams %}
    <input type="hidden" name="fields[tournamentTeams][]" value="{{ currentTeam.id }}">
{% endfor %}
<input type="hidden" name="fields[tournamentTeams][]" value="{{ team.id }}">

To remove the entry:

{% for currentTeam in entry.tournamentTeams if currentTeam.id != team.id %}
    <input type="hidden" name="fields[tournamentTeams][]" value="{{ currentTeam.id }}">
{% endfor %}

Update: What I'm not sure about is if the above code works when trying to remove the last remaining entry. If it doesn't work I'd try and add something like this:

{% if (entry.tournamentTeams|length == 1) and (entry.tournamentTeams.first().id == team.id) %}
    <input type="hidden" name="fields[tournamentTeams]" value="">
{% endif %}


You don't want braces within braces.

You want something like this instead:

{% set index = craft.entries.section(sectionName ~ 'Index').first %}

Same needs changing in the for loop.


Develop a plugin for outputting data in a loop

Please have a look at the "Template Variables" section of the documentation:
http://buildwithcraft.com/docs/plugins/variables

The template variables are the containers of data which you can access from your twig templates using craft.yourPluginName.yourPluginVariableFunctionName

Let's say you want to loop through 3 different items in an array from your Plugin. Your Plugin variables file might look like this:

<?php
namespace Craft;

class PluginNameVariable
{
    public function data()
    {
        return array('one', 'two', 'three');
    }
}

In your template you can now "fetch" this data like this - in a loop:

{% for item in craft.pluginName.data %}
    {{ item }}
{% endfor %}

Please not this code is not tested


How to set up {siteUrl} to work with both http and https

One method is using something like the following in your general.php file.  Using this method the config settings will take on the scheme of the request being made.  I've set both the siteUrl and example environmentVariables below:

<?php

// Ensure our urls have the right scheme
define('URI_SCHEME',  ( isset($_SERVER['HTTPS'] ) ) ? "https://" : "http://" );

// The site url
define('SITE_URL',    URI_SCHEME . $_SERVER['SERVER_NAME'] . '/');

// The site basepath
define('BASEPATH',    realpath(CRAFT_BASE_PATH . '/../') . '/');

return array(
    '*' => array(

        'siteUrl' => SITE_URL,

        'environmentVariables' => array(
            'siteUrl'  => SITE_URL,
            'basePath' => BASEPATH
        ),
    ),
);


Documentation for this can be found in Craft's class reference.

# Login as user, by id
Craft::$app->getUser()->loginByUserId($user->id);

# Redirect
return Craft::$app->getResponse()->redirect($url)->send();

Or, if you're in a controller:

return $this->redirect($url);


User photos not showing after replacing photo

Can I ask why you can't change the filename to the old one? For the new file that is. That will easily solve the problem.

The reason it won't show up as per the new file name is that when you upload a profile photo for a user, craft creates a image model for it and when copying over a file directly this image model will not be created hence you either need to use the backend for uploading profile photos or change the filename to the old one. Also you would need to do this in multiple folders as inside userphotos/{username}/ you will see that there are multiple folders, these are folders for different cropped sizes of the profile photo and will be displayed in different locations, Hence you will need to replace the file in all of these locations for the user photo to appear correctly in all places.


You can change your entry's URL format right inside Craft. It's under Settings -> Sections then choose the section you want.

Under URL Format, just add .html after the {slug}. In this example, I've also added the year that the entry was added to the URL as well and you can really make it whatever you want.
Using .htaccesss you could also remove the .html extension from the static pages too if you want to follow Craft's format (though be careful with that one).
SEO
As far as whether it's a good idea to do either for SEO purposes, you're going to get a lot of differing opinions. I'm a URL minimalist,  so I tend to keep my URLs simple, including removing www from the hostname and removing any trailing slash from URLs if possible.
Google tends to favor short URLs among other things but it's not a big factor.
Content is content. Years ago, I remember there used to be some SEO benefit to adding .html but if search engines can index it, it doesn't matter what the URL is.
The bigger issue for me is any time you change a URL, you risk blowing something up. I'm always reminded of the saying Cool URLs don't change.
If your site has been around awhile,  I wouldn't mess with them. Other people may be linking to your pages and if you change the URLs, you'll want to put in 301 redirects—otherwise they'll 404, which is a much bigger problem.


First you’ll need to get the Table Of Contents entry that holds the Entries field (the source entry). I’m going to assume that is in a Single section with the handle toc.

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

Once you have that, you can just pass its Entries field value into getPrev() and getNext():

{% set prevEntry = entry.getPrev(toc.myEntriesField) %}
{% set nextEntry = entry.getNext(toc.myEntriesField) %}


Compare Value to Category Title In Template

Your entry_pos is an Element Criteria Model. You want to get the first (and probably only) category from this ElementCriteriaModel, and then compare its title to 'staff':

{% set entry_pos = entry.position.first %}
{% if entry_pos.title == 'staff' %}
  ...
{% endif %}

This will give you an error if there is no entry.position.first, as entry_pos will be null, so you should defend against that somehow. One possility is:

{% if entry_pos and entry_pos.title == 'staff' %} ...

Another is to use twigs useful null-coalescing operator:

{% if (entry_pos.title ?? '') == 'staff' %} ...

With Craft 3, you will use one instead of first, but otherwise everything is the same.


Multiple articles with individual entries

There are always so many ways to configure a CMS like Craft. Personally I would make:

"Articles" a Channel
"Main Sections" a Structure

Within Articles, you could have a Matrix field, which would in turn contain an Entries custom field, allowing your client to select Main Sections and sort them as content-blocks, using the drag-n-drop features of the Matrix custom field.

From the client's perspective, they would see something like this:

Let us know if that helps, I'm sure others will offer alternatives :)


Updating Entry field with GraphQL mutation

To edit an entry via a GraphQL mutation you will need to pass the id of the entry you want to edit (similar to front end entry form).
This example assumes a news Section, an article Entry Type and will update the entry title.
Mutation
mutation MyMutation($id: ID = "", $title: String = "") {
  save_news_article_Entry(id: $id, title: $title) {
    id
    title
  }
}

Query variables
{
  "id": "12345",
  "title": "My title update"
}


Well, I deleted the whole contactform folder, downloaded it again, and added it back to the plugins folder. Just to be safe, I ran service httpd restart. After that, it showed up immediately.

I can't be sure, but I'm assuming that there was just something wrong with the originally downloaded files.

I hope this helps someone else in the future.


Plugin only saving one column in database

I had a similar problem, ended up using multiple setAttribute() calls instead of setAttributes().

I created an array of attributes separately and then looped through them and called setAttribute for each one, seemed to do the trick.

if ($id = $model->getAttribute('id')) {
    if (null === ($record = $this->myRecord->findByPk($id))) {
            throw new Exception(Craft::t('Can\'t find item with ID "{id}"', array('id' => $id)));
        }
    } else {
        $record = $this->myRecord->create();
    }

    /* Not this: */
    $record->setAttributes($model->getAttributes());

    /* This instead: */
    $attributes = array(
        'column1' => $col1,
        'column2' => $col2
    );
    foreach($attributes as $k => $v) $record->setAttribute($k,$v);
}


Is there any danger to Craft from upgrading from PHP 5.5 to PHP 5.7?

Don't worry, you should be fine.

Craft currently supports a minimum of PHP 5.3. Any higher version of PHP is also compatible.

When Craft 3 ships (late 2016 / early 2017), it will require a minimum of PHP 5.6.

Side note... If you're about to upgrade PHP, I highly recommend switching to PHP 7. The performance boost is notable, and should speed up your site by about 50-80%!


Caching in Craft 3 causes out of memory when including grouped for loop

After looking through this, it would probably be better off as a Github issue than a Stack Exchange post, but answering here for posterity.

In short, this comes down to a change we had to make in Craft 3 to fix some other caching issues where we started to serialize element queries when saving them, so that when retrieving them later to determine if a cache should be busted, we would unserialize and execute the saved element query.

It turns out that serialization requires significantly more memory than not serializing.

In the case of your database, with your custom fields and plugins on both shows and movies sections, it takes about 1.1MB of memory to save each element query inside of your {% cache %} tags.

Given your current template code, with the nested for loops and the number of elements you're accessing in the cache tag, you're looking at about 7,000 element queries that Craft has to track, or 7.7GB of memory - hence the error you're hitting.

It's on our list to completely revamp the template caching engine to help mitigate scenarios like this (as well as other template caching issues people have come across)

In the meantime, you've got a few options.

Revamp your template logic so you're not executing O(n2) database queries.  That could involve pure Twig/templates or a custom plugin where you can grab exactly the data your template needs from PHP/Querybuilder.
Set the cacheElementQueries config setting to false. Craft will no long attempt to record/bust template caches, so you can come up with your own logic for busting them (cron job, plugin, etc.).
Use a plugin like Cache Flag (or a similar one).  It also doesn't attempt to save element queries, but provides a way to bust caches based on keywords.


First I think it helps to clear up some terminology... I've seen a few devs (myself included sometimes!) using the word "hooks" when they really mean "events". For me at least this is a hangover from Craft 2 (and also ExpressionEngine), where "hooks" were used to inject custom back end code.
In Craft 3 however, everything is driven by events. Plugins/modules listen for these events and take action accordingly. ("Hooks" in Craft 3 are something different - more specifically, "Template Hooks" simply give you a chance to alter Craft's control panel templates and inject your own front end code).
Craft and the underlying Yii framework both fire hundreds of different events before and after every conceivable thing that happens, and likewise, plugins can do the same.
So to code a plugin/module that listens for events from Sprout Forms, you'd approach this in exactly the same way as a regular Craft plugin/module. Here's the general syntax for listening to Sprout's events: https://sprout.barrelstrengthdesign.com/docs/forms/events-and-hooks.html#events - in your case you'd probably want to listen for Sprout's EVENT_BEFORE_SAVE event and amend the POST data accordingly.


I have found that the best format for me is XML, it's easy to write and read. I've moved a number of EE2 sites to Craft by writing export templates using XML and importing into Craft with Feedme.
It's relatively simple, but can be tedious and time consuming as there are often tweaks needed either in the XML or the feedme settings.
I have a blog article I wrote a while ago that may help. Importing Entries into a Multi Lingual Craft CMS Website
I did not use the Smart Export Pro plugin but wrote my XML export templates by hand, I wasn't aware of that this existed.

I haven't used Content Elements but you say that it is similar to Craft Matrix so in that case I would look at the docs for importing into a Matrix field.https://docs.craftcms.com/feed-me/v4/guides/importing-into-matrix.html#setup-your-feed.
I have used this once to import into Craft 3 from a Craft 2 site with the code below. You should be able to use this as a model for your EE feed that you want to put into a Craft matrix. Below is the relevant bit from a larger feed.
    <recollection_asset_type_matrix>
      {% for block in entry.recollectionAssetType %}
        <matrix_block>
          {% switch block.type %}

            {# video #}
            {% case "video" %}
              <subtitle_file>{{ block.subtitleFile.first().url() }}</subtitle_file>
              <subtitle_label><![CDATA[{{ block.subtitleLabel }}]]></subtitle_label>
              <vimeo_url><![CDATA[{{ block.vimeoFilmURL }}]]></vimeo_url>
              <runtime><![CDATA[{{ block.runTime }}]]></runtime>
              <poster_image>{{ block.posterImage.first().url() }}</poster_image>

            {# picture gallery #}
            {% case "pictureGallery" %}
              <gallery_bg_image>{{ block.backgroundImage.first().url() }}</gallery_bg_image>
              <gallery_audio_file>{{ block.audioFile.first().url() }}</gallery_audio_file>
              <gallery_images>
                {% for image in block.images %}
                  <image>{{ image.url() }}</image>
                {% endfor %}
              </gallery_images>

            {# memoir #}
            {% case "memoir" %}
              <memoir_tagline><![CDATA[{{ block.tagline }}]]></memoir_tagline>
              <memoir_bg_image>{{ block.backgroundImage.first().url() }}</memoir_bg_image>
              <memoir_copy><![CDATA[{{ block.copy }}]]></memoir_copy>
              <memoir_audio_file>{{ block.audioFile.first().url() }}</memoir_audio_file>

          {% endswitch %}
        </matrix_block>
      {% endfor %}
    </recollection_asset_type_matrix>

Unfortunately this import is long done so I am unable to take screenshots of the feedme settings.


At first glance, it looks like a little conflict around absolute positioning

I've had good success in 'massaging' the Craft CP using: Craft CPCSS

See here for a little more, too: Remove outdent & indent from Redactor2 "lists" button

Hope it helps, Cole


Update fails: mod_fcgid: read data timeout

If running Webmin, check the Website Options under Server Configuration and set Maximum PHP script run time to unlimited or a largar value.

This is what finally did the trick but updating /etc/apache2/mods-available/fcgid.conf with the following values may have also played a role.

FcgidConnectTimeout 600
FcgidIOTimeout 600
IPCCommTimeout 600

After these changes and restarting apache, the script was finally able to finish and update the installation successfully.


As far as I know, the only fields that allow defaults are those that extend the BaseOptionsFieldType, namely Dropdown, Multiselect, Checkboxes, and RadioButtons. You could change your lightswitch to one of these other fieldtypes and have a default value available.


Hidden files are no longer accessible with AJAX in Craft 3

My guess is still: you did not define a route correct route for your template. You can check if you can access the file when you call the route normally via url www.example.com/blog/test if you can see the template, then it should usually work, if not you did not define any routing rules see here

However: when you do it that way everyone with the link may see this template and I expect it to look not very good without content since it's probably only a partial, so I would highly recommend you to use the proper way via controller.

public function actionRenderTemplate(){
    $response = [
        'success'   => false,
        'message'   => 'something went wrong'
    ];
    if($template = Craft::$app->getRequest()->getBodyParam('template')){
        try{
            $response['success'] = true;
            $response['html'] = Craft::$app->getView()->renderTemplate($template, [
                'foo' => Craft::$app->getRequest()->getBodyParam('just an example to pass values');
            ]);
        }catch(\Twig_Error_Loader $e){
            $response['message'] = $e->getMessage();
        }catch(\yii\base\Exception $e){
            $response['message'] = $e->getMessage();
        }
    }
    return $this->asJson($response);
}

And your javascript

$.ajax({
    type: "post",
    data: {
        action: 'plugin-handle/controller/render-template',
        template: 'path/to/template'
    },
    url: '',
    success: function (data) {
        if (data.success === true) {
            // do your stuff
            $('body').append(data.html);
        } else {
            // something went wrong
            // show a message or whatever
        }
    }
});

Edit
Please make sure you are in the correct folder for rendering your template, there is a difference between frontend and cp requests docs that's why we always build a custom template service that checks if there is a template in the normal path first and only takes the plugin template if there is none so we can overwrite plugin templates if needed and don't need to check/overwrite the paths every time


Craft 2.6 incorrect string value SQL error for 4 byte UTF-8 characters when saving entries

So it looks like our Craft site had an older version of the Dukt Twitter plugin installed. In a newer version it looks like the Twitter keywords have been handled better with:

return StringHelper::encodeMb4($keywords);

Which is similar to the same work done in the Craft core files for emojis.

https://github.com/craftcms/cms/issues/1627

Updating the plugin seems to have solved the issue saving on my local development environment, so not a direct answer, but a better solution than messing around with the the DB schema/collation.


How do I upload an asset in Craft 3, via PHP

I finally figured out how to upload an asset, however I still don't understand why the insertFileByLocalPath has been removed.

/**
 * @param UploadedFile $uploadedFile
 * @param int $folderId
 * @return Asset
 * @throws BadRequestHttpException
 * @throws UploadFailedException
 */
protected static function uploadNewAsset(UploadedFile $uploadedFile, $folderId) {

    if (empty($folderId)) {
        throw new BadRequestHttpException('No target destination provided for uploading');
    }

    if ($uploadedFile === null) {
        throw new BadRequestHttpException('No file was uploaded');
    }

    $assets = Craft::$app->getAssets();

    if ($uploadedFile->getHasError()) {
        throw new UploadFailedException($uploadedFile->error);
    }

    // Move the uploaded file to the temp folder
    if (($tempPath = $uploadedFile->saveAsTempFile()) === false) {
        throw new UploadFailedException(UPLOAD_ERR_CANT_WRITE);
    }

    if (empty($folderId)) {
        throw new BadRequestHttpException('The target destination provided for uploading is not valid');
    }

    $folder = $assets->findFolder(['id' => $folderId]);

    if (!$folder) {
        throw new BadRequestHttpException('The target folder provided for uploading is not valid');
    }

    // Check the permissions to upload in the resolved folder.
    $filename = Assets::prepareAssetName($uploadedFile->name);

    $asset = new Asset();
    $asset->tempFilePath = $tempPath;
    $asset->filename = $filename;
    $asset->newFolderId = $folder->id;
    $asset->volumeId = $folder->volumeId;
    $asset->avoidFilenameConflicts = true;
    $asset->setScenario(Asset::SCENARIO_CREATE);

    $result = Craft::$app->getElements()->saveElement($asset);

    return $asset;
}

and then in my controller I can simply use

$service->uploadImage(UploadedFile::getInstanceByName('photo'), 1);


Take a look at Craft's own UsersController->actionSaveUser().

You're probably looking for something closer to this:

$user = new craft\elements\User();

$user->firstName = $firstName;
$user->lastName = $lastName;
$user->username = $userName;
$user->email = $email;
$user->password = $password;

if ($user->validate(null, false)) {
    Craft::$app->getElements()->saveElement($user, false);
}


So looks like I was just missing the extra [] in the name.

fields[borough][]

Since categories are arrays the name also needed to be an array!


How to handle 'related' categories within import script

Sorted. This seems to work...

$catFieldRecord = FieldRecord::model()->findById(4);
$catFieldModel = FieldModel::populateModel($catFieldRecord);

craft()->relations->saveRelations($catFieldModel, $craftcat, $relatedcats);


Default Upload Location for asset fields on a User...?

Assuming you want the folders to be named after the users' IDs (since they won't change), the subpath should be {id}.


Deleting oldest 404 redirects task stalling

I found the table 'craft_tasks' in the database, there were actually over 5,000 tasks in here all run by Sprout Seo. I emptied the table which has cleared the tasks.

I will need to look into why these tasks are not running correctly on the clients server.


How can I fire a controller action for a particular route or entry?

It's more clear to me now that I've seen the database and extra description from the ticket.

The issue is that you've got an entry that already has has the URI of book.

Normally the code you're trying to use would work, but in resolving a route Craft matches any entry/category requests (Step 4) before it matches any dynamic routes (Step 5).

When you're testing the action URL directly in the browser that works because it hits step 2.

One way to pull off what you're looking for is to give your plugin a template hook.  Then from the template that loads when book is hit, you can do something like:

{% if craft.request.getSegment(1) == 'book' %}
    {% hook "myAwesomeHook" %}
{% endif %}


Craft on digital ocean Ubuntu: Craft can’t connect to the database with the credentials in craft/config/db.php

Could you post your nginx/apache configuration?

In short the configuration array key is matched based on the server name (server_name in nginx, ServerName in Apache httpd iirc).

If you're using some sort of default configuration it might not have a server_name, or a bogus one.

Thus, if your configuration array is like this:

<?php

return array(

  '1.2.3.4' => array(
    'someSetting' => 'foo'
  );
);

You should have a corresponding configuration in (nginx in this example):

server {
  listen 80;
  server_name 1.2.3.4;
  ....
}

If you have more than one host in server_name, Craft will match on the first.


{{ entry.postDate | date("M d, Y") }}

Inside the date filter, you use the date formatting values documented in the PHP date() documentation.

Also, see Craft's DateTime documentation, and the Twig date() filter documentation for more information on the topic.


Interesting problem! I took a stab at this, see if this works for your use case.
It relies on ImageMagick to check for the top left pixel color (0,0) after the image is uploaded (but will also work if you hit resave). (If you want to check the other 3 corners, you'll need more code but this should get you started.)
To use it, you'll need a lightswitch field called hasWhiteBackground on your asset volume (or change the name in the script).
The light switch gets switched to true if the top right corner of the image is white or transparent.
The "magic" is in the getImagePixelColor function.
Event::on(
    \craft\elements\Asset::class,
    \craft\elements\Asset::EVENT_BEFORE_SAVE,
    function(\craft\events\ModelEvent $event) {
            $asset = $event->sender;

    if ($asset->kind == 'image' ) {

        if  ($event->isNew) {

            $assetFilePath = $asset->tempFilePath;

        } else {

            $volumePath = $asset->getVolume()->settings['path'];
            $folderPath = '/' . $asset->getFolder()->path;
            $assetFilePath = Craft::getAlias($volumePath) . $folderPath . $asset->filename;

        }

        $img = new \Imagick($assetFilePath);
        $pixel = $img->getImagePixelColor(1, 1);
        $p = $pixel->getColor();

        if (($p['r'] == 255 && $p['g'] == 255 && $p['b'] == 255) || ($p['r'] == 0  && $p['g'] == 0 && $p['b'] == 0 && $p['a'] == 0)) {
            $asset->setFieldValue('hasWhiteBackground','1');

        }
    }

});


Without thinking about it too deeply, I think rather than sending the single bundle Id, you will probably want to use MultiAdd for this - https://github.com/verbb/multi-add - and basically set up a form that intercepts the user choices and translates those to the appropriate variant Ids for submission to Commerce.


How can I grant front-end access to an entry that belongs to the current user?

You can check if the current user can edit an entry by using this  as your conditional:

{% if entry.isEditable() %}
    Edit Page
{% endif %}


You might check out the routing docs on accessing subpatterns in your templates.

Here is the example given in the docs (which provides the variables 'year' and 'month' to the template that correspond to the matched uri segments — which would match `news/2015/02'):

'news/(?P<year>\d{4})/(?P<month>\d{2})' => 'news/_archive',

So I would presume you could do the same using your products (I'm terrible with regular expression though, so please check the match syntax).

'products/(?P<slug>[^/]+)/details' => 'products/_details',

Fyi, the variable is defined using (?P<name>...), where '...' is the pattern to match. So in this case the variable 'slug' (or whatever you defined it as in your regex pattern) should now be available as a variable in your template, which you can use to retrieve the entry.

{% set entry = craft.entries.section('mySectionHandle').slug(slug).first() %}
{% if entry %}
    {{ entry.title }}
    ...
{% endif %}

When you create the link to that page you would naturally want to include the slug:

View details

Untested.


Closure in plugin class/ saving and passing a public property

I figured that i could just use Craft::$app->getSession()->set( 'key', $value ); to store the vars in the craft session.

class somePlugin extends Plugin {

    public function init() {

        parent::init();
        self::$plugin = $this;

        Event::on( Order::class, Order::EVENT_BEFORE_COMPLETE_ORDER, function( Event $e ) {
            $order             = $e->sender;
            $order->customerId = $this->getCustomerId();
        } );
    }

    public function setUser( $userId ) {

        self::$plugin = $this;

        // get userModel by userId
        $userModel = Craft::$app->users->getUserById( $userId );

        // check if  commerce record for craft user exists
        if ( ! $this->customers->getCustomerByUserId( $userId ) ) {

            // create and save new customer
            $newCustomer       = new Customer();
            $newCustomer->user = $userModel;
            $this->customers->saveCustomer( $newCustomer, false );
        }

        // get and store customerId
        $customerId = $this->customers->getCustomerByUserId( $userId )->id;
        $this->setCustomerId( $customerId );

    }

    public function setCustomerId( $customerId ) {
        Craft::$app->getSession()->set( 'customerId', $customerId );
    }

    public function getCustomerId() {
        return Craft::$app->getSession()->get( 'customerId' );
    }
}


Plugin to "check/uncheck" all matrix blocks while editing entries?

There's a related feature request for this: "Expand/collapse all" UI for Matrix fields

In that feature request, Brandon Kelly explains how this is already supported (it works very well):

  There is a way to achieve this: Check one of the blocks, then hit
  Command + A to select all blocks. Then click the option button on any
  of the expanded blocks and click "Collapse" to collapse all blocks,
  and vise-versa to expand all blocks.


How can I pass a variable defined in a Controller to my variables?

The shortest answer is "that's not possible," and the slightly longer answer is "that's not possible because Controllers and Variables have no reason to ever interact." If your Controller relies on a Variable (or vice versa), something is architecturally incorrect. There's no reason for the two to cross paths.

The purpose of a Controller is to receive input from a form, AJAX call, or to be used as an API endpoint. It can also be used via routing to show a particular template under particular conditions.

The purpose of a Variable is simply to render a value in your Twig template.


How do I programmatically add assets to an assets fieldtype on a Matrix

This is totally untested but something like this could work (or at least give you some hints)

edit: since I was bored I tested the code.. it works

public function actionImport(){
    $jsonData = // getYouJsonDatasomehow here
    foreach($jsonData as $json){
        $entry = craft()->elements->getElementById($json['id']);
        /** @var \Craft\MatrixBlockModel[] $matrix */
        $matrix = $entry->Content->find();
        /** @var \Craft\MatrixBlockModel $block */
        foreach ($matrix as $block){
            // I pretend there is already the required block for the entry otherwise you have to create it

            if($block->getType()->handle === 'allImages'){
                // long version...
                $attributes = $block->getContent()->getAttributes();
                $attributes['images'] = $json['imageIds'];
                // some other changes if you want... title or whatever
                $block->getContent()->setAttributes($attributes);

                // short version would be
                $block->getContent()->setAttribute('images', $json['imageIds']);
                craft()->matrix->saveBlock($block);
            }
        }

    }
}

Since you did not say if the blocks/entries already exist or if the images even exist or if they have to be imported as well I decided to pretend everything is ready to use and your json images contain just an array of ids. If your images contains only local paths you would have to import them first with something like

$arrImages = [];
foreach($json['images'] as $image){
    $path = $image['path'];
    $name = $image['name'];

    $response = craft()->assets->insertFileByLocalPath(
        $yourFilePath,
        $nameOfImage,
        $folderId,
        AssetConflictResolution::Replace
    );

    if($newFildeId = $response->getResponseData()['fileId']){
        $arrImages[] = $newFildeId;
    }
}

$block->getContent()->setAttribute('images', $arrImages);


Is it possible to merge entry parameters to create a dynamic field handle?

The Twig attribute function solved this for me. Thanks to @tom-bauer

Revised Template Code:

{% set newsSectionIds = craft.entries.section('news').ids() %}
{% set pressSectionIds = craft.entries.section('press').ids() %}
{% set entryIds = newsSectionIds|merge(pressSectionIds) %}
{% set entries = craft.entries.id(entryIds) %}

{% for entry in entries %}

    {% set sectionMatrix = attribute(entry, "entryMatrix"~entry.section) %}

    {% for block in sectionMatrix %}

        {# my matrix code #}

    {% endfor %}

{% endfor %}


See the SQL query that gets executed when saving entry

If you add the devMode setting to your config, you should then be able to view the Javascript Console in your browser to see the SQL Queries being run.

In particular you're looking for the Profiling Summary Report.

Also, you can view the Craft Logs at /admin/utils/logs, when you are logged into the Control Panel.


Craft Commerce cart product as unique product with different notes

Line item options are built in and are designed exactly for this use-case:

https://docs.craftcms.com/commerce/v2/adding-to-and-updating-the-cart.html#line-item-options-and-notes


How to clear the database of unused fields?

You can get the fields that aren’t in use anywhere by running this SQL query:

SELECT f.*
FROM craft_fields f
LEFT JOIN craft_fieldlayoutfields l ON l.fieldId = f.id
WHERE l.id IS NULL

The easiest way to delete them would be from the Control Panel, but if you really want to limit your work to the database, you would need to delete those fields’ rows in craft_fields, and their corresponding column (“field_TheFieldHandle”) in craft_content. For Matrix fields, you would also need to drop the corresponding DB table (“craft_matrixcontent_TheFieldHandle”).


Matrix Gallery, with every image having it's own unique URL?

You can do this by creating a "single image" template, and point to that template with a URL GET variable containing the Asset ID, for example:

http://yoursite.com/gallery/single?assetId=234

First, create a template for your "single" image – e.g /templates/gallery/single.twig (I like to use the twig extension rather than .html, but its not important).

Add the following Twig code to your template – it will look at the current request query string for the assetId variable, and try to pull the relevant Asset:

{% set assetId = craft.request.getParam( 'assetId' ) %}
{% if assetId %}
{% set asset = craft.assets.id( assetId ).first() %}
{% endif %}

Then, you can easily output the image in whatever way you want, here's an example:

{% extends 'layouts/myGalleryTemplate' %}
{% block single %}
    {% if asset is defined %}

    {% else %}

The specified image could not be found

    {% endif %}
{% endblock %}


How should I organize/structure my channel sections?

Some of this depends on what the content is for each item. If all these pages are essentially the same sort of thing, but they differ in how you're categorising them - it's just one channel, and you can use Categories to organise them. Given that it seems you could categorise your content either by "production / development" and also by "Entity 1 / 2 / 3 / 4" it sounds like you may be better creating two Category Groups ("Entities" and "Status"), then creating a Category Field for each, which you add to your Entry Type.

There's not really enough to go on in terms of what content you have to advise much more clearly than that though.


If you look at the data file for a locale in Yii you can see that the territories property includes regions and continents as you've found. These all have keys with numeric values, whereas countries have two character keys. Using this knowledge, you can loop over the keys and values of the territories array as you are doing, but only output those with two character keys. You'll also probably want to omit the Unknown Region value which has a key of zz.

Untested, but this should work:

<select name="country" required>
    {% for key, value in craft.i18n.getLocaleData().getAllTerritories() %}
        {% if (key matches '/[a-z][a-z]/') and (key != 'zz') %}
            <option>{{ value }}</option>
        {% endif %}
    {% endfor %}
</select>

EDIT

OK, so my original idea doesn't work as craft.i18n.getLocaleData().getAllTerritories() doesn't preserve the territory array keys from the Yii i18n data files.

I'm not sure you can do what you want to do natively in Craft, but it looks like John D. Wells' Territories fieldtype plugin may provide what you need. You don't need to use the fieldtype as there is an undocumented Twig variable provided that gives you an array of localised territory names, excluding the regions. Try this:

<select name="country" required>
    {% for country in craft.territories.getTerritories() %}
        <option>{{ country }}</option>
    {% endfor %}
</select>


How to get section content from another site with multisite setting

From a template you could do:

{% set entries = craft.entries.section('jobs').site('siteA').all() %}

In your follow up comment, you're passing craft.entries as an element to relatedTo, but that's just going to be an instance of the ElementQuery class.  You need to give it the actual element you're interested in finding the relationship to.


Element API calling Module that integrates with third-party plugin

You have to use full namespaces in Element API because anything within those functions is out of scope. So you need to use the full path to the Google class.

$googleMaps = new \Vendor\Module\GoogleMapsApi();

Putting a "use" directive at the top of the file will not work.

I had the exact same problem and that resolved my issues immediately.


How do I add input a value to a Craft/Twig request?

You can't.

The Craft / Twig code runs server-side, before the page is delivered to the browser. The JavaScript runs client side, after the page is delivered to the browser.


Order Sprout Forms by field handle returns an error

It seams, that the columns for the form values are not part of the sql, that's why it never will work like this. Maybe it works in upcomming versions of the Sprout Forms plugin.

As a workaround you can use the SuperSort Plugin. With this plugin it's possible to sort your form entries like you need it.

Step 1 -> Download and Install SuperSort Plugin -> https://topshelfcraft.com/lagniappe/supersort
Step 2 -> Filter your form entries like this:

{% set formEntries = craft.sproutForms.entries.formHandle('contact')%}
{% set formEntriesSort = formEntries | supersort('sortAs', '{address | lower}') %}

{% for formEntry in formEntriesSort %}
   {{ formEntry.address }}<br>
{% endfor %}

Like this it should work!


Displaying an array returned from a hook

Template hooks are useful if you need to change the current twig context array somewhere inside of a template. If you make any changes to $context inside of your hook's function, those changes will be available after your hook tag.

If you just need to return some text or an array, a variable will do the trick just fine!


Using Yii CDbCriteria to query a table in a plugin

Try this (untested)

$criteria = 'cottage = :cottage and ((fromdate between :d1 and :d2) or(toDate between :d1 and :d2))';
$params = array('cottage' => $booking->cottage, 'd1' => $booking->fromDate, 'd2' => $booking->toDate);
$previousBookings = BookingEngine_BookingsRecord::model()->findAll($criteria, $params);


Yes, I believe this is perfectly acceptable. As long as you are not pretending to be Craft CMS or Pixel & Tonic, then you shouldn’t run into any legal issues.

They even made their brand assets available for use...

  https://craftcms.com/brand-assets

If you still have questions, send an email to support@craftcms.com.


Can't view image assets in web browser (403 error) after uploaded in Craft CMS Dashboard

Fixed the image issue. Such a simple oversite.

I just needed to change the Asset Source settings and change the URL to include :8888 since I was running a local build with MAMP Pro.


Craft 3: how can I set an ordered list of all sites, and set a display name different from the site name?

If you would use a custom plugin you can create this function in your (I know it's deprecated but I don't know a better name) PluginVariable

public function createSiteQuery(): Query
{
    return (new Query())
        ->select(['id', 'groupId', 'name', 'handle', 'language', 'primary', 'hasUrls', 'baseUrl', 'sortOrder'])
        ->from(['{{%sites}}']);
}

You can then use

{% set sites = craft.plugin-handle.createSiteQuery().orderby({'whatever': 'you want'}).all() %}

And attach as many parameters to the query as you like... If you would like to fetch only sites with a specific language you can do

{% set sites = craft.plugin-handle.createSiteQuery().where('language = "en"').all() %}

You have the full power of Yii2 Query class. You can group your sites as you like, change the order. You'll receive a single SiteRecord or multiple SiteRecords Class reference and you can display whatever information you like in the frontend.

You are free to change the site names in your frontend with a static array map in your php code as well. Create a map with siteHandle => "new display name" and do something like

{{ craft.plugin-handle.displayCustomSiteName(site.handle) }}


Return element criteria model from attribute of a model

If I'm following you correctly, seems like you could override your Model's getAttribute method to do something like this completely untested code:

public function getAttribute($name, $flattenValue = false)
{
    if ($name == 'location' && $flattenValue != false)
    {
        $criteria = craft()->elements->getCriteria('MyPlugin_MyElementType');
        $criteria->location = parent::getAttribute($name, $flattenValue);
        return $criteria;
    }

    return parent::getAttribute($name, $flattenValue);
}

If I'm not following you correctly, then that was pointless.


Need no search engine tracking option in Craft websites

If you're used to another CMS such as WordPress, you're probably used to using a Discourage search engines from indexing this site option. As Robin's answer mentions, the training wheels are off.

However, that doesn't mean you can't replicate WP's functionality.

When you tick that box, there's a few things that happen behind the scenes:

If robots.txt file is requested, WP auto generates a version that tells google to skip indexing the site.
A <meta name="robots" content="noindex,follow"> is added to each page.
XML-RPC pinging is disabled (so WP won't "ping" services like ping-o-matic when you update pages on the site).

Craft doesn't automatically ping any services so you don't have to worry about the last option but the first 2 are pretty straightforward to setup.

Global Lightswitch / templates

Create a Global called siteSettings and add a Lightswitch with a field handle of disableIndexing so you can reference throughout the site.

In the <head> section of your templates, it can be as simple as:

{% if siteSettings.disableIndexing %}
    <meta name="robots" content="noindex,follow">
{% endif %}

robots.txt

The second piece is some Craft magic. If you don't already have a robots.txt file, create one inside Craft's templates folder or remove it/move it if it exists in your public root folder.

Craft is smart enough to parse your robots.txt file as Twig code and even output the proper mime type. This allows you to dynamically change it as it is requested.

When robots.txt is requested, instead of serving the file directly as your web server would, Craft will instead take the request and because there is a file that matches robots.txt inside templates folder, it'll use it.

Put this in your robots.txt file:

User-agent: *
Disallow: {% if siteSettings.disableIndexing %}/{% endif %}

We're basically telling search engines not to index anything when the Lightswitch is ticked. That's a pretty basic robots.txt file but it gets the job done for this example. There's a ton more options.

Wrap up

That's really it.  The only thing to remember is to UNTICK the box when your site goes live or when you want search engines to revisit.

Lots of people in WP land get burned because they forget to turn it back on so this isn't really a great thing to do in the first place but this answer goes into some basic Craft concepts.

If you want more control, instead of a Global lightswitch, you could setup one up on a per entry basis much like Yoast does. This is pretty common for landing pages used for PPC so they don't get indexed to begin with. Just remember not to include them in your sitemap as well.  Also consider the SEOMatic plugin which can do all of this and more.


Cached entries and postDate / expirationDate

Currently, it will ignore them and will only invalidate according to any explicit parameters you've told it to.

However, I think it should take into account an entry's post and expiration date so I've added it to our todo list.


As you've discovered, you should be using the more generic elements.onBeforePerformAction or elements.onPerformAction events.  They get fired when any action takes place and you can check their action parameter to determine if it was a SetStatus action.


Got it:

"price": ' . $order->totalDiscount . ',

^^


Generate PDF's (Printmaker plugin) with a static header and footer

I've not yet tested specifically with Printmaker (only Laravel + Dompdf), but you should be able to add page numbers by using a special <script> block in the template you use for PDF rendering. This block's PHP instructions will be interpreted by Dompdf as it renders your document, so you can position additional elements like page numbers, headers/footers, etc.

Example of what you'd include in your Twig template:

<script type='text/php'>
if ( isset($pdf) ) {
    $font = $fontMetrics->get_font('Proxima Nova', 'normal');
    $size = 9;
    $y = $pdf->get_height() - 32;
    $x = ($pdf->get_width() / 2) - ($fontMetrics->get_text_width('1 of 1', $font, $size) / 2);
    $pdf->page_text($x, $y, '{PAGE_NUM} of {PAGE_COUNT}', $font, $size);
}
</script>

More on the subject where I first learned about it: https://stackoverflow.com/a/13184208/897279

CRITICAL POINT:

Ensure PHP is enabled in config/printmaker.php...

'isPhpEnabled' => true,


Solved it for now by making the file input hidden first and only changing its type attribute to file (using jquery) once the asset get’s deleted, ajax-style.


Query to find users who are in more than one user group

If you're looking for a SQL query (as opposed to an element query), then you can use this:
SELECT userId FROM craft_usergroups_users GROUP BY userId HAVING COUNT(*) > 1;

This only gets the userId.


Add new error to macro errorList - User Registration

I've done something similar recently... The errors returned by that macro are errors on the user model. Therefore, rather than creating errors on the user session, why not create them on the user model during registration and they'll automatically be available in the same macro...

Here's an example I'm using in a custom module to add extra validation to the user registration form:

// --------------------------------------------
// BEFORE SAVE USER ELEMENT EVENT. Add our own validation
// --------------------------------------------

use craft\elements\User as UserElement;
use craft\base\Element;
use craft\events\ModelEvent;

Event::on(
    UserElement::class,
    Element::EVENT_BEFORE_SAVE,
    function(ModelEvent $e) {
        if ($e->isNew && $e->sender instanceof \craft\elements\User) {
            $errors = false;
            if (!Craft::$app->request->post('firstName')){
                $e->sender->addError('firstName','First name is required');
                $errors = true;
            }
            if (!Craft::$app->request->post('lastName')){
                $e->sender->addError('lastName','Last name is required');
                $errors = true;
            }
            if (strlen(Craft::$app->request->post('fields.phoneNumber')) < 10) {
                $e->sender->addError('phoneNumber','Telephone number should be at least 10 characters long');
                $errors = true;
            }
            if (!is_numeric(Craft::$app->request->post('fields.phoneNumber'))) {
                $e->sender->addError('phoneNumber','Telephone number must be numeric');
                $errors = true;
            }
            if ($errors){
                $e->isValid = false;
            }
        }
    }
);

Then in your template you'd have something like this after every field (I tend to prefer includes over macros but macros would work fine too):

...

    Telephone number &bull;
    {# minlength is not supported in IE11 so add a server side check too #}
    <input minlength="10" required id="phoneNumber" type="tel" name="fields[phoneNumber]" value="{{ user is defined ? user.phoneNumber }}">
    {% if user is defined and user.getFirstError('phoneNumber') %}
        {% include '_partials/fieldErrors.twig' with { errors: user.getErrors('phoneNumber') } %}
    {% endif %}

...

### _partials/fieldErrors.twig:

{% if errors %}

        {% for error in errors %}

{{ error }}

        {% endfor %}

{% endif %}


In this case, since I happen to be dealing with reviews, The Star Reviews plugin calculates averages when new ratings are posted: https://www.doublesecretagency.com/plugins/star-ratings


Display images in Matrix block in grid view

{% for batch in block.images|batch(3) %}

  {% for image in batch %}

  {% endfor %}

{% endfor %}


Yes this is correct. The best documentation you can find is the source code, so looking at it is usually the way to go. Craft stores all relations with an array of element ids.

When you have a BaseRelationField in your elements field layout you'll store the value - even if it's a single value - like

$element->setFieldValue('day', [1]); //<- note, always pass an array

(or the faster variant)

$fieldsLocation = Craft::$app->getRequest()->getParam('fieldsLocation', 'fields');
$element->setFieldValuesFromRequest($fieldsLocation);

If you don't use a field layout and store your relations in a custom table/column you'll have to find a way that fits your requirements


Remove the last comma in an inline list of tags?

There's a couple of special variables available while for looping through an array. In your case I'd make use of loop.last.

{{ tag }}{{ not loop.last ? ', ' }}

This is the expression using the ternary operator to keep the syntax short.


Using Craft to render frontend pages in addition to using it headless

Absolutely! Craft works really well like this. You can use twig to render your website, then either element api or graph QL (built in to craft 3.3) to open up your data to other applications.

I run several sites like this where I’ve opened up various parts of the content for external use, e.g. the news feed for use in an app.


As documentation for Migrations is pretty slim, here is the working code:

<?php

namespace craft\contentmigrations;

use Craft;
use craft\db\Migration;

/**
 * m180428_195138_test migration.
 */
class m180428_195138_test extends Migration
{
    /**
     * @inheritdoc
     */
    public function safeUp()
    {

      if (is_null(Craft::$app->volumes->getVolumeByHandle("newvolume"))) {
        $volume = new \craft\volumes\Local([
          "name" => "New volume",
          "handle" => "newvolume",
          "hasUrls" => true,
          "url" => "@web/images/newvolume",
          "path" => "@webroot/images/newvolume"
        ]);

        $success = Craft::$app->volumes->saveVolume($volume);

      }

      if (is_null(Craft::$app->sections->getSectionByHandle("awesomeNews"))) {
        $section = new \craft\models\Section([
          "name" => "Awesome News",
          "handle" => "awesomeNews",
          "type" => \craft\models\Section::TYPE_CHANNEL,
          "siteSettings" => [
              new \craft\models\Section_SiteSettings([
                  "siteId" => Craft::$app->sites->getPrimarySite()->id,
                  "enabledByDefault" => true,
                  "hasUrls" => true,
                  "uriFormat" => "foo/{slug}",
                  "template" => "foo/_entry",
              ]),
          ]
        ]);

        $success = Craft::$app->sections->saveSection($section);

        $errors = $section->getErrors();
        foreach ($errors as $error) {
          echo $error[0];
        }

      }

      return $success;

    }

    /**
     * @inheritdoc
     */
    public function safeDown()
    {

      $newvolume = Craft::$app->volumes->getVolumeByHandle("newvolume");
      if (!is_null($newvolume)) {
        $success = Craft::$app->volumes->deleteVolumeById($newvolume->id);
      }

      $awesomeNews = Craft::$app->sections->getSectionByHandle("awesomeNews");
      if (!is_null($awesomeNews)) {
        $success = Craft::$app->sections->deleteSectionById($awesomeNews->id);
      }

      return $success;

    }

}

This includes the error checking when creating the new section and the save functions are assigned to a variable which are returned at the end.


It depends what you are most comfortable with. PHP and Apache are shipped with macOS by standard but you'd still need to install and configure MySQL (or MariaDB etc), along with manual virtual host configuration.

MAMP makes it much easier but sandboxing it all in one easy to install package with a GUI so if you're not comfortable with the command line and the manual configuration then it's a good option.

If you are a little comfortable with the command line and want a minimalist setup then Laravel Valet could be worth a try. It is a wrapper which orchestrates installing the required components via Homebrew which enables you to just create a new folder in your web root folder with a .dev extension and then be able to view it in the browser. This can be a nice in between.

For more of an isolation you can opt for virtual machines and Vagrant images for example which run a virtual OS with all pre-requisites installed. It can be a little resource hungry however. Alternatively there is docker which provides a containerised environment (much the same but without the full OS layer).

It really goes down to what you're more comfortable with but any of the above will get you up and running with Craft.


I ended up doing it like this:

'api/featured-apps.json' => [
  'elementType' => 'Entry',
  'criteria' => [
    'section' => 'apps',
    'appFeatured' => '1',
  ],
  'transformer' => function (EntryModel $entry) {
    $logos = [];
    foreach ($entry->appLogo as $image) {
      $logos[] = $image->url;
    }

    $videos = [];
    foreach ($entry->appVideo as $video) {
      $videos[] = $video->url;
    }

    return [
      'title' => $entry->title,
      'logo' => $logos,
      'video' => $videos,
    ];
  }
],


Best practice for volume aliases in config files

Ah, the power of commit history.

@brandon-kelly removed the volumes config section from the v3 docs back in February, mentioning

  Environment variables solve the same problem better.

So it seems that the best practice is to create volume aliases in config/general.php.


Craft's HttpSessionService is a thin wrapper for PHP's global $_SESSION variable.

You can use:

craft()->httpSession->add($key, $value)

and:

craft()->httpSession->get($key)

to save and retrieve values from it.


There's no photo attribute on the UserElementType, so you can't query by it like you're trying.

Completely untested, but you can probably work around that with something like this:

{% if geslacht_param_string !=''  %}

{% set queryParams = {
    search: {
        query: geslacht_param_string,
        attribute: 'geslacht'
    },
    geboortedatum : dateRange,
    order :'lastName',
} %}

{% else %}
    {% set queryParams = {
        geboortedatum : dateRange,
        order :'lastName',
    } %}
{% endif %}

{% set allUsers = craft.users(queryParams).find() %}

{% set usersWithPhotos = [] %}

{% for user in allUsers %}
    {% if user.photo %}
        {% set usersWithPhotos = usersWithPhotos|merge([user]) %}
    {% endif %}
{% endfor %}

There are {{ usersWithPhotos|length }} users with photos.


You could do this using the CP CSS plugin from Lindsey DiLoreto.

Install the plugin then add the following custom css:

#weekStartDay-field { display: none; }

Note that this will hide the field for all users, including you.


Set a lineItem option from within a plugin?

I'm guessing you're doing this in a plugin and not the front end using an input for a reason?

I struggled with this recently and had luck using the following:

// Get the line item from the event
$item = $event->params['lineItem'];

// We get all the options from the post request
$options = craft()->request->getPost('options', []);

// Add the new value
$options['optionKey'] = 'newValue';

// Save the options to the line item
$item->options = $options;

If somebody can suggest an improvement to this I'd be grateful.


create a fixed height and width for profile photos

Kind of.  They currently aren't technically true "Assets" like in the rest of Craft.

The most you can do is pass in a size to the method getPhotoUrl(45) and you'll get a 45 x 45 square result back.  I believe it will crop from the center only.

We have plans for Craft 3 so they'll be treated like 1st class Assets and you'll be able to perform transforms on them like any other Asset.


If I had to guess, MySQL has ran out of disk space on the volume that it's trying to write to.  Either that, or your host applies some artificial limit to the size of your MySQL databases that you're bumping up against.


Cannot remove index.php from URLs either

In this case, the Apache mod_rewrite module wasn't installed, so the <IfModule mod_rewrite.c> block of Craft's default .htaccess file was being skipped not allowing index.php to be rewritten in the URL.


I believe it's the quotes that is throwing it off. Try this:

{% set entries = craft.entries({
section: 'leads',
lastAssigned: now | date_modify("-3 days")
}) %}


status('disabled') should do the trick for you

{% set entries = craft.entries()
    .section('profileEntry')
    .status('disabled')
    .all() %}


How to get a list item  using a plain text field every time I hit enter

You'll want to split on the line breaks, then loop through the resulting array...

{% for ingredient in listOfIngredients|trim|split('\n') %}
    <li>{{ ingredient }}</li>
{% endfor %}


Records are definitely not the way to go with dealing with large amounts of data sets in the database.  There is just too much overheard associated with them.

Manually running SQL (as you've discovered) is an option, but if you wanted to do this from PHP, you could still use QueryBuilder.

$elementIds = craft()->db->createCommand()
            ->select('id')
            ->from('entries')
            ->where('sectionId = :sectionId', array(':sectionId' => 18))
            ->queryColumn();

$rowsAffected = craft()->db->createCommand()
            ->delete(
                'elements',
                array('in', 'id', $elementIds)
             );

The MySQL cascading deletes setup on the foreign keys should take care of cleaning up the necessary rows in the remaining tables automatically.


Sprig "Load more" not loading over https

Sprig will use whatever your site's base URL is set to, to construct the action URL. Ensure in Settings → Sites that the base URL is either set to an absolute path starting with https://, or if an alias or environment variable, that it is defined as an absolute path starting with https://.
Also be sure to either force the www subdomain or force a naked domain. in your example above I see one with and one without www.


Adding this from the comments above as a solution:

Try style="background-image:url({{ image.getURL() }})" instead, this means you would only overwrite the image and not any of the other background properties


How do I only display list of categories at certain level of parent category that have entries

If I understand your issue correctly, try changing

{% set topLevelCats = craft.categories.relatedTo({ sourceElement: entryIds }).group('filter').level(1) %}
{% set secondLevelCats = topLevelCats.slug(secondSeg) %}

to

{% set topLevelCats = craft.categories.relatedTo({ sourceElement: entryIds }).group('filter').level(1) %}
{% set secondLevelCats = craft.categories.slug(secondSeg).level(2) %}


Solspace Freeform upload multiple image files

There appears to be 2 errors in your code. name="uploadPhotos.handle[]" should be name="uploadPhotos[]", assuming your field name is uploadPhotos. The handle part is unnecessary, unless you were using it like name="{{ uploadPhotos.handle }}[]", but it's redundant since you already are calling the handle to get the handle (but makes more sense when you're automating the template code).

Secondly, you need to specify multiple attribute if you wish to have more than 1 file uploaded.

The correct code should be:

  Upload photos of the fault
  <input id="uploadPhotos" type="file" name="uploadPhotos[]" multiple />


Craft 3 Multi-site with no "default" site

This can be done in 3 main steps.

1. Get the site subdirectories working

First just get the /en/ and /es/ subdirectory working:

Create en/ and es/ subfolders in your webroot
Each subfolder should have its own index.php file and .htaccess file (if using Apache).
Assuming you used the craftcms/craft project as a starting point, update the define('CRAFT_BASE_PATH'... line in each of the index.php files to:

define('CRAFT_BASE_PATH', dirname(__DIR__, 2));

Update your English site’s Base URL to include the /en/.

At this point, if you point your browser directly to /en/, the English site should work as expected.

2. Create a redirect script in the webroot’s index.php

Create an index.php file in your webroot (alongside the en/ and es/ subfolders). This script will be responsible for redirecting the request to the correct subfolder, based on the requested URI and language.

<?php

// Bootstrap Craft -------------------------------------------------------------

// Set path constants
define('CRAFT_BASE_PATH', dirname(__DIR__));
define('CRAFT_VENDOR_PATH', CRAFT_BASE_PATH.'/vendor');

// Load Composer's autoloader
require_once CRAFT_VENDOR_PATH.'/autoload.php';

// Load dotenv?
if (file_exists(CRAFT_BASE_PATH.'/.env')) {
    (new Dotenv\Dotenv(CRAFT_BASE_PATH))->load();
}

// Load Craft (but don't run)
define('CRAFT_ENVIRONMENT', getenv('ENVIRONMENT') ?: 'production');
/** @var \craft\web\Application $app */
$app = require CRAFT_VENDOR_PATH.'/craftcms/cms/bootstrap/web.php';

// Custom Logic ----------------------------------------------------------------

// find a site language that matches the browser's requested language
$siteLanguages = $app->i18n->getSiteLocaleIds();
$language = $app->request->getPreferredLanguage($siteLanguages);

// find the first site that uses that language
foreach ($app->sites->getAllSites() as $site) {
    if ($site->language === $language) {
        // found it
        break;
    }
}

// figure out where to redirect this request now
$url = (function() use ($app, $site) {
    $uri = $app->request->getPathInfo();

    // see if we have an exact URI/language match
    if ($element = $app->elements->getElementByUri($uri, $site->id, true)) {
        return $element->getUrl();
    }

    // see if we have an exact URI match in any other site
    foreach ($app->sites->getAllSites() as $otherSite) {
        if ($otherSite !== $site) {
            if ($otherSiteElement = $app->elements->getElementByUri($uri, $otherSite->id, true)) {
                // found one! now see if the element is also available in the requested site
                if ($element = $otherSiteElement::find()->id($otherSiteElement->id)->siteId($site->id)->one()) {
                    return $element->getUrl();
                }
                // otherwise we'll just ignore the browser language
                return $otherSiteElement->getUrl();
            }
        }
    }

    // no element matches. we'll just redirect to the same URI in the requested site.
    return \craft\helpers\UrlHelper::siteUrl($uri, null, null, $site->id);
})();

// redirect to the URL
$app->response->redirect($url)->send();

With that in place, you should be able to start testing the redirects by pointing your browser to /index.php?p=some/uri.

3. Redirect nonlocalized requests to the webroot’s index.php

Finally, we want to get all requests that don’t start with en/ or es/ to be routed to an index.php file in your web root. If you’re using Apache, you can do that with mod_rewrite:

# Send requests missing en/ or es/ to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/(en|es) [NC]
RewriteRule (.+) index.php?p=$1 [QSA,L]

Now everything should work!


How to handle entry save in plugin when entryId is not set?

Had to browse through your plugin repo for a bit to try and wrap my head around what's going on, but I think you have the problem nailed down in that the issue is this: https://github.com/iNalgiev/webtexttool1/blob/1.0.0/WebtexttoolPlugin.php#L57

Trying to grab the entry ID from the cp.entries.edit.right-pane template hook for a new entry is going to return null because IDs aren't assigned until after the element is saved.

Off the top of my head, you've got two not-so-thought-out options.

Refactor your plugin logic so that the code that eventually calls your controller/service's saveRecord methods happen after the entry has been saved in onSaveEntry and you've got a valid entry ID.
Come up with some AJAXy way to calling Craft's saveEntry method from the cp.entries.edit.right-pane template hook that returns the entry ID so the rest of your logic can assume that the entry already exists.


How to export client-entered content for a specific channel to keep my local database in sync with staging

There's currently not an easy or clean answer for this.

There are some great answers here on different solutions for handling data syncing/migrations across multiple environments.

We've got some ideas of our own on how we'd like to make this less painful for users (it's a PITA for us as well), with syncing / importing / exporting data between Craft installs, but unfortunately we don't have an ETA on it.


I'll be the first to admit, I know nothing about snipcart so my answer could be way off.
Since your site works without snipcart, that means you are here:

Once the installation is completed, simply login into the Craft admin and go to Settings. You will have to create the fields that will be required to define a Snipcart product. In the settings, click on Fields and create 2 new fields:

Once you have those fields created, you will need to create a new section - which is a Channel

Name: Store
Handle: store
Section Type: Channel
Uncheck Entries in this section have their own URLs

Once you have that done, and the entry fields created/updated as they suggest, I think where you went wrong is with the actual layout.html file.

You need to include Snipcart’s JavaScript file and jQuery if it is not already included. Use the default CSS theme that you need to include as well.

What that is telling me is to open layout.html that I downloaded with snipcart and copy/paste all of the appropriate javascript into this file:
/path-to-your-project/craft/templates/_layout.html

That's the default layout template that Craft uses. So by pasting all of the necessary javascript & css into that file, each entry will have access to it.
Hope this helps!


Stalled / Stuck Task (GeneratePendingTransforms)

There is a support article about stuck tasks.

In your case I would take a look at your logs, especially the phplog.
You find them at: yourdomain.com/cp-path/utils/logs

https://craftcms.com/support/stuck-tasks


craft.matrixBlocks element queries with .type()

This was a bug in a beta version of Craft 3 (fixed here: https://github.com/craftcms/cms/commit/9b6dad7385c5a82d1c83d230fe6ce0cfe940675b)


Howard, craft itself doesn't break like that, in my experience.

set devMode true in config/general.php
try the url again, then look at the logs for craft and php, in craft/storage/runtime/logs
if you don't see anything, look at the php log on the server..

The clue should be there.


Look up a specific Variant, using the variant's ID?

You can use the recently documented template variable:

craft.commerce.variants.id(yourVariantId).first()

If you want to get a variant's product from the variant ID, you can use:

craft.commerce.products.hasVariant({id: yourVariantId}).first()

https://craftcommerce.com/docs/craft-commerce-products#hasvariant


How do I hook into Capture form onPost event?

I found the answer in a bit of a clumsy way, but the capture plugin has two services, capture_forms and capture_submissions. The first deals with saving the forms within the CraftCMS admin, the latter is for dealing with the form submissions.

I had to simply change my listener to craft()->on('capture_submissions.onPost', function(Event $event){...}); and I can see the event data.


Redirect all but certain requests to index

This will redirect all queries but urls containing:
api or robots or utm_source strings

return array(
   '^(?!.*(api|robots|utm_source)).*$' => ['template' => 'index']
);


Cached template content not invalidating

When new elements are created, there’s no way for Craft to immediately know which template caches should be cleared. That’s where the Delete Stale Template Caches task comes in. It loops through all of your caches that included element queries, re-runs the queries, and checks to see if the new element is now included in the results.

There are two things to be aware of, though:

Your element query must happen inside the {% cache %} tag pair.

bad:

{% set entries = craft.entries.section('news').limit(3) %}
{% cache %}
    {% for entry in entries %}
        ...
    {% endfor %}
{% endcache %}

good:

{% cache %}
    {% set entries = craft.entries.section('news').limit(3) %}
    {% for entry in entries %}
        ...
    {% endfor %}
{% endcache %}

The cache querying is not immediate. After saving the entry you will see a little progress bar in the CP header. You need to wait until that has completed before your caches will be cleared.


Entry Tracker to see who has completed the course

I'd add an Entries field in your User field layout called Articles Read or such. Then whenever they click that they've read a particular article, I'd add the id of article entry that they've read to that field.

I'd do that probably via a custom plugin, but you could also do it with a simple form that passes the correct data to the the actionUrl('users/save-user') UsersController


How do you debug problems with a migration?

Logs should be written to craft/storage/runtime/logs to help debug issues like this.  It gets a little sketchy with fatal errors, though.  Logs get flushed to disk when the onEndRequest event gets successfully fired.  If it's a fatal error that kills script execution, that event will never get fired and the logs don't get flushed.  That might have been what you're running into here.

Outside of that, to answer your original question, the absolute best way to debug stuff like this is with xDebug.  PhpStorm has a native xDebug client built in and it's pretty fantastic.


Accessing entries in a matrix field in plugin

I think I've figured out how to do this now (mainly through trial and error).
The code above should actually be like this:

foreach ($matrixBlocks as $block) {

    foreach ($block->blockContent as $blockContent) {
        ....
    }
    foreach ($block->blockDependency as $blockDependency){
        ....
    }
}

And the the $blockContent and $blockDependency variables will contain the entries required.


Change this:

$craftPath = './craft';

to this:

$craftPath = 'craft';


How do I build a LIKE query with DbCommand/Query Builder?

Just before posting the question, I had the good mind to read the Yii CDbCommand docs again, and I figured this out myself:

$query->orWhere(array(
    'like',
    'somecolumn',
    '%foo%'
));


Following the Digital download docs you may need the file path, so in order to get the file path in Enupal Snapshot you may need to return the asset model of the PDF:

{%  set settings = {
        filename: 'my-first-pdf.pdf',
        inline: false,
        asModel: true
    }
%}

{% set assetModel = craft.enupalsnapshot.displayTemplate("reports/pdf-report", settings) %}

{# Digital Download code #}
{% set token = craft.digitalDownload.createToken(assetModel, options) %}

{{ assetModel.filename}}


You can include the level

number {level} published in {postDate|date('F')} {postDate|date('Y')}


Front end Entry form with validation error support?

The saveEntry controller used by the default example returns an entry variable with the newly created item and the applicable error messages. This could be a potential cause of conflict if you have another variable called entry, which is by default pre-loaded in entry templates.

I think you could create a (for example) product.twig template and manually set an entry variable (via ID or slug) called anything else than entry.


Correct. It currently only allows for creating new entries, not editing existing ones.


How do you only show children of "active" parent in a Structure section's nav?

A recursive macro will help you get around the limitations of ifchildren (which P&T will hopefully resolve soon), as follows:

{% set mainEntry = craft.entries.slug(craft.request.getSegment(1)).first() %}
{% set subnav = craft.entries.descendantOf(mainEntry).level(2) %}

{% macro recursiveChildren(page) %}
  {% if page.hasDescendants and page.slug == craft.request.getSegment(page.level) %}

      {% for subpage in page.children %}

            {{ subpage.link }}
            {{ _self.recursiveChildren(subpage) }}

      {% endfor %}

  {% endif %}
{% endmacro %}

{% for page in subnav %}

    {{ page.link }}
    {{ _self.recursiveChildren(page) }}

{% endfor %}

More on macros here.


Add localised tracking codes for production environments

If people don't need to change these through the control panel, I would put them in the general.php config file.

Here's how I would do it:

return array(
  '*' => array (
    // default to not doing analytics
    'doAnalytics' => false,
    // all the analytics codes, by locale
    'gaCodes' => array(
      'fr_fr' => 'UAxxx',
      'en_us' => 'UAxxy'
    ),
  ),
  // CRAFT_ENVIRONMENT is set to one of 'LOCAL', 'STAGING', or 'PRODUCTION' in index.php
  'LOCAL' => array (
  ),
  'STAGING' => array (
  ),
  'PRODUCTION' => array (
    'doAnalytics' => true,
  ),
);

Then in your template:

{% if craft.config.doAnalytics %}
  ...{{ craft.config.gaCodes[craft.locale] }}...
{% endif %}

Here {% if ... %} tests if we want to do analytics, and {{ craft.config.gaCodes[craft.locale] }} pulls out the gaCode for the current locale.


For anyone from the future, this worked for me utilizing Ubuntu 16.0.4 with PHP7.2:

Try this command:

sudo phpenmod pdo_mysql

If it says it cant find the package, install this:

sudo apt-get install php7.2-mysql

Check your active php.ini file for this line(my active .ini was located n /etc/php/7.2/apache2/php.ini):

;extension=pdo_mysql

If it has a semicolon before it, remove it, and then save. For good measure, run this again:

sudo phpenmod pdo_mysql

Restart apache. Good day.


You can create 2 queries, first you pull all the channel entries, that are related to your bandCategory

$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->relatedTo = $bandCategory;
$criteria->section = 'channel';
$relatedChannelEntries = $criteria->ids();

// then continue your code
$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section = 'stories';
$criteria->search = $this->query;
$criteria->order = $this->orderSql();
$criteria->limit = 1000;
$criteria->visibility = $this->checkVisibility();
$criteria->thisIsAGuide = ':empty:';
// and search only for entries that are related to channel entries that are related to your band
$criteria->relatedTo = $relatedChannelEntries;


Search Between 2 Dates Venti Calendar Plugin

I managed to figure this out on my own.  There's a good chance this solution will work for searching for entries between custom date fields using Craft's standard entry system (not the Venti Plugin) as well.

 {% set start = craft.request.param('startMonth') %}
 {% set end = craft.request.param('endMonth') %}
 {% set entries = craft.venti.events.startDate('and', '>= ' ~ start|date('Y-m-d'), '<= ' ~ end|date('Y-m-d')) %}

 {% for entry in entries %}
      <p>{{ entry.title }}</p>
 {% endfor %}


It wasn't really clear to me if you want to list only those categories that are related to the current entry
or if you want a list of all categories that are assigned to your sermons.

I dont't think the group filter helps a lot in either case and I'd get the catgories like this.

{% set sermonCategories = entry.series %}

In case you don't want them to be ordered by your manual sort order, you need to
get them using a craft.categories ElementCriteriaModel.

{% set sermonCategories = craft.categories.relatedTo(entry).order('title') %}

To get all the categories you'd query for all of your "sermons" entries first.

{% set sermons = craft.entries.section('sermons') %}
{% set sermonCategories = craft.categories.relatedTo(sermons).order('title') %}

The you can start with your loop. I did some small changes, so that only categories with entries related to it will be shown.

{% for category in sermonCategories %}

    {% set relatedEntries = craft.entries.relatedTo(category) %}

    {# Only show category if there are related entries #}
    {% if relatedEntries|length %}

        {% set image = category.photos.first() %}
        {% set params = { width: 300, height: 200 } %}

        {# If a photo exists, show it, otherwise show a placeholder #}
        {% if image %}

        {% else %}

        {% endif %}

            {% for entry in relatedEntries %}

{{ entry.title }}

            {% endfor %}

    {% endif %}

{% endfor %}


Registration Form twig add to an usergroup

1) You can set the default user group through your admin:

2) Also I'm pretty sure <input type="hidden" name="userGroups" = "1"> needs to be set to <input type="hidden" name="userGroups" value="1"> for it to work but I'd need to test to be sure.


Display text field from Matrix of an Entry Field in Matrix

There's a couple of problems with your current code – for one, you're (as Brad mentions in the comments above) doing some variable overwriting by reusing the entry and block names. Also, you're attempting to do a for loop on the result from a call to first(), which won't work (first() returns a single element, not an array).

In any case, I'd suggest getting rid of all the for loops (you're looping on a resultset with a single element in each of your inner loops), in an attempt to make the code a tad more clear.

Something like this should work:

{% for entry in craft.entries.section('sectionHandle') %}
    {% set outerBlock = entry.matrixHandle.first() %}
    {% set outerBlockEntry = outerBlock ? outerBlock.entryFieldMatrixHandle.first() %}
    {% set innerBlock = outerBlockEntry ? outerBlockEntry.entrysMatrixHandle.first() %}
    {{ innerBlock ? innerBlock.fieldHandle }}
{% endfor %}

That's a lot of {% set %} statements, though – you could also do this (although I'm honestly not sure which option is more readable):

{% for entry in craft.entries.section('sectionHandle') %}
    {% set block = entry.matrixHandle.first().entryFieldMatrixHandle.first().entrysMatrixHandle.first()|default %}
    {{ block ? block.fieldHandle }}
{% endfor %}

Finally, as an alternative approach altogether you could use the relatedTo param:

{% for entry in craft.entries.section('sectionHandle') %}

    {% set block = craft.entries.relatedTo({
        sourceElement: entry.matrixHandle.first(),
        field: 'entryFieldMatrixHandle'
    }).first().entrysMatrixHandle.first()|default %}

    {{ block ? block.fieldHandle }}

{% endfor %}

None of the above examples are tested, and now my head hurts – but hopefully it'll prove helpful :)


Updating user profile matrix block with plugin

I believe this is the correct way to get an existing Matrix block. Found this gem after digging around in the Google group.

$block = craft()->matrix->getBlockById(blockId);

I updated my plugin code above to this and it seems to work properly.

// THIS DOESN'T WORK
// $block = new MatrixBlockModel($post['kidId']);

// THIS WORKS
$block = craft()->matrix->getBlockById($post['kidId']);

$block->fieldId    = $kidsMatrix->id; // Matrix field's ID, 'Kids'
$block->ownerId    = $currentUser->id; // ID of entry the block should be added to
$block->typeId     = $kidBlock->id; // ID of block type, 'kid'
$block->getContent()->setAttributes(array(
    'wooly' => $post['myWooly'],
));

$response = craft()->matrix->saveBlock($block);


Can't access Pending user's profile info

This works:

{% set user = craft.users.id(craft.request.lastSegment).status('pending').first() %}


Can I create a number with decimal point in number field?

As per the docs, there is a setting where you can specify how many decimal places are allowed. So yes, 7.5 can be represented in a number field.


That's because Craft doesn't do fuzzy searching by default.  You'd need to use the wildcard 'Peru*' to match 'Peruvian'.  You can see the full list of supported search syntaxes here: http://buildwithcraft.com/docs/searching

Related, you might want to vote for this feature request: http://feedback.buildwithcraft.com/forums/285221-feature-requests/suggestions/8459443-add-option-to-enable-fuzzy-search-as-default

Update:
As of Craft 2.5, you can enable fuzzy searching by default.


Upload assets to location based on category if entry isn't saved yet?

I've ran into something similar, although it was using the entry ID. If you set the category and save the entry, and then upload an asset to that field on the entry does it save into the location you have set?

Also if the assets field is within a matrix you'll need to use owner

{owner.galleryCategory.first.slug}


Redirect to template from controller and pass data

You could do this by saving the email address to a custom session variable like this in your controller:

Craft::$app->getSession()->set('email', $email);

This should then be available in your template using:

{{ set email = craft.app.session.get('email') }}


Some (but not all) controller action routes return 404 on staging server

I figured this one out, it was bad error handling on my part.

If the service you're calling returns NULL, this will appear in the network tab as a 404.


Just create translations/en/app.php directory of your Craft installation with the following content (replace en with the desired language code):
<?php return [
    'Settings' => ' Params',
];

Craft updates won't touch it.


myFieldHandle error in Craft using Smart Map

The example of myFieldHandle is just a placeholder for your actual field handle.
So if your Address field has a handle of address, it would look something like this...
{% set entries = craft.entries.section('contractors').address(params).orderBy('distance') %}


This doesn't work out of the box with Craft as the category field is a relation field.

However you should be able to use SuperSort plugin.

{% set products = craft.commerce.products.type('coins').limit(null) %}
{% set orderedProducts = products | supersort('sortAs', '{stateCat.first.stateImportance}' %}


Order confirmation emails not being sent to guests

Fixed by updating to 1.2.1350

https://craftcommerce.com/changelog#build1350


From your code sample it looks like you may be using Blitz to cache the page, in which case this is likely neither a Sprig issue nor a Snaptcha issue. A CSRF token is a dynamic token which should not be statically cached. You would normally use the {{ craft.blitz.csrfInput() }} tag but since you are using Sprig, I'd recommend you look into implementing the dynamic content example instead of using the craft.blitz tags.
As an aside for future reference, you'll get better support if you can post an issue in the appropriate Github repository along with code samples and the specific version numbers of the plugins in question.