Setting a conditional for username in URL?

If you're looking for the current (logged in) user, you should use the global variable currentUser.

{% if currentUser %}
    {# currentUser returns a User Model if there is one, so do with it whatever you like #}
{% endif %}

However, if you want to find a user through a URL segment, you might want to get into using routes. If you use advanced routing, you can get what (I think) you want by adding following to your craft/config/routes.php:

return array(
    '(?P<category>[^/\]+)/(?P<user>[^/\]+)/' => 'path/to/template',
)

In your template, you can then use the variables {{ category }} and {{ user }}. Don't hang me on the RegExp-pattern, this is not tested but should get you further.


To add to Matt's answer there are example templates which contain enough code to get you started in the templates folder craft/templates.

There is also a repo on Github called 'HappyLager' which contains more example templates along with annotations.


Just found the trick: When you access an object in array style, you can test via is defined

e.g.

{{ object['property'] is defined ? 'defined' : 'not defined' }}

and you will get reliable results.


Not really feasible without a plugin – fortunately, there's the excellent SuperSort:

{% set results =  craft.entries.section('player').search('team:"thenameoftheteam"') %}

{% set resultsByPlayerPosition = entries|supersort('sortAs', '{playerPosition}') %}
{% set resultsByPlayerHeight = entries|supersort('sortAs', '{playerHeight}') %}
{% set resultsByPlayerBirth = entries|supersort('sortAs', '{playerBirth}') %}

If you need the sorted results in the opposite order, you can just apply the |reverse filter, i.e.

{% set resultsByPlayerHeight = entries|supersort('sortAs', '{playerHeight}')|reverse %}

If e.g. playerPosition is a relational field (a category, perhaps), you'll need to do something like this:

{% set resultsByPlayerPosition = entries|supersort('sortAs', '{{ playerPosition.first.title }}') %}


Updated Information Requested | Craft CMS & MariaDB

We currently have no open tickets or known issues with MariaDB.

Fun fact: according to our logs roughly 15% of Craft installs are running some version of MariaDB.


Error: file_put_contents(/var/www/html/craftcms/composer.lock): failed to open stream: Permission denied

Whatever user:group PHP is running as on your server doesn't have the permissions to write to /car/www/html/craftcms

  It also looks like Craft didn't take a backup, as my most recent backup is from RC4, back in January.

Craft will only do a backup during updating if mysqldump or pg_dump is available to PHP (by default), or if your custom backupCommand config setting executes successfully.

If Craft can't make a backup during updating, it will halt the update process and prompt you asking what you'd like to do with one of the options being to continue without making a backup.

  I'm not sure how to recover from this,

To restore the Craft files to the previous version, you can open your project's composer.json file, find the craftcms/cms line, set the version to the pre-update attempt version, then run composer update from the command line.

If there were no database migrations that ran during the update attempt, that should be all you need to do.

If there were database migrations that ran, you'll probably get an message when you try to access the Control Panel saying that you can't backtrack to that version of Craft because now the database is out of sync with the files.

The only practical way around that is to restore from a pre-update attempt database backup.


Display categories not related to an entry

You can grab all ids and exclude them from your query

{% set excludeIds = craft.categories.group('services').relatedTo(entry).ids() %}
{% for category in craft.categories.where(['!=', 'elements.id', excludeIds]).all() %}

If your relation field is in your entry you can do

{% set categories = craft
    .categories
    .section('services')
    .where(['!=', 'elements.id', entry.category.ids()])
    .all()
%}


Sort / Order Entries on select or button click

Okay so you can either do this through ajax or through a page reload, a page reload is going to be much easier, but you can get it to work without reloading the page...

Reloading the page

You can basically make it so that when a user selects an option, use jQuery to redirect to the current page and append the <option> value to append as a query string, so your template could look like this:

<select id="sortQuery">
 <option value="postDate asc">New - Old</option>
 <option value="postDate desc">Old - New</option>
 <option value="title asc">A-Z</option>
 <option value="title desc">Z-A</option>
</select>

Then, you can do this in your template:

{% set orderJs %}
  $(function(){

    $('#sortQuery').on("change", function(e){

     // Get the value from the select
     var filter = $(this).val();

     // We can use twig because we are setting this in template, if you extracted this to its own file, you would need a different means to output the page url
     document.location.href = '{{ craft.request.getUrl() }}?order=' + filter;

   });

  });
{% endset %}

{# let craft include the script to the end of our template #}
{% includeJs orderJs %}

Then, in your template file your code could be:

{% set counter = 0 %}

{# Either get the order from the query or use a default #}
{% set order = craft.request.getParam('order', 'title asc')  %}

{% for entry in craft.entries.section('tips').order(order) %}
  {% set counter = counter + 1 %}
  {% include 'includes/tip-blocks' %}
{% endfor %}

This should then reload the request with the query string, craft will see it and update the response accordingly. I must stress this is untested, but it should work...

Without reloading the page

This gets a little more complex and would involve more jQuery/Javascript than craft so I won't go into too much detail about it.

The steps are pretty much the same as above, except within the script tags (where you listen for a select change) you would make an ajax request to either a html template (which contains the sorted results) or even using the ElementApi plugin to return json (from a template) which you can then iterate over in jQuery and then update your DOM accordingly.

I hope this helps get you on track!


Module Development - Get ID of a field within a Matrix field

You'll need to loop through the fields in the blocktype definition for your Matrix field. For simplicities sake, I've supplied a loop, which you can cut-down if you have a specific block type in mind you just want to fetch for:

$matrixField = Craft::$app->getFields()->getFieldByHandle('myMatrixFieldHandle');

foreach ($matrixField->getBlockTypes() as $key => $blockType) {
    Craft::dump($blockType->name);

    foreach ($blockType->getFields() as $key => $field) {
        Craft::dump($field->name);
    }
}


It depends on the underlying MySQL collation of the database and the tables Craft is searching against.  The MySQL 5.1 rules surrounding this can be found here: https://dev.mysql.com/doc/refman/5.1/en/case-sensitivity.html

There isn't anything in Craft where you can toggle the case sensitivity of searches.

Update:

Turns out I was completely wrong on this. Case sensitive searches would rely on the database's underlying collation if Craft didn't normalize all search keywords to lowercase first.


Try this:

{% set entriesInYear = craft.entries
    .section('agenda')
    .limit(null)
    . dateAndTime([
        'and',
        '>=' ~ year,
        '<' ~ (year + 1)
    ])
    .all()
%}

The .before() and .after() methods are convenience methods that hide the complexity of the date query on Craft's postDate field. They don't affect any other custom date fields like your dateAndTime field.

The array for your dateAndTime field condition (in the above example) is more of a Yii Framework query thing where the optional 'and' operator in the first position means all of the following conditions must apply. If omitted, it's assumed to be 'or'.

If you prefer, the array can also be expressed as a string of comma-separated conditions like so:

.dateAndTime('and, >= ' ~ year ~ ', < ' ~ (year + 1))


Pulling images from other sections with image transform

Try the following, it should do what you are after.

{#
  Generate array of entries comprised of first
  entry from each section
#}
{% set entries = [
  craft.entries.section('news').first(),
  craft.entries.section('other_section').first(),
  craft.entries.section('yet_another_section').first()
] %}

{# Loop through entry array #}
{% for entry in entries %}
  {% if entry.bannerSlider|length %}
    {% set image = entry.bannerSlider.first() %}
    {% set transformedImage = craft.imager.transformImage(image, { width: 1420, height: 550, position: image.focalPoint,  effects: { grayscale: true, gamma: 1.5}, }) %}

  {% endif %}
{% endfor %}


Only the /app folder matters.

No other files are relevant to the Craft core operations. Make sure you replace the folder entirely, don't let the new files get merged with the old files.

Nothing else will be changed. If the update would trigger any database changes, those will be handled automatically by migrations (located in the app/migrations folder).

For more information, see the documentation on Manually Updating.


Search for assets containing a custom field

Caveat: This is totally untested, and could be nonsense. I'm sure you'll let me know. It assumes that the Craft element query methods can be used here.
If you have a 'lang' value, add a where to your basic assets element query
    {% set folderId = craft.app.request.getQueryParam('folderId') %}
    {% set query = craft.app.request.getQueryParam('q') %}
    {% set lang = craft.app.request.getQueryParam('lang') %}

    {# Search for assets in the downloads folder #}
    {% set assetsQuery = craft.assets().volume('downloads') %}
    {% set assetsQuery = assets.folderId(folderId).includeSubFolders() %}

    {# If there's a lang value, add a where to the element query #}
    {% if lang is not empty %}
    {%     set assetsQuery = assetsQuery.where(expression('[[field_lang]] = :lang', {lang: lang})) %}
    {% endif %}

    {% set searchQuery = [] %}

    {# Check if a query was supplied, if so then search for it. #}
    {% if query is not empty %}
    {%     set searchQuery = searchQuery|merge({query: query}) %}
    {% endif %}

    {% paginate assetsQuery.search(searchQuery).limit(10) as pageInfo, pageEntries %}

*Note that I've changed the variable 'assets' to 'assetsQuery'


Check if a value exists in a Matrix field

You can check if certain elements match for your Query via exists()

entry.floors.type('floor').floorNumber(1).exists()

returns true or false. However keep in mind entry.floors returns an element of type Query and you'll append the parameters type and floorNumber to the Query. These properties won't reset magically since you call the object by reference and not by value thus you'll either need to reset them

{% do entry.floors.type(null).floorNumber(null) %}

or you don't use the object directly and clone/copy it instead

{% set exists = clone(entry.floors).type('floor').floorNumber(1).exists() %}


{% block content %} is a no-go in template/subfolders

In this case, it was just human error and ignorance of how hidden template files work through the CMS.

I believed that I should be able to call the hidden file in the browser, via something like "base_url/subfolder/_hiddenfile.html" and partially I was able. For whatever reason, using this primitive test method, I was able to see the header and footer, but not the block content, in the browser window.

The fact is, what I was doing was not a viable test. I don't understand why, but that doesn't matter.


Plugin to create an image transformation for an external image (non-Assets field)

The ImagesService's loadImage() method is designed to read image files off of the local file system only, not URLs – hence the appropriate error message; Craft treats your URL as a local filepath and that file obviously doesn't exist.

To apply transforms to an image on a remote host, you'll have to jump through a few hoops. First, you'll need to download the image from the remote URL to your local server – the easiest way to do this is using PHP´s file_get_contents method – before creating and storing the image file (the best way to do that is by using the IOHelper class' createFile and storeFile methods). At that point you'll have an image file on the local filesystem and a valid filepath to use for the ImageService in order to apply your transform.

Along the way, you'll need to take care to retain the remote image file's extension (i.e. jpg, gif, png or the like), construct valid filepaths for the downloaded image and the transformed image(s), handle caching for the external file (avoiding a situation where you'll have the server downloading the remote image on every pageload), testing for existing transforms (to avoid needlessly re-transforming the image on every pageload) etc.

My advice: Unless you absolutely need to (or want to) write your own plugin, you should use the excellent Imager plugin – which is able to transform images from external hosts (i.e. URLs) out of the box. Here's how you could use Imager in your template:

{% set thumb = {
    mode: 'crop',
    width: 100,
    height: 100,
    quality: 75,
    position: 'top-center'
} %}
{% set image = craft.imager.transformImage('http://thoughtfulweb.com/images/_halfPageStandard/Thoughtful-Indiana-Jones.jpg', thumb) %}
{% if image %}
<img src="{{ image.url }}" />
{% endif %}


Catch-all routes based on template structure

What we often do for a section (lets call it Pages) is actually not use any custom routing, and control things in the templates.

Start by setting the section template to pages/index. In your index.html file, we usually have the following:

{# Look for a template for this entry type (if any), then look for a template matching #}
{# the entry's slug, and fallback to the default '_entry' template #}

{% include [
    'pages/' ~ entry.type,
    'pages/' ~ entry.slug,
    'pages/_entry'
] %}

Using Twig's array-style include means it'll look for templates, and if one doesn't exist, move onto the next. In this scenario, we can simply create a file for an entry type, or even for a specific slug, with a fallback to a default.

Your case might be different of course, but might be a step in the right direction.


This should do what you're looking for:

{% set closed = true %}

{% for dayOfWeek in theCenter.openWeekDay %}

    {% if 'now'|date('N') == dayOfWeek and 'now'|date('Hi', 'America/Denver') > theCenter.openTime|date('Hi') and 'now'|date('Hi', 'America/Denver') < theCenter.closeTime|date('Hi') %}
        {% set closed = false %}
    {% endif %}

{% endfor %}

{% if closed %}

The center is CLOSED

{% else %}

The center is OPEN

{% endif %}


Entry Form - Multiple Entries & Entry Type & Parent

A little bit late but here it is.

Go to https://pluginfactory.io/ and create a plugin, you need at least 1 Controller but you can leave the Name value blank to create a controller with the same Name as your PluginHandle. So if you choose "Experiment" as your Pluginhandle your controller will be ExperimentController
Click on "Build my Plugin" and save the files in your craft/plugins/>>pluginhandle<< folder (of course you need to create the >>pluginhandle<< directory eg.) Then you should install the plugin
Insert this function in your controller. Note: this is just an example. I don't know your fieldLayout or some special behaviors you might want to include. So this is just the basic logic with some error handling. Important please read the commands and change the entryType Ids

     /**
     * @var    bool|array Allows anonymous access to this controller's actions.
     * @access protected
     */
    protected $allowAnonymous = true;

    /**
     * @throws Exception
     */
    public function actionSaveEntry(){
        $this->requirePostRequest();
        // check for an Id if there is one we update an existing entry if not we create a new one
        if($entryId = craft()->request->getParam('entryId')){
            if(!$entry = craft()->elements->getElementById($entryId)){
                throw new Exception('Could not find entry with id');
            }
        }else{
            $entry = new EntryModel();
            $entry->typeId = craft()->request->getParam('entryType');
            $entry->sectionId = craft()->request->getParam('sectionId');
        }

        // set the content of your entry/experiment
        $entryData = craft()->request->getParam('experiment');
        $entry->getContent()->setAttributes($entryData['fields']);

        // try to save the entry
        if(craft()->entries->saveEntry($entry)){
            // fetch the id from the experiment so we can use that as a parentId for the cage
            $entryId = $entry->id;
            // if everything is alright we can save the cage like we did it with the experiment
            if($cagesData = craft()->request->getParam('cage')){

                foreach ($cagesData as $cageData){
                    // like with the entry check for an Id
                    if($cageId = $cageData['entryId']){
                        if(!$cage = craft()->elements->getElementById($cageId)){
                            throw new Exception('Could not find cage with the given Id');
                        }
                    }else{
                        $cage = new EntryModel();
                        $cage->typeId = 5; // you could as well create a hidden field like for the entry itself but you must change the typeId to your entryType Id
                        $cage->sectionId = craft()->request->getParam('sectionId');
                    }

                    // save the content as well
                    $cage->getContent()->setAttributes($cageData['fields']);
                    // and set the parent
                    $cage->parentId = $entryId;
                    if(craft()->entries->saveEntry($cage)){
                        $cageId = $cage->id;
                        // and now we are going to do the same with the animals
                        if($rodentsData = $cageData['rodents']) {
                            $rodentErrors = [];
                            foreach ($rodentsData as $rodentData){
                                // like with the entry check for an Id
                                if (array_key_exists('entryId', $rodentData) && $rodentId = $rodentData['entryId']) {
                                    if (!$rodent = craft()->elements->getElementById($rodentId)) {
                                        throw new Exception('Could not find rodent with the given Id');
                                    }
                                } else {
                                    $rodent = new EntryModel();
                                    $rodent->typeId = 6; // change your entryType Id here
                                    $rodent->sectionId = craft()->request->getParam('sectionId');
                                }

                                $rodent->getContent()->setAttributes($rodentData['fields']);
                                $rodent->parentId = $cageId;
                                if (!craft()->entries->saveEntry($rodent)) {
                                    // important note: if there are any errors here, the cage and the experiment is
                                    // saved anyway so you should insert the id of the experiment to the form in order
                                    // to update the form instead of creating a new one again and again
                                    // if the experiment has an Id but the cage/rodent not you'll just update the experiment
                                    // and create new cages/rodents for it
                                    $rodentErrors[] = $rodent->getErrors();
                                }else{
                                    $rodentErrors = [];
                                }
                            }
                            // include errors of each item
                            craft()->urlManager->setRouteVariables(array(
                                'rodentErrors' => $rodentErrors
                            ));
                        }
                    }else{
                        craft()->urlManager->setRouteVariables(array(
                            'cageErrors' => $cage->getErrors()
                        ));
                    }
                }

            }
        }else{
            // handle your errors here.. you can use $entry->getErrors()
            // return them to your frontend and render them in twig or something
            craft()->urlManager->setRouteVariables(array(
                'experimentErrors' => $entry->getErrors()
            ));
        }
    }

Your html template. Note I don't know your fieldLayout so I just included the title and the craft default body field. In order to add your custom fields to the html you need to set the input name to entryType[fields][fieldHandle] so if you want to add a field with the handle foo to the cage you would name it cage[fields][foo]. As for the routing: your action must be pluginHandle/functionName

<form method="post" accept-charset="UTF-8">
    {{ getCsrfInput() }}
    {# your plugin name and function name #}
    <input type="hidden" name="action" value="test/saveEntry">
    {# the id of your section for me its 4 you need to change this value to your section Id #}
    <input type="hidden" name="sectionId" value="4">
    {# enable the entry #}
    <input type="hidden" name="enabled" value="1">
    {# id of your entry leave it blank to insert a new entry, insert a id to change an existing entry#}
    <input type="hidden" name="entryId" value="">
    {# the id of your experiments entryType for me its 4 you need to change this value #}
    <input type="hidden" name="entryType" value="4">

    Title
    <input id="title" type="text" name="experiment[fields][title]">
    <input  type="text" name="experiment[fields][body]">

    {# now the cage as a children #}

        cage title
        <input type="text" name="cage[0][fields][title]">
        <input type="text" name="cage[0][fields][body]">
        <input type="hidden" name="cage[0][entryId]" value="">
        {# and some Rodents as children for the cages #}

            Rodent title
            <input type="text" name="cage[0][rodents][0][fields][title]">
            <input type="text" name="cage[0][rodents][0][fields][body]">
            <input type="hidden" name="cage[0][rodents][0][entryId]" value="">

            Rodent title
            <input type="text" name="cage[0][rodents][1][fields][title]">
            <input type="text" name="cage[0][rodents][1][fields][body]">
            <input type="hidden" name="cage[0][rodents][1][entryId]" value="">

            Rodent title
            <input type="text" name="cage[0][rodents][2][fields][title]">
            <input type="text" name="cage[0][rodents][2][fields][body]">
            <input type="hidden" name="cage[0][rodents][2][entryId]" value="">

    {# and another cage #}

        cage title
        <input type="text" name="cage[1][fields][title]">
        <input type="text" name="cage[1][fields][body]">
        <input type="hidden" name="cage[1][entryId]" value="">
        {# and some Rodents as children for the cages #}

            Rodent title
            <input type="text" name="cage[1][rodents][0][fields][title]">
            <input type="text" name="cage[1][rodents][0][fields][body]">
            <input type="hidden" name="cage[1][rodents][0][entryId]" value="">

    <input type="submit" value="Publish">

{# just as an example how you could display errors or at least receive the error object #}
{% if rodentErrors is defined %}
    {% for errors in rodentErrors %}
        {% for fieldHandle, errorMessages in errors  %}
            {{ fieldHandle }} {{ errorMessages[0] }}

        {% endfor %}
    {% endfor %}
{% endif %}

Please let me know when you need help and feel free to ask what you like.
If done right, you'll end up with a structure like this with your form (note: please ignore the titles...)


Is it possible to assign fields to entries by category?

Could you use the entry types to achieve the same thing?
https://buildwithcraft.com/features/entry-types


{% if loop.first %} and {{ loop.index0 }} not working with Matrix

At the moment loop.first and loop.index0 are relative to your block.image loop.

If you want them to be set based on your entry.locationSlideshow loop (the parent loop) you can use {{ loop.parent.loop.index0 }} and {{ loop.parent.loop.first }}

For more information see the Twig documentation.


Example using build-in functions (sure, not the best ;-) ).

Supposing that number is our number:

{% set result = 0 %}
{% if number / number|round == 1 %}
    {% set result = 1 %}
    {% if number > 3 %}
        {% for i in 2..number-1 if result == 1 %}
            {% if number is divisibleby(i) %}
                {% set result = 2 %}
            {% endif %}
        {% endfor %}
    {% endif %}
{% endif %}

Now, result equals to:

0, if number is not integer
1, if number is prime
2, if number is composite


Outputting Sprout Form from a matrix field

Sure, you'll likely want to use:

{% for block in entry.pageBody %}
    {% if block.type == 'form' %}
        {{ craft.sproutForms.displayForm(block.form.first.handle) }}
    {% endif %}
{% endif %}


How to deploy website from dev to staging from localhost to remote server using composer

There is a course on CraftQuest regarding deployment of Craft CMS you might want to check out: https://craftquest.io/courses/deploying-craft-cms-3

For my personal workflow, I develop locally then push my codebase to Github. Since my servers are built using Laravel Forge, I have it set up to deploy my code to my server, which can be an AWS server, Digital Ocean, or any number of places.

For some sites, I use a more robust deployment service. I've used both Envoyer.io and Deploybot to do that. I wrote a post on the Deploybot set up I used. You can find that post here: https://supergeekery.com/blog/laravel-forge-and-deploy-bot


Commerce new order error : mail::getRenderLanguage() must be of the type string

I think I figured out the problem. This was my first time switching to the project.yaml configuration Deleting and rebuilding the project config allowed me to change the Commerce > System Settings > Email > Language which fixed the error.


How to filter entries by clicking multiple categories on front end

First, I would use something like training in your query string. It's a little more readable and you aren't searching for the words lunge and dumbbell anywhere in those entries, just entries related to those category slugs.

{# First you would find any training categories in the URL query string. #}
{% set trainingQuery = craft.request.getParam('training') %}

{# Then find categories that match the slugs in your query string. #}
{% set trainingCategories = craft.categories.group('trainingCategoryGroup').slug(trainingQuery) %}

{# setup your search parameters #}
{% set searchParams = {
  relatedTo:  trainingCategories,
  section: 'exercisesDb'
} %}

{# Find your entries #}
{% set entries = craft.entries(searchParams).order('score') %}

Your search form just needs to have the checkbox's input name as training[]. If it's on the same page, test to see if the category slug is in the trainingQuery array so it can be marked as checked or not.
Create this by finding all the categories in the trainingCategoryGroup group.

<form action="http://www.website.com/training/exercise-list">

  {% for category in craft.categories.group('trainingCategoryGroup') %}
    <input type="checkbox" name="training[]" value="{{ category.slug }}" {{ category.slug in trainingQuery ? 'checked'}}>{{ category.title }}

  {% endfor %}

  <button type="submit">Search</button>
</form>

Then output your list of entries. This is a simple example.

{% if entries | length %}

    {% for entry in entries %}

        {{ entry.title }}

    {% endfor %}

{% else %}

No results

{% endif %}

If the query string is blank, this will show all of your entries. If you want to restrict that, you can wrap the previous code block in this...

{% if trainingQuery %}
  ... (entries) ...
{% endif %}

This is an inclusive search that will match entries in ANY selected categories. If you want an exclusive search instead (category AND category), you have to do it a little differently.

{# Get search parameters from the URL query string #}
{% set trainingQuery = craft.request.getParam('training') %}

{# Start an array of search parameters (relationParam) with 'and' to match ALL categories #}
{% set relationParam = ['and'] %}

{# Find categories that match the slugs in your query string... #}
{% for querySlug in trainingQuery %}
  {% set trainingCategory = craft.categories.group('trainingCategoryGroup').slug(querySlug) %}

  {# And merge them into the relationParam array. #}
  {% set relationParam = relationParam|merge([{ targetElement: trainingCategory }]) %}
{% endfor %}

{# Avoid passing an array with `['and']` only #}
{% if relationParam|length < 2 %}
  {% set relationParam = '' %}
{% endif %}

{% set searchParams = {
  relatedTo:  relationParam,
  section: 'exercisesDb'
} %}


How to set the value of a Date field from PHP?

Here's an example value that will set it to today:
[
  'timezone' => 'America/New_York',
  'date' => date('m/d/Y')
]

As always, easiest to find out how it's done by inspecting the fields as they are saved in the control panel.


Create filters from Matrix Blocks on entries or products

Ok, so It's totally possible to do this utilising the array|merge feature of twig.
Firstly, we do a for loop over all our products (or whatever), loop over our matrix block(s), loop of the fields(s) and spit those values into a new array. We should end up with every value applied to every product in a big array:

{% set ageArray = [] %} // array for all your values
{% for product in craft.commerce.products.relatedTo(category) %}
  {% for block in product.ageRange %}
    {% for option in block.options %}
      {% set ageArray = ageArray|merge({ (loop.index): option.value }) %}
    {% endfor %}
  {% endfor %}

for me, I had multiple values set from 1-10 on all products, so ended up with something like: [2,3,4,5,6,3,4,5,6,7,1,2,3,4] etc etc

Now we sort and loop over this new array, counting how many times we come across the same number. The original value, as well as the amount of times we count it, gets spat into another array:

{% set counter = 1 %}
{% set ageArray = [] %}
{% for age in ageArray|sort %}
  {% if currentAge is defined and currentAge != age %}
    {% set counter = 1 %}
  {% endif %}
  {% if currentAge is defined and currentAge == age %}
    {% set counter = counter + 1 %}
  {% endif %}
  {% set newArray = newArray|merge({ ('age'~age): {'age': age, 'counter': counter} }) %}
  // ('age'~age) has to be string key, integer wont overwrite
  {% set currentAge = age %}
{% endfor %}

CurrentAge is basically the last iteration's value, so we do some checks against the current value and either reset the counter or increment. If it is the first time we see this number - the counter should be 1. If it matches, we add 1 on!

We then merge these values into the final array, overwriting any with the same key. Finally, we update currentAge with the actual new value, ready for the next iteration.

finally, you can just use this new array:

  {% for reducedAge in newArray %}

         {{ reducedAge.age }} ({{reducedAge.counter}})

  {% endfor %}

Twig really does not seem like a clever place for this logic. However, this will provide a nice fallback for an ElementApi / JS solution. I'm surprised it wasn't easier, I'd have though alot of people need this sort of functionality!


The first example makes sense because you are passing a multidimensional  array (syName), looping through that array, assigns each array within to alt allowing you to then access the values through dot notation ({{ alt.name }}), because alt is an array.

In your second example you are passing through just one array, so when you loop through it, the value in name is assigned to alt as a string. (the value in the array) so you can echo it out just by doing {{ alt }}

So your code could look like:

{% macro prognose(symbol, syName) %}

   {% for name in syName %}
      {{ name }}
   {% endfor %}
{% endmacro %}

{{ _self.prognose(  '1' , syName.x ) }}

This will output Schön

To make things even easier for yourself, if you are passing just one array i.e syName.x You don't even need the loop as you can just access the value through dot notation:

{% set syName = {
   x: { name: "Schön"},
   y: { name: "Leicht bewölkt"},
   z: { name: "Stark Bewölkt"},
}%}

{% macro prognose(symbol, syName) %}

    {{ syName.name }}
{% endmacro %}

{{ _self.prognose('1', syName.x) }}

This will output Schön


Depending on the level of "corruption", if the 3.1 Control Panel is still accessible and loading, you can use something like FeedMe to export the content you're looking for into a new Craft 3 install.


Push/Add asset to Entry by asset filename

You need to fetch the asset and set it as a field value to your entry

$pushImageId = Asset::find()->filename($name[0])->ids();

id will display the id property of your query. You won't fetch any results with it ids() will return an array of asset ids

$product->setFieldValue ('productImages', $productImages);

Will set the relation and finally you can store the element

Edit: and you need to fetch the product as well. Currently you just create the query for it


Output the contents of an instructions field within a Matrix block

I just searched this Stack Exchange and found an answer on how to get the field model from the templates: How can I output the Field Name in my template?

  You can get any field with craft.fields, which returns a FieldModel:

 {% set field = craft.fields.getFieldbyHandle('field_handle') %}
 {{ field.name }}
 {{ field.instructions }}

Unfortunatelly, however, this won't work with fields within a Martix field. The getFieldbyHandle method is written for use in specific parts of the CP, where Craft knows the context the field is used in.

There's a getFieldbyId method though, which could work for your use case. The field's ID is independent from the context (inside Matrix or not).


Is it possible to convert a plain text field to a rich text field, without losing content?

You should be OK converting your Plain Text to Rich Text. I've just tried it in my dev environment and everything was preserved.

Rich Text will add the paragraph tags as you suggest, so you'll want to remove them from your templates files as you mentioned.

If you're being cautious, you can take a backup of your database in the Settings section of your control panel before changing the field type. It only takes a few seconds, and that way, if anything goes wrong, you can restore.


Passing value in form with amforms plugin

Whenever you submit forms to Craft, your name attribute must be formatted in a certain way by adding your values to a fields[] array. In your case, the field should look like:

<input type="hidden" name="fields[nomDocumentEfficy]" value="my_value">

You can see this happening if you ever inspect a form field inside an entry in the CMS, or if you inspect the output generated by amforms' tags you're using: {{ form.displayField('email') }}

However, not all form field types get added to this array the same as a simple text or hidden field! For reference on how to format checkbox fields, date fields, or even Matrix fields, for example, you can reference this great guide on StraightUpCraft.


Create a new site in Settings > Sites > New Site
Make sure "This Site Has Its Own Base URL" is checked
Go to the "Entries" section, publish a page, and set the entry slug as __home__
Return to the Entries section, switch to Site 2 using the dropdown menu at the top of the screen
Publish a page and set the entry slug as __home__

Craft knows which site each page belongs to, so there will be no conflict between the slugs.

You can use any section you like to publish your homepages, as long as the Entry URI Format in the section's settings doesn't require a special syntax. Many people use a "Single"-type section or a "Structure"-type section with a URL setting of {parent.uri}/{slug}. Make sure the section is available to be used by Site 2 in the section settings.


The URL you call using Ajax shouldn't include the action trigger, since Craft will add this to call the correct method in your controller when it interprets the URL.

So in the example you gave, your Ajax URL should be: /actions/businessLogic/exampleAjax

More details can be found in the Plugin Development docs.

Note that if you change the actionTrigger in the general.php config file, then you will need to change the first segment of the Ajax URL to match the new value for the actionTrigger.


Accessing global set's field gives object that couldn't be converted to string

Well, when I went properly through the output of {{ dump(company.businessName) }} I found out right from the start that it is element criteria model of entry type.
That led me to check for the handle company that could exists twice in system.

I found section with the handle company. So two identical handles in system were causing my problem. But on the first place, how could Craft let me save the global set with the handle that already existed in system even if they are different type of element criteria model and Craft would throw that string conversion error anyway?


How do I get the Site/Revision/Draft in a field in the control panel?

In the context of the Control Panel, the URL parameters are the best way to get that info because the user chooses which site to work on, which draft to work on, or which revision to review. Craft, itself, relies on those URL parameters.

In the context of a CLI request, there is no user interaction. You're on the hook to sort out which entry, draft, site, and user are relevant to the element you'd like to manipulate. As of Craft 3.3 (current version today) there is an EntryRevisions service class. All of the methods are deprecated in favor of running your own entry queries, but those methods are a good reference for how to get the drafts or revisions you're looking for.

For example, rather than running the deprecated method:

$drafts = Craft::$app->getEntriesRevisions()->getDraftsByEntryId($entryId, $siteId);

You'd run the contents of that method for yourself:

return Entry::find()
    ->draftOf($entryId)
    ->siteId($siteId)
    ->orderBy(['drafts.name' => SORT_ASC])
    ->all();


Isnt this possible with the modifyCategorySources hook?

-> https://docs.craftcms.com/v3/extend/updating-plugins.html#modifyentrysources-modifycategorysources-modifyassetsources-modifyusersources

I'm assuming you are using C3 by the namespace you mentioned. Correct me if this is wrong :).


How to get a field value from next/prev asset

I found this to work for what I needed:

{% set nextImage = image.getNext() %}
{% if nextImage %}

    {% if nextImage.checkboxFieldHandle.contains('value') %}
        {# Do something #}
    {% endif %}

{% endif %}


How to re-generate titles for all entries in a section?

My understanding is that dynamic titles only get updated whenever an entry is saved — so without using a plugin you would have to re-save them each manually. If you wanted to automate this process in a plugin, you would use something like this.

public function updateMySectionTitles()
{
    $criteria = craft()->elements->getCriteria(ElementType::Entry);
    $criteria->section = 'mySection';
    $entries = craft()->elements->findElements($criteria);
    foreach ($entries as $entry) {
        craft()->entries->saveEntry($entry);
    }
}

Untested (if anyone sees an error please comment). Also, keep in mind, this might only update the current locale — I'm not sure. You'll need to test, and modify if needed. You could also potentially add this is as a custom command to the amcommand plugin for easy access.


Send to a friend that sends an email to a defined email of the users choosing

<input type="input" name="toEmail" value="">

https://github.com/craftcms/contact-form/tree/v1#dynamically-adding-email-recipients-requires-craft-25


The database backup from Craft is slightly different to the SQL export in phpMyAdmin. Craft’s export (presumably) assumes you’re going to want to import that data into an existing site, whereas phpMyAdmin’s default (presumably) assumes you’ll want to import it into an empty database.
However you can do exactly as you suggest — export from phpMyAdmin locally, create a new Craft installation on your live server, use phpMyAdmin on the live server to delete the new database’s contents, then import the original data with phpMyAdmin.
I did this a few months ago (long story); it worked fine, nothing has exploded so far.


Welcome to the community Adam.

Yes. Completely possible with vanilla Craft.

There's always more than one way to achieve things but here's a first round.

Start by creating two User Groups; Contractors and Clients. This will allow you to define permissions as needed.

Your 'Property Projects' Section could contain fields like.

Title
Description
Images
Related Contractors (user)
Related Client (user)
Etc as needed

Craft has a custom field type called 'User' which will allow you to relate all of the relevant contractors to the project and also define who the client is, all within the 'project' Entry.

Because the client also has a user profile and is able to log in to Craft (front end only), you can present their project information to them in the 'client area' of the site.

If you actually want the client to edit their project Entry, then you could also consider making them the Author of their Entry. (Just an idea)

Have a look at Craft's relatedTo documentation


Adding new structure items to top of structure

As far as I'm aware there is nothing like that natively to Craft. You can either:

Submit a Feature Request for adding pages to the top of structures
Develop your own Craft plugin that provides this functionality


How do I add custom styles/plugins to the rich text editor in Craft?

If by styles you mean the formatting drop-down, just add them in an array:

{
    buttons: ['bold', 'italic'],
    formatting: ['p', 'blockquote', 'h2', 'h3', 'h4', 'SomeHtmlTag']
}

.

If you want to have a button which adds custom CSS-classes, take a look at: Redactor CSS by Nathan Doyle

Update (July 2015)

Craft 2.3.2615 (Dec 2, 2014) and above use Redactor 10, which includes the formattingAdd setting for adding custom styles and classes.

formattingAdd: [
{
    tag: 'p',
    title: 'Red Block',
    class: 'red'
}


EntryModel attributeConfigs method throwing undefined index

An entry's title is stored on the ContentModel, so you'd need to do:

$content = $entry->getContent();
$content->attributeConfigs['title'];


Plugin uploads an asset, need the final url

I think your best bet here would be to make use of the entries.onSaveEntry event, because at the moment $entry doesn't relate to the entry you have just saved, but the entry you wanted to save so it makes sense the entry asset paths are still pointing to the temp locations.

As far as i'm aware craft()->entries->saveEntry() just returns a bool, whether or not the save was a success, and not the entry model that was just saved.

So your controller could look like this:

if (!craft()->entries->saveEntry($entry))
{
 // Only worry if something goes wrong
}

Then in an init function in your main plugin class you could do something like:

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

 // Is this a new entry?
 if($event->params['isNewEntry'])
 {
    // This is an EntryModel object of the entry that was just saved
    $entry = $event->params['entry'];

    // Is the entry in the right section?
    if($entry->sectionId == 1)
    {
      // Send the $entry to your email function
      craft()->yourPlugin->sendEmail($entry);
    }
 }

});

I would assume at this point the asset paths are all correct as it would have been saved to the database and all the backend work done etc

This would help you out in the future as well as it wouldn't matter where the entry was created, whether in the admin or through your plugin or anywhere else, and you could be sure the email will still get triggered :)

Failing that you could also try the assets.onSaveAsset event and see if you get better results with that?

http://buildwithcraft.com/docs/plugins/events-reference

I hope this helps in some way!


Image Transforms not generated - permission problem?

Craft will store any temporary files it generates into storage/runtime/temp by default, but both Imagick and GD will also likely write to the system's temp folder (likely /tmp but could vary depending on OS and distro).


Invalid plugin: No plugin exists with the handle - Craft 3

For future reference, I had the same error and resolved it with Craft Support.

In my case the project.yaml file got out of sync with what was in the database.

Running craft project-config/rebuild from the project's root resolved the issue and allowed us to re-enable the plugins


Craft Commerce 2 - get order data for plugin

$order = \craft\commerce\elements\Order::find()->id($id)->one();

if($order)
{
  foreach ($order->getLineItems() as $item) {
   // $item->description
   // $item->qty
  }

  $billingAddress = $order->getBillingAddress();
  $shippingAddress = $order->getShippingAddress();
}


How to copy Matrix from one entry to another in Craft 3

The blocks in a Matrix field are all elements, with their owner ID set to the corresponding entry. This is how you could copy them (untested):

use craft\elements\MatrixBlock;

foreach ($entryA->matrixFieldHandle->all() as $matrixBlockA) {
    $matrixBlockB = new MatrixBlock();
    $matrixBlockB->fieldId = $matrixBlockA->fieldId;
    $matrixBlockB->typeId = $matrixBlockA->typeId;
    $matrixBlockB->ownerId = $entryB->id;
    $matrixBlockB->siteId = $entryB->siteId;
    $matrixBlockB->enabled = $matrixBlockA->enabled;
    $matrixBlockB->sortOrder = $matrixBlockA->sortOrder;
    $matrixBlockB->setFieldValues($matrixBlockA->getFieldValues());

    Craft::$app->getElements()->saveElement($matrixBlockB);
}

Things can get tricky if you have multiple sites and the entries do or do not get propagated (etc), but this is how it works in a nutshell.

For the above code to work, you have to first save Entry B, to get an entry ID for it. So, create Entry B, fill 'normal' fields, save Entry B, create Matrix B, save Matrix B.


100% untested, but something like this should work using Twig's date_modify filter.

{% set startDate = now|date_modify("-6 months") %}

{% set allEntries = craft.entries.section('blog').limit(null).postDate('>= ' ~ startDate) %}

{% for date, entries in allEntries | group("postDate|date('F Y')") %}

{{ date }}

        {% for entry in entries %}

{{ entry.getLink() }}

        {% endfor %}

{% endfor %}


How do I write an if statement to show Isotope filter button only if the Entry Section has content?

Here's just a variation on the conditional that Victor provided that will do the same thing, might be a bit cleaner if you ever need to check several arrays:

{% if albumCd|merge(singleCd)|length  %}
    <button class="filt btn" type="button" data-filter=".CD">CD</button>
{% endif %}


How to change/discount total amount before payment

Have you looked into building an adjuster for this purpose? You can find the documentation here


Charge plugin: subscription start and end dates not updating for recurring subscription payments

Not really a solution, I know, but in the absence of any support from the developer on this there may be a workaround.

In my case I've been developing using planIntervals of only 1 day so I can see what's going on. As noted in your question, it never updates to the correct currentPeriodEnd, but it does seem to be updating. It looks like it updates to the end of the next but last payment taken. Here's an example:

I've got three payments taken for this subscriber:

2018-07-26
2018-07-25
2018-07-24

With the last payment being on 26 July, currentPeriodEnd should be 27 July. It isn't. It's outputting 26 Jul, the period end of the next to last payment. Or maybe the actual date the last payment was taken. I'm not sure.

Rather than fix this, I'm probably just going to test for the subscription being active and adding the planInterval to the currentPeriodEnd. But only if more than the initial payment has been made.

{% if charge.subscription.status == "active" %}

    {% if charge.payments | length > 1 %}
        {% set paymentEnd = charge.subscription.currentPeriodEnd | date_modify("+1 day") %}
    {% else %}
        {% set paymentEnd = charge.subscription.currentPeriodEnd %}
    {% endif %}

    {{ paymentEnd | date('j M Y') }}

    {% set daysToRenewal = date(paymentEnd).diff(now).days %}
    {{ daysToRenewal }} days to renewal

    {# Send email to subscriber if exactly 28 days to go #}

{% endif %}


Include Global Set Variable in Print Delimiters

You'd want to do something like this:

{{ "#" ~ craft.config.siteCode ~"Defaults.defaultTelephoneLink" }}


What you need is a "host" project for your plugin, and then use a repository path to point to your plugin as described here: So You Wanna Make a Craft 3 Plugin?


Macro for entry loop causing 'null' variable template error

Your blogroll can be treated as a PHP function. In order to use functions you have to pass the required parameters. In your case your blogroll expects the parameter entry

{{ blogroll.blogroll(entry) }}
or
{{ blogroll.blogroll(category) }}

will work


Values in the documentation list possibilities, like: 'firstName' and 'lastName', which needs to be updated, since Craft only accepts lowercase values.

Changing 'firstName' to 'firstname' solves the issue.


Display list of countries in form using a dropdown

This is not the answer you were looking for, but if you decide to just go with a normal drop-down, then you can paste the following into the dropdown field in the database. This would go in the craft_fields table, yourCountryField row, settings column. After editing the list the way you need it I would suggest removing all line-breaks using grep find/replace ('\n', ''), but it may not matter either.

{"options":[
{"label":"Afghanistan","value":"AF","default":""},
{"label":"Aland Islands","value":"AX","default":""},
{"label":"Albania","value":"AL","default":""},
{"label":"Algeria","value":"DZ","default":""},
{"label":"American Samoa","value":"AS","default":""},
{"label":"Andorra","value":"AD","default":""},
{"label":"Angola","value":"AO","default":""},
{"label":"Anguilla","value":"AI","default":""},
{"label":"Antarctica","value":"AQ","default":""},
{"label":"Antigua and Barbuda","value":"AG","default":""},
{"label":"Argentina","value":"AR","default":""},
{"label":"Armenia","value":"AM","default":""},
{"label":"Aruba","value":"AW","default":""},
{"label":"Australia","value":"AU","default":""},
{"label":"Austria","value":"AT","default":""},
{"label":"Azerbaijan","value":"AZ","default":""},
{"label":"Bahamas","value":"BS","default":""},
{"label":"Bahrain","value":"BH","default":""},
{"label":"Bangladesh","value":"BD","default":""},
{"label":"Barbados","value":"BB","default":""},
{"label":"Belarus","value":"BY","default":""},
{"label":"Belgium","value":"BE","default":""},
{"label":"Belize","value":"BZ","default":""},
{"label":"Benin","value":"BJ","default":""},
{"label":"Bermuda","value":"BM","default":""},
{"label":"Bhutan","value":"BT","default":""},
{"label":"Bolivia","value":"BO","default":""},
{"label":"Bosnia and Herzegovina","value":"BA","default":""},
{"label":"Botswana","value":"BW","default":""},
{"label":"Bouvet Island","value":"BV","default":""},
{"label":"Brazil","value":"BR","default":""},
{"label":"British Indian Ocean Territory","value":"IO","default":""},
{"label":"Brunei Darussalam","value":"BN","default":""},
{"label":"Bulgaria","value":"BG","default":""},
{"label":"Burkina Faso","value":"BF","default":""},
{"label":"Burundi","value":"BI","default":""},
{"label":"Cambodia","value":"KH","default":""},
{"label":"Cameroon","value":"CM","default":""},
{"label":"Canada","value":"CA","default":""},
{"label":"Cape Verde","value":"CV","default":""},
{"label":"Cayman Islands","value":"KY","default":""},
{"label":"Central African Republic","value":"CF","default":""},
{"label":"Chad","value":"TD","default":""},
{"label":"Chile","value":"CL","default":""},
{"label":"China","value":"CN","default":""},
{"label":"Christmas Island","value":"CX","default":""},
{"label":"Cocos (Keeling) Islands","value":"CC","default":""},
{"label":"Colombia","value":"CO","default":""},
{"label":"Comoros","value":"KM","default":""},
{"label":"Congo","value":"CG","default":""},
{"label":"Congo, The Democratic Republic of the","value":"CD","default":""},
{"label":"Cook Islands","value":"CK","default":""},
{"label":"Costa Rica","value":"CR","default":""},
{"label":"Cote D'Ivoire","value":"CI","default":""},
{"label":"Croatia","value":"HR","default":""},
{"label":"Cuba","value":"CU","default":""},
{"label":"Cyprus","value":"CY","default":""},
{"label":"Czech Republic","value":"CZ","default":""},
{"label":"Denmark","value":"DK","default":""},
{"label":"Djibouti","value":"DJ","default":""},
{"label":"Dominica","value":"DM","default":""},
{"label":"Dominican Republic","value":"DO","default":""},
{"label":"Ecuador","value":"EC","default":""},
{"label":"Egypt","value":"EG","default":""},
{"label":"El Salvador","value":"SV","default":""},
{"label":"Equatorial Guinea","value":"GQ","default":""},
{"label":"Eritrea","value":"ER","default":""},
{"label":"Estonia","value":"EE","default":""},
{"label":"Ethiopia","value":"ET","default":""},
{"label":"Falkland Islands (Malvinas)","value":"FK","default":""},
{"label":"Faroe Islands","value":"FO","default":""},
{"label":"Fiji","value":"FJ","default":""},
{"label":"Finland","value":"FI","default":""},
{"label":"France","value":"FR","default":""},
{"label":"French Guiana","value":"GF","default":""},
{"label":"French Polynesia","value":"PF","default":""},
{"label":"French Southern Territories","value":"TF","default":""},
{"label":"Gabon","value":"GA","default":""},
{"label":"Gambia","value":"GM","default":""},
{"label":"Georgia","value":"GE","default":""},
{"label":"Germany","value":"DE","default":""},
{"label":"Ghana","value":"GH","default":""},
{"label":"Gibraltar","value":"GI","default":""},
{"label":"Greece","value":"GR","default":""},
{"label":"Greenland","value":"GL","default":""},
{"label":"Grenada","value":"GD","default":""},
{"label":"Guadeloupe","value":"GP","default":""},
{"label":"Guam","value":"GU","default":""},
{"label":"Guatemala","value":"GT","default":""},
{"label":"Guernsey","value":"GG","default":""},
{"label":"Guinea","value":"GN","default":""},
{"label":"Guinea-Bissau","value":"GW","default":""},
{"label":"Guyana","value":"GY","default":""},
{"label":"Haiti","value":"HT","default":""},
{"label":"Heard Island and Mcdonald Islands","value":"HM","default":""},
{"label":"Holy See (Vatican City State)","value":"VA","default":""},
{"label":"Honduras","value":"HN","default":""},
{"label":"Hong Kong","value":"HK","default":""},
{"label":"Hungary","value":"HU","default":""},
{"label":"Iceland","value":"IS","default":""},
{"label":"India","value":"IN","default":""},
{"label":"Indonesia","value":"ID","default":""},
{"label":"Iran, Islamic Republic Of","value":"IR","default":""},
{"label":"Iraq","value":"IQ","default":""},
{"label":"Ireland","value":"IE","default":""},
{"label":"Isle of Man","value":"IM","default":""},
{"label":"Israel","value":"IL","default":""},
{"label":"Italy","value":"IT","default":""},
{"label":"Jamaica","value":"JM","default":""},
{"label":"Japan","value":"JP","default":""},
{"label":"Jersey","value":"JE","default":""},
{"label":"Jordan","value":"JO","default":""},
{"label":"Kazakhstan","value":"KZ","default":""},
{"label":"Kenya","value":"KE","default":""},
{"label":"Kiribati","value":"KI","default":""},
{"label":"Korea, Democratic People's Republic of","value":"KP","default":""},
{"label":"Korea, Republic of","value":"KR","default":""},
{"label":"Kuwait","value":"KW","default":""},
{"label":"Kyrgyzstan","value":"KG","default":""},
{"label":"Lao People's Democratic Republic","value":"LA","default":""},
{"label":"Latvia","value":"LV","default":""},
{"label":"Lebanon","value":"LB","default":""},
{"label":"Lesotho","value":"LS","default":""},
{"label":"Liberia","value":"LR","default":""},
{"label":"Libyan Arab Jamahiriya","value":"LY","default":""},
{"label":"Liechtenstein","value":"LI","default":""},
{"label":"Lithuania","value":"LT","default":""},
{"label":"Luxembourg","value":"LU","default":""},
{"label":"Macao","value":"MO","default":""},
{"label":"Macedonia, The Former Yugoslav Republic of","value":"MK","default":""},
{"label":"Madagascar","value":"MG","default":""},
{"label":"Malawi","value":"MW","default":""},
{"label":"Malaysia","value":"MY","default":""},
{"label":"Maldives","value":"MV","default":""},
{"label":"Mali","value":"ML","default":""},
{"label":"Malta","value":"MT","default":""},
{"label":"Marshall Islands","value":"MH","default":""},
{"label":"Martinique","value":"MQ","default":""},
{"label":"Mauritania","value":"MR","default":""},
{"label":"Mauritius","value":"MU","default":""},
{"label":"Mayotte","value":"YT","default":""},
{"label":"Mexico","value":"MX","default":""},
{"label":"Micronesia, Federated States of","value":"FM","default":""},
{"label":"Moldova, Republic of","value":"MD","default":""},
{"label":"Monaco","value":"MC","default":""},
{"label":"Mongolia","value":"MN","default":""},
{"label":"Montserrat","value":"MS","default":""},
{"label":"Morocco","value":"MA","default":""},
{"label":"Mozambique","value":"MZ","default":""},
{"label":"Myanmar","value":"MM","default":""},
{"label":"Namibia","value":"NA","default":""},
{"label":"Nauru","value":"NR","default":""},
{"label":"Nepal","value":"NP","default":""},
{"label":"Netherlands","value":"NL","default":""},
{"label":"Netherlands Antilles","value":"AN","default":""},
{"label":"New Caledonia","value":"NC","default":""},
{"label":"New Zealand","value":"NZ","default":""},
{"label":"Nicaragua","value":"NI","default":""},
{"label":"Niger","value":"NE","default":""},
{"label":"Nigeria","value":"NG","default":""},
{"label":"Niue","value":"NU","default":""},
{"label":"Norfolk Island","value":"NF","default":""},
{"label":"Northern Mariana Islands","value":"MP","default":""},
{"label":"Norway","value":"NO","default":""},
{"label":"Oman","value":"OM","default":""},
{"label":"Pakistan","value":"PK","default":""},
{"label":"Palau","value":"PW","default":""},
{"label":"Palestinian Territory, Occupied","value":"PS","default":""},
{"label":"Panama","value":"PA","default":""},
{"label":"Papua New Guinea","value":"PG","default":""},
{"label":"Paraguay","value":"PY","default":""},
{"label":"Peru","value":"PE","default":""},
{"label":"Philippines","value":"PH","default":""},
{"label":"Pitcairn","value":"PN","default":""},
{"label":"Poland","value":"PL","default":""},
{"label":"Portugal","value":"PT","default":""},
{"label":"Puerto Rico","value":"PR","default":""},
{"label":"Qatar","value":"QA","default":""},
{"label":"Reunion","value":"RE","default":""},
{"label":"Romania","value":"RO","default":""},
{"label":"Russian Federation","value":"RU","default":""},
{"label":"Rwanda","value":"RW","default":""},
{"label":"Saint Helena","value":"SH","default":""},
{"label":"Saint Kitts and Nevis","value":"KN","default":""},
{"label":"Saint Lucia","value":"LC","default":""},
{"label":"Saint Pierre and Miquelon","value":"PM","default":""},
{"label":"Saint Vincent and the Grenadines","value":"VC","default":""},
{"label":"Samoa","value":"WS","default":""},
{"label":"San Marino","value":"SM","default":""},
{"label":"Sao Tome and Principe","value":"ST","default":""},
{"label":"Saudi Arabia","value":"SA","default":""},
{"label":"Senegal","value":"SN","default":""},
{"label":"Serbia and Montenegro","value":"CS","default":""},
{"label":"Seychelles","value":"SC","default":""},
{"label":"Sierra Leone","value":"SL","default":""},
{"label":"Singapore","value":"SG","default":""},
{"label":"Slovakia","value":"SK","default":""},
{"label":"Slovenia","value":"SI","default":""},
{"label":"Solomon Islands","value":"SB","default":""},
{"label":"Somalia","value":"SO","default":""},
{"label":"South Africa","value":"ZA","default":""},
{"label":"South Georgia and the South Sandwich Islands","value":"GS","default":""},
{"label":"Spain","value":"ES","default":""},
{"label":"Sri Lanka","value":"LK","default":""},
{"label":"Sudan","value":"SD","default":""},
{"label":"Suriname","value":"SR","default":""},
{"label":"Svalbard and Jan Mayen","value":"SJ","default":""},
{"label":"Swaziland","value":"SZ","default":""},
{"label":"Sweden","value":"SE","default":""},
{"label":"Switzerland","value":"CH","default":""},
{"label":"Syrian Arab Republic","value":"SY","default":""},
{"label":"Taiwan, Province of China","value":"TW","default":""},
{"label":"Tajikistan","value":"TJ","default":""},
{"label":"Tanzania, United Republic of","value":"TZ","default":""},
{"label":"Thailand","value":"TH","default":""},
{"label":"Timor-Leste","value":"TL","default":""},
{"label":"Togo","value":"TG","default":""},
{"label":"Tokelau","value":"TK","default":""},
{"label":"Tonga","value":"TO","default":""},
{"label":"Trinidad and Tobago","value":"TT","default":""},
{"label":"Tunisia","value":"TN","default":""},
{"label":"Turkey","value":"TR","default":""},
{"label":"Turkmenistan","value":"TM","default":""},
{"label":"Turks and Caicos Islands","value":"TC","default":""},
{"label":"Tuvalu","value":"TV","default":""},
{"label":"Uganda","value":"UG","default":""},
{"label":"Ukraine","value":"UA","default":""},
{"label":"United Arab Emirates","value":"AE","default":""},
{"label":"United Kingdom","value":"GB","default":""},
{"label":"United States","value":"US","default":""},
{"label":"United States Minor Outlying Islands","value":"UM","default":""},
{"label":"Uruguay","value":"UY","default":""},
{"label":"Uzbekistan","value":"UZ","default":""},
{"label":"Vanuatu","value":"VU","default":""},
{"label":"Venezuela","value":"VE","default":""},
{"label":"Viet Nam","value":"VN","default":""},
{"label":"Virgin Islands, British","value":"VG","default":""},
{"label":"Virgin Islands, U.S.","value":"VI","default":""},
{"label":"Wallis and Futuna","value":"WF","default":""},
{"label":"Western Sahara","value":"EH","default":""},
{"label":"Yemen","value":"YE","default":""},
{"label":"Zambia","value":"ZM","default":""},
{"label":"Zimbabwe","value":"ZW","default":""}
]}


Looping through Entries based on MultiSelect Field Selection

Pretty straight forward in the end =]

{% set allPeople = craft.entries.section('People') %}
{% for entry in allPeople if entry.peopleCategory.contains('leadership') %}


Craft Commerce: ordering products like a structure

Yeh there's few workarounds.
Your entries field is close to what Nathanial from P&T mentioned on the issue tracker:

If you create a global set and add a custom product field. Then select all the products. This gives you the ability to drag and drop the order of the products. You can use this in conjunction with the on save event and catch the save of new products and programmatically add them to the field mentioned above.

If you filter by category, you won't have to create a field for every category however it's definitely still a workaround.

One other option would be to sort based on some other criteria that's always around, such as date created or modified.
If you want something to float to top or bottom, just remove the post date (so Craft will make the product the current date and time) or resave the product (to change the modification date). Depending on how you sort that could be a quick way to move products to the top for example.
Make sure you chime in on that issue on the tracker to give it more attention.


Installing GA is easy... you can either put that info into a Global field, or include it as a separate Twig template.

As for general SEO... Check out the SEOmatic plugin or the Sprout SEO plugin.


My issue was that the assets files were in the same folder as the twig template files. Moving the files to the web folder solved the issue.


What is the expected data type to be returned when using the prepValue() method?

Looks like the error is occurring when your field type’s getSearchKeywords() function is called. The value that’s passed into that function will have already been run through prepValue(), so at that point it looks like it will be a MyPlugin_MyModelNameModel instance (whatever the actual class name is).

If your field type doesn’t override getSearchKeywords(), the BaseFieldType version will just pass the value off to StringHelper::arrayToString(), which will do its best to convert whatever variable it was passed into a string. Something in there must be tripping it up.

Your best bet here is probably to just override getSearchKeywords() in your field type. It should be returning a space-delimited list of keywords you want to be stored for the current field value.


How do I get tags to only display on posts that have that tag?

The code you're using at the moment is trying to output the tags that are in use on any/all entries:

{% set entries = craft.entries.section('news').limit(null) %}

If I understand you correctly, you want to output the tags only for the current entry, right?

This is explained with very useful examples in the documentation.

Solution

Assuming you already have the entry variable set, you could do the following:

    {% for tag in craft.tags.relatedTo(entry) %}

{{ tag.title }}

    {% endfor %}

Another example adapted from the docs:

{% set tags = entry.tagsFieldHandle %}

{% if tags | length %}

        {% for tag in tags %}

{{ tag.title }}

        {% endfor %}

{% endif %}

You first set the variable tags to the tags related to your entry. Then, you check if there are tags related to the entry. If there are, you iterate over them.


Remove the / at the end of databases/ and it should work.

Technically, index.html is not required either, so you could just use library-database-demo-section.


Using Sprig's live search but show all entries first

Looking at the example from the Sprig Cookbook, it looks like the results container should live outside the sprig.isInclude:
{% if sprig.isInclude %}
    <select sprig s-target="#results" name="verdict" id="verdict">
        {# loop through options #}
    </select>
    <select sprig s-target="#results" name="rating" id="rating">
        {# loop through options #}
    </select>
    <select sprig s-target="#results" name="platform" id="platform">
        {# loop through options #}
    </select>
    <input sprig s-trigger="keyup changed" s-target="#results" type="search" name="title" id="title" />
{% endif %}

<div id="results">
{% if queryParams %}
    {% set entries = craft.entries(queryParams).orderBy('score').all() %}
    {% for entry in entries %}
        {{ entry.title }}
    {% endfor %}
{% else %}
    {% set entries = craft.entries.section('games').orderBy('title').all() %}
    {% for entry in entries %}
        {{ entry.title }}
    {% endfor %}
{% endif %}
</div>


What password requirements exist for new users?

Craft 2:

By default Craft enforces a 6 character minimum as the only password requirement, but as of Craft 2.3, a plugin can now listen for the users.onBeforeSetPassword event to enforce any password requirements it wants for newly set/changed passwords and set $performAction = false to cancel the action with any validation errors returned on the UserModel.

Craft 3:

This has changed quite a bit for Craft 3... here is how you would pull it off:

use craft\elements\User;
use yii\base\Event;
use yii\base\ModelEvent;

Event::on(User::class, User::EVENT_BEFORE_VALIDATE, function(ModelEvent $event) {
    /** @var User $user */
    $user = $event->sender;

    if ($user->newPassword !== null) {
        $validates = $this->validateNewPassword($user->newPassword);

        if (!$validates) {
            $user->addError('newPassword', Craft::t('plugin-handle', 'Invalid password'));
            $event->isValid = false;
        }
    }
});


Checking value of customer order field within Plugin

What you're probably looking for is:

if ($order->signupForNewsletter->contains('joinMailingList'))
{
    echo "I've opted in";
}
else
{
    echo 'Not matched';
}


AJAX CSRF Producing Inconsistent Results

Trying to understand the issue in general. These are my thoughts, not sure if they will help you.

I assume that by caching, you mean some sort of full page cache and the comments below are based on that.

AJAX requests to support CSRF in craft, require the tokens name/value passed as a param in the request data.

In general, if you introduce a full page cache system on your system, you generally need a 'hole punching' mechanism to exclude from caching, any dynamically set variables.

This is a common use for eCommerce websites. For example where you might have a mini-cart feature on your page which needs refreshing when you perform an 'add to cart' action using AJAX. So the page does not refresh, but that bit of template needs refreshing.

Within Craft, I would try to exclude from caching the javascript lines that introduce the CSRF token, as well as excluding from cache any twig methods that generate the CSRF token in the templates

The way to perform 'hole punching' depends on the type of full page caching you are using. Each system have their own method.


Webhook plugin & hooking into Contact Form

I had a similar issue where some queues would only run when I logged in via the control panel. The root cause is usually stalled or failed tasks, but I was able to get webhook tasks to run instantly by installing the AsyncQueue plugin.

From their docs:

  This plugin replaces Craft's default queue handler and moves queue execution to a non-blocking background process. The command craft queue/run gets executed right after you push a Job to the queue.


Sending Error Message to Template With No Logged In User - Craft 2

You are mixing Craft 3 code with Craft 2. There is no native way to access the session in Craft 2 via Twig so you need to inject the functions with your plugin

See a working example here


Ordering Looped Results by Field's Numerical Value

It's an extra plugin but SuperSort would do the job - https://github.com/TopShelfCraft/SuperSort

Edit - couldn't make it work in one go, but this works:

{% set results = [] %}
{% for field in submission %}
  {% set results = results | merge([{'handle': field.handle, 'value': submission[field.handle].value}]) %}
{% endfor %}
{% set sortedResults = results | supersort('sortAs', '{value}', SORT_NUMERIC) %}

Not the most elegant, let me know if you find a better solution!


The Features section on the Craft site already has some useful videos that may be of interest:

https://buildwithcraft.com/features/matrix


Should my controllers actions 'return' when rendering templates?

There’s no reason for your controller to return anything – it will never be checked.

Many requests call more than one controller action, so it would be pretty presumptuous for Craft to think that it should actually output whatever your controller returns, and end the request.

Instead, it’s up to the actual controller to do the outputting, and end the request, if that’s what it wants to do.

$this->renderTemplate() comes from BaseController, and it’s basically a wrapper for craft()->templates->render(), except that after calling that, it will also set the Content-Type header for the request, insert any queued-up JS and CSS, and then end the request.


How to create a new site (locale: de-AT) based on another site (de) within same installation?

Think if the de site is the default site and the sections are setup to propagate the entries to other sites with the same language (or within the same site group, if de and de-AT will be in the same site group), the entries should be copied to the new de-AT site.


Environment specific siteUrl settings not working

Make sure that you change .dev, .com, etc. to reflect your actual environment URLs. They operate based on a partial string match, so as long as your URL contains one of those substrings, it'll pick up the first one it matches.

For example:

'local.mywebsite' => array(
  'environmentVariables' => array(
    'userSessionDuration' => false,
    'devMode' => true,
    'siteUrl ' => 'http://local.mywebsite',
  )
),

'mywebsite.com' => array(
  'environmentVariables' => array(
    'userSessionDuration' => false,
    'devMode' => true,
    'siteUrl ' => 'http://mywebsite.com',
  )
),

UPDATE

Whoa, I think I may have just realized what the problem is... I copied my example from your original code, and copied a glitch right along with it...

You've listed siteUrl like this:

    'siteUrl ' => 'http://mywebsite.com'

Notice anything? There is an extra space between siteUrl and the closing quote.

    'siteUrl '

... should be:

    'siteUrl'


Freeform is unable to send emails after changing webhost

In that case, it's likely that Sendmail isn't configured on your new host. You could contact them for help in setting that up, though I'd recommend considering a switch to sending via SMTP/API. There's a bunch of different services out there, many of which have free tiers if you're not sending many emails - SendGrid, Mandrill, Amazon SES are a few options available.


Impossible to invoke a method ("getUrl") on a null variable

You can do it like this:

.bg{
    background-image: {{ entry.siteBg.first().getUrl('bodyBg')|default(siteBgFallback.siteBg.first().getUrl('bodyBg)}}
}

And the same for the other one. What you are doing is the following:

Set an item that can be empty (hence the |default).
If the item is empty go to the fallback (the part between the default brackets).

For more info on the default filter check here


Have you tried using {{ craft.entries.id(entry.id).locale(locale.id).first().url }} inside the for loop you have made?


You'll need to use the {% nav %} tag to output nested
s as documented here:
https://craftcms.com/guides/displaying-a-navigation-for-a-structure-section

{% set categories = craft.categories.group('projectType').all() %}
{% nav category in categories %}
  {% if category.level == 1 %}

{{ category.title }}

  {% else %}

{{ category.title }}

  {% endif %}
  {% ifchildren %}

      {% children %}

  {% endifchildren %}
{% endnav %}

This answer should help too:
https://craftcms.stackexchange.com/a/4453


How can I safely identify a single asset-folder?

Moving a folder is a pretty complex operation. You have to move all the files contained in the folder, all of the subfolders and all of the files contained in the subfolders. Another thing to consider is that a move is essentially a copy+delete.

So, how Assets goes about all of this is that firstly it mirrors the subfolder structure to be moved in the target destination. It then moves the files one by one. After that, it deletes all of the old folders.

Dividing the operation into many steps accomplishes several things:
1) It allows for displaying the progress bar.
2) It divides the processing time and memory needed across multiple requests, helping prevent timeouts
3) If the user closes the browser window, there is at least fault tolerance and no files are lost - you just get duplicates of some files and you can retry the same operation using "replace" instead of trying to figure out which files were moved and which were not.

So, the folder ID changes, because it's not the same folder anymore. Theoretically, it would be possible to manually adjust the folder IDs afterwards so that they remain unchanged, but I don't think that's a good precedent.

I could argue that folder IDs are a Craft internal thing and relying on them is not encouraged, however, I would just offer a better solution UX wise - just use an Asset source type drop down selector and a text box for the relative path. Not only it would be less amibigious than a magical ID, it would also be more consistent with user experience of addressing folders while also pointing to a specific spot, instead of an entity, which is definitely better for long-term maintenance.


You could use Twig's replace filter on output:

{{ entry.richtext_field_handle|replace('&': '&amp;') }}

At first glance I couldn't find a Redactor setting which would help you, but you might want to check yourself, or even write a Redactor plugin.


I wrote a plugin that posts to Buffer.com (which is free for up to very reasonable levels of activity).  Buffer in turn allows you to post to Facebook, Twitter, LinkedIn, Google+, etc.:

https://github.com/khalwat/buffer

I use it on several sites to do exactly what you describe.


I had to get this working just the other day. Here is what I did:

{# Get the relevant entries #}
{% set categoryQuery = craft.request.getParam('category') %}
{% set categories = craft.categories.group('sectionName').slug(categoryQuery) %}

{# Set the search parameters #}
{% set searchParams = {
    relatedTo: categories,
    section: 'sectionName'
} %}

{# Get the relevant entries #}
{% set relevantEntries = craft.entries(searchParams) %}

In the form I have:

<form action="">

{% for category in craft.categories.group('services') %}
    <input id="{{category.slug}}" type="checkbox" name="category[]"  value="{{ category.slug }}" {{ category.slug in categoryQuery or categoryQuery == null  ? 'checked'}}>
    <label for="{{ category.slug }}" >{{ category.title }}</label>
{% endfor %}

</form>

This seems to work for me.


Absolutely! In fact, you've outlined the steps needed to do so...

Rename craft folder
Change $craftPath value in index.php

That's it!


Looking for a private commenting solution for member area

Something like this should work, but keep in mind there are lot's of ways to accomplish this. Without knowing your requirements, I'll assume you want an index page of assets, that link to an asset detail page. The detail page would show all comments and provide a form to add new comments.

On your assets index page (i.e. '/clientarea/lightbox'):

{% requireLogin %}

{# show user profile information (if needed) #}

    {{ currentUser.firstName }} {{ currentUser.lasName }}

{# loop through images in Assets field #}

Images

    {% for image in currentUser.assetsFieldHandle %}

            {# display image, title and link #}

            {{ image.title }}

            View image

    {% endfor %}

{# repeat for videos, etc #}

In your asset detail page (i.e. 'clientarea/lightbox/media/123' ). Note: to get this uri, you can either create these folders in your templates folder (i.e. 'clientarea/lightbox/media/_entry.html'), or create a custom route.

{% requireLogin %}

{# fetch image #}
{% set imageId = craft.request.lastSegment %}
{% set image = craft.assets.id(imageId).first %}

{# check whether image exists, otherwise redirect 404 #}
{% if not image %}
    {% redirect 404 %}
{% endif %}

{# check whether they are authorized to view this asset #}
{% set authorized = false %}
{% set authorizedImages = craft.assets.relatedTo(currentUser) %}
{% for authorizedImage in authorizedImages %}
    {% if authorizedImage.id == image.id %}
        {% set authorized = true %}
    {% endif %}
{% endfor %}

{# if not authorized, redirect to 401 #}
{% if not authorized %}
    {% redirect 401 %}
{% endif %}

{# show user profile information (if needed) #}

    {{ currentUser.firstName }} {{ currentUser.lasName }}

{# display image details #}

    {# display image and title #}

    {{ image.title }}

{# fetch comments from the 'clientComments' section that are related to this image #}

    {% set comments = craft.entries.section('clientComments').relatedTo(image) %}
    {% for comment in comments %}

{{ comment.commentTextFieldHandle }}

    {% endfor %}

{# display a form to add a new comment #}

    <form method="post" accept-charset="UTF-8">
        {{ getCsrfInput() }}
        <input type="hidden" name="action" value="entries/saveEntry">
        {# reload the current page on successful form submission #}
        <input type="hidden" name="redirect" value="{{ craft.request.path }}">
        {# section id for 'clientComments' #}
        <input type="hidden" name="sectionId" value="2">
        <input type="hidden" name="enabled" value="1">

        {# hidden field to save the image id #}
        <input type="hidden" name="fields[commentAssetsFieldHandle]" value="{{ image.id }}">

        Comment
        <textarea id="body" name="fields[commentTextFieldHandle]"></textarea>

        <input type="submit" value="Add comment">
    </form>

You will likely also need to add some checks for the asset type, in order to determine how to display the asset. But you get the general idea.

You will also need to make sure that they have permission to create entries in the clientComments section (but not view or edit other peoples entries).

And if the image or video is displayed on more than one user's profile, then you will also need to factor in the author when searching for comments. Either that, or also add a related users field to the comments section, and then search for comments related to both image and currentUser.


Problem with Twig group function, group by year

You don't mention where you tried putting the reverse filter, but perhaps you put it in the wrong place? It should go here:

{% set entriesByYear = entries|reverse|group('postDate.year') %}

I've tested this and it works ok for me.


The title field supports ternary syntax conditionals. You could do that like this:

{firstName} {middleName|length ? middleName ~ ' '}{lastName}

That says "if middleName has length, print it out, and append a space with ~.

Also part of the ternary syntax is the "else" statement, which looks like the below. This is the code I use for most of my asset alt texts for accessibility.

{{ asset.assetAltText|length ? asset.assetAltText : asset.title }}

If asset.assetAltText has a length, use that. Otherwise use the asset title as the alt text


query orders by date AND time in craft commerce

'>= ' ~ dateFrom|date('c')

is correct to output the DateTime object as a string with the time (and timezone) included. If you don’t use the filter it’s output in the Y-m-d format by default.

So my recommendation would be to double check what dateFrom|date('c') actually outputs and to compare it with the dateOrdered values in the CP or database.


Check if we're the second or last sunday of the month today

Maybe it doesn't work because the monthyear variable is formed in dutch and not english?

Yes that's part of the problem. Have a look at PHP's relative formats page to see what it supports.

You can actually pull off what you're doing with the this keyword.

{% set secondSunday = now|date_modify("second sunday of this month")%}
{% set lastSunday = now|date_modify("last sunday of this month") %}

You also don't need to define (or override) now since Craft will always set that to a DateTime object for you.


That syntax looks to be for Redactor 2. The latest versions of the redactor plugin (starting from 2.0) use Redactor 3. The syntax has changed slightly


There are so many tables that phpMyAdmin paginates them. All the tables that came after craft_tags alphabetically are on the second page, making it look like there is no craft_users table. Pagination controls are at the top:

Reason I know? I just made the same mistake.


Yes, if you don't include the dropdown field in your entry form, Craft will store the default value for that field, if one has been set. If no default value has been set, then the value will be null.


You can use entry.level in a conditional:

{% set entries = craft.entries.section('spb') %}
{% nav entry in entries %}

    {% set liTagAttributes = entry.level == 1 ? 'class="uk-parent" data-uk-dropdown' : 'class="uk-child"' %}

        {{ entry.title }}
        {% ifchildren %}
            ...
        {% endifchildren %}

{% endnav %}

I set a intermediate var to keep the template code clean. If you don't have many levels in your structure, you could also consider to not use the nav tag at all and nest your navigation levels using hasDescendents and getDescendents(1) (see the example code I posted here).


The asker was able to solve their question and confirm that MailGun can be used with Craft. In the comment they state:

  Just FYI: requiring vendor/autoload.php (from my plugin) worked and
  correctly loads Mailgun. So I guess it works, it's just (more than a
  little) ugly

We have had success integrating Craft with MailGun in our plugins as well.  While we have not released our integration publicly, we have a Sprout Email MailGun integration used by our direct customers and we were able to successfully integrate with Email Lists and Campaigns, and allow users to build Emails using Craft templates with Live Preview and send them through the MailGun API.


How can I find entries that link to a given entry?

Have you thought about running something like Screaming Frog https://www.screamingfrog.co.uk/


Is it possible to have secure (private) assets?

I ran into this requirement today and initially assumed a plugin would be required, but then I spotted that the native Assets action menu already included a Download File option and it was working just fine with files that weren’t publicly accessible. Maybe we could use that rather than reinventing the wheel?

If you check DownloadFileElementAction.php you can see the markup and JS that’s used for this button in the control panel. It generates a simple <form> tag that POSTs to assets/downloadAsset. With a tiny bit of tweaking that can be converted to a code suitable for use in a frontend template:

<form method="post" target="_blank" action="">
    {{ getCsrfInput() }}
    <input type="hidden" name="action" value="assets/downloadAsset" />
    <input type="hidden" name="assetId" value="123" />
    <input type="submit" value="Submit" />
</form>

This works a treat and includes all native permissions checks as you’d expect. So long as the requesting user has the viewAssetSource permission for the Asset Source the download will work. If the requesting user is logged out then they are automatically redirected to your loginPath.

The only snag I’ve noticed is that Craft does return a JSON formatted error string if your user doesn’t have permission to view the asset. In my case this doesn’t matter, as all authenticated users will have permission to view the files - we’re just trying to prevent guests from seeing them.

Since this approach requires POSTs it’s a bit limiting (secured img tags are a non-starter), but for typical download button use cases it looks fine to me and avoids the need for third party plugins.

(This is a Craft 2 build, I haven’t tested this with Craft 3)


How to reference an entry field in a guest user form?

So, I found the answer after much digging.

Thanks to this answer https://craftcms.stackexchange.com/a/9831/7962

I see that the entries field type has to be referenced with an additional set of brackets.  My form now works after changing my input to:

<input type="hidden" name="fields[event][]" value="{{ eventId }}">


How do I get elements using getCriteria from a specific date?

Something like this should work:

$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section  = 'sectionHandle';
$criteria->postDate = array('and', '> 2014-11-03 23:59:59', '< 2014-11-05 00:00:00');
$results = $criteria->find();


If you already have the product

PHP

$product = Product::find()->one();
$variants = ArrayHelper::filterByValue($product->variants, 'enabled', 1);

Twig

{% set product = craft.products.one() %}
{% set variants = product.variants|filterByValue('enabled', "1") %}

If you don't have the product

Twig

{% set variants = craft
    .commerce
    .variants
    .productId(x)
    .all()
%}

PHP

$variants = Variant::find()
    ->productId(x)
    ->all();


If you don't want to get into plugin controllers and actions you can replicate this format here: https://craftcms.com/docs/templating/entry-form

And trick Craft into believing your data comes from an entry form.


How to understand this exception error in context?

If you leave off the closing {% endcache %} tag, then you should always get the error that you received with devMode enabled.  If devMode is disabled, you'll get the default 500 error template.

I would disable the nginx microcaching while you're testing this to make sure that you're not getting erroneous caching results.


Ajax - Create tag with custom ID programatically

You'll need to create a new table/record to store the data

class IdRecord extends BaseRecord
{
    /**
     * Returns the name of the database table the model is associated with (sans table prefix). By convention,
     * tables created by plugins should be prefixed with the plugin name and an underscore.
     *
     * @return string
     */
    public function getTableName()
    {
        return 'ids';
    }

    /**
     * Returns an array of attributes which map back to columns in the database table.
     *
     * @access protected
     * @return array
     */
    protected function defineAttributes()
    {
        return array(
            'oldId'   => AttributeType::Number,
            'newId' => AttributeType::Number
        );
    }
}

Create a new Controller and store with the record

public function actionCreateTag()
{
    $this->requireLogin();
    $this->requireAjaxRequest();

    $tag = new TagModel();
    $tag->groupId = craft()->request->getRequiredPost('groupId');
    $tag->getContent()->title = trim(craft()->request->getRequiredPost('title'));
    $oldId = craft()->request->getRequiredPost('oldId');

    if (craft()->tags->saveTag($tag))
    {

        $tagMap = new IdRecord();
        $tagMap->oldId = $oldId;
        $tagMap->newId =  $tag->id;
        $tagMap->save();
        $this->returnJson(array(
            'success' => true,
            'id'      => $tag->id
        ));
    }
    else
    {
        $this->returnJson(array(
            'success' => false
        ));
    }
}

And when you are saving your entries you'll do

$entry = new EntryModel();
// ... set your content
$oldId = 'number of your old WP tag id';
$tag = IdRecord::model()->find('oldId = :oldId',[
    'oldId' => $oldId
]);
$entry->getContent()->setAttribute('yourTagFieldHandle', $tag->newId);

You can use pluginfactory.io to create your boilerplate.

Edit

Another approach. If you receive the title of the tags as an array like ['tag1', 'tag2', 'tag3'] would be something like

$ids = [];
foreach($tagTitles as $tagTitle){
    $criteria = craft()->elements->getCriteria(ElementType::Tag);
    $criteria->title = 'your Tag Title';
    $tag = $criteria->first();
    if($tag){
        $ids[] = $tag->id;
    }
}
$entry->getContent()->setAttribute('yourFieldHandle', $ids);


How can I write a PHP script to zip and download an Assets subfolder?

Yes, you'd need to write a plugin to do this... or you could write a module. There are some plugins that may already do what you want tho: Squeeze / Compress


Is there a way to divide an entry's data into multiple subviews with unique URLs?

Disclaimer: I haven't ever used structure, but hopefully the method described below also works for that section type.

You can do this quite easily with URL-segments

Consider a URL like so:

http://www.domain.com/section/entry/

http://www.domain.com/section/entry/subview-1

And so on.

The section/entry route will hit your entry template, but you can create a new route

section/{slug}/*

And point it to your subview template.

There, you ask craft for whatever is in URL segment 3 like so:

craft.request.getSegment(3)

And display content based on that.

To get the entry you are on currently, just filter on segment 2 like so:

{% for entry in craft.entries.section('section').slug(craft.request.getSegment(2)) %}
    {{ entry }}

{% endfor %}


Equivalent of "EE Pages" module in Craft?

A common approach is to create a Structure for the pages, and use a Content Builder where you can use Matrix blocks of various types to allow the client to build out the pages as they see fit in the Structure.


Craft updater still spinning after at least half an hour--no error message

If you have ssh access to your remote server you might be better off just updating composer via command line. I find it's ofter faster and less prone to causing errors by updating composer and craft this way.

Let me know if you need help doing that.


How to fetch entries from multiple sections

You can insert an array of different sections instead of a single one to pull entries from multiple sections

{% set entries = craft.entries.section(['sectionHandle', 'sectionHandleTwo']).limit(10) %}

You can also write that

{% set entries = craft.entries({
  section: ['sectionHandle', 'sectionHandleTwo'],
  limit: 10
}) %}

If you remove the .section() / section:..., entirely you'll fetch all entries from all sections.
Here's a link to the docs


What can we do to help avoid member activation emails going to spam?

This the best article I've read on reliably delivering emails through code: http://blog.codinghorror.com/so-youd-like-to-send-some-email-through-code/


Running composer commands will not affect the data in your Craft database directly. The only scenario that might update your data or schema would be if you added a new plugin that had an install migration or updated a plugin or module that included an migration. These migrations would not get run during your composer command, but could get triggered when you visited the /admin area of your control panel or ran a command like ./craft migrate/all.

Due to the timing of multiple major releases between Sprout, modules that Sprout depends on, and Craft (Craft 3.1 should have also been considered a major release), there are several tricky upgrade scenarios between Sprout and Craft between the Craft 3.0 and 3.1 set of dates.

The easiest path around these is to upgrade to the latest of everything all at once. composer update alone will not upgrade to the latest major release, only to the latest releases defined in your composer.json. To make sure you are upgrading to the latest of everything:

Review each package in the require array of your composer.json
Update each package to the latest version release.
Once all packages are defined with their latest versions, run composer update

Regarding version constraints in your composer.json file, you'll probably want to require an explicit version of Craft and us the Caret Version Range for plugins:

{
  ...
  "require": {
    "craftcms/cms": "3.1.23",
    "vlucas/phpdotenv": "^2.4.0",
    "barrelstrength/sprout-forms": "^3.0.0-beta.50"
    "barrelstrength/sprout-forms-range-slider": "^1.5.0"
  }
  ...
}

By updating to the latest versions of everything all at once, you'll ensure that the major releases of supporting modules that may be used by more than one plugin are updated and resolved together.


How can I incorporate a variable into a string?

If you‘ve got a multi-lingual site (or even if you don’t), you can pass variables into strings with the |t filter:

{{ "Welcome back, {name}"|t( {'name': currentUser.name} ) }}

(See http://buildwithcraft.com/help/static-translations for details on how you can use the |t filter to translate your text.)


Twitter API request for images with DUKT twitter

I have used it like this. You can find the documentation for most fields on Twitter. Truth be told, the DUKT documentation is not too transparent.

{% set tweets = craft.twitter.get('statuses/user_timeline', { user_id:'', count: 10, trim_user: false }) %}
{% if tweets %}

        {% for tweet in tweets %}

{{tweet.text|autoLinkTweet}}

           {{ tweet.created_at | twitterTimeAgo )}

        {% endfor %}

{% endif %}

Update

You have several entities in the data you get back from Twitter API (as described by Twitter):  media, urls, user_mentions, hashtags, and symbols. The DUKT plugin, however only gives back urls, user_mentions, hashtags, and symbols as far as I see in the error messages they provide.

 {{tweet.entities}}


How do I create pagination links for my entry index page?

You have your {% for %} and {% paginate %} tags in the reverse order. You need to wrap the loop and the pagination URLs with the {% paginate %} tag pair:

{% paginate craft.entries.section('houseRules').limit(1) as entries %}

    {% for entry in entries %}

                {# Content is here #}

    {% endfor %}

    {% if paginate.prevUrl %}Previous Page{% endif %}
    {% if paginate.nextUrl %}Next Page{% endif %}

{% endpaginate %}

Notice how we’re actually looping through entries, rather than a new craft.entries call. That entries variable will be an array of the current page’s entries. All we had to do is define what we wanted that variable to be called (e.g. “entries”).

See http://buildwithcraft.com/docs/templating/tags#paginate for more details on what can be done inside the {% paginate %} tag pair.


I assume you're referring to template caches with the {% cache %} tag.

If so, then yes, the {% cache %} tag by default will cache it's contents on a per URL and per locale basis.

If you use the globally parameter, then it will just be on a per locale basis.


You can wrap your HTML in a {% set myString %} block and use myString however you need too.

{% set myString %}
{% set resultsNum = 0 %}

{{ block.location }}

{% set searchString = block.location %}
{% for entry in craft.entries.section('journal').find() %}
{% for block in entry.locations %}
    {% if block.type == "location" %}
    {% if block.location == searchString %}
        {% set resultsNum = resultsNum+1 %}

{{ entry.title }}

    {% endif %}
{% endif %}
{% endfor %}
{% endfor %}

{% endset %}