Back-up doesn't work in Craft CMS 3 on MAMP locally

I have just run into a similar problem.

I'm not sure if this is what fixed it but try creating an Envvars file as per jonlivingstone's comment here https://github.com/craftcms/cms/issues/2364

Once I had done that my backup ran. I then had to switch MAMP out of FastCGI mode otherwise I got a 500 error at the end of the update process.


User activation via email does not work when system status is "off"

This has been changed on the upcoming Craft 2.3 release such that if the system status is set to off, account verification and set/forgot password logic will still run.


Your syntax is a bit off – the search() parameter doesn't accept multiple parameters, only a search query (e.g. .search('body:foobar')) or an object containing the search query plus search term options. In your case, you're actually passing an object (.search(entry.clientsOrAgency)), in which case Craft will look for a query parameter on that object (the second parameter is just ignored). Hence your error.

That being said, here's what you probably want:

{% set testimonial = craft.entries.section('testimonials').search('clientsOrAgency:'~type).order('RAND()').limit(1) %}

The above will search for entries in the testimonials section, which has the value equal to type in each clientsOrAgency field.

However – unless you need (which can be enabled as a default for all searching in Craft, or per-search using search term options mentioned above) for the clientsOrAgency field, I don't actually think using search() is the appropriate approach here. The following would be easier and probably more performant:

{% set testimonial = craft.entries.section('testimonials').clientsOrAgency(type).order('RAND()').limit(1) %}

Also, you should probably add .first() to your craft.entries query, in order to only pull a single entry:

{% set testimonial = craft.entries.section('testimonials').clientsOrAgency(type).order('RAND()').limit(1).first() %}

{% if testimonial %}
    ...
{% endif %}


External liblary class inside plugin controller

Is this some kind of namespace issue?

Yes.  If the class you're trying to instantiate is in a namespace, you'd need to indicate that:

$object = $rest = new \the\library\class\namespace\mail_delivery();

If it does not use namespaces, it's probably in the global namespace:

$object = $rest = new \mail_delivery();

If you do it like in your example:

$object = $rest = new mail_delivery();

Then PHP will assuming it's in the current file's namespace (Craft) and you'll get the error that you see.


In case it helps someone, my issue was the permissions for the root index.php file...It was 666 (writeable by group) and when I switched that file permissions to 644, the installation was able to move forward.


I am pretty sure it's the same for a product as it is for any other Craft element, like an entry.

To get simple fields:

$lineItem->purchasable->product->myCustomFieldHandle

To handle matrix fields, just loop through the matrix blocks:

$matrixBlocks = $lineItem->purchasable->product->matrixFieldHandle;
foreach ($matrixBlocks as $block){
    echo $block->id;
    echo $block->fieldHandle;
    if ($block->fieldHandle == "whatever"){
          etc
    }
}

Certainly that works with SuperTable fields on a product, pretty sure it's the same with matrix fields.


Mixed relation criteria operator in Element API

Something like this should work to combine 'and' and 'or' conditions.

'relatedTo' => [
    'and',
    ['element' => [124, 99]],
    ['element' => 105],
    ['element' => 231],
],

And this is the pattern I’m usually using to build the relatedTo param dynamically. I also try to be explicit about the direction (sourceElement / targetElement) and the relation’s field.

$query = craft()->request->getQuery();

$relatedToParam = ['and'];

if ($query['reg']) {
    $relatedToParam[] = [
        'targetElement' => $query['reg'],
        'field' => 'myRegFieldHandle',
    ];
}

// repeat for all our other relatedTo conditions

$relatedToParam = count($relatedToParam) > 1 ? $relatedToParam : null,

return [
    'criteria' => [
        'section' => 'resources',
        'relatedTo' => $relatedToParam,
    ],
];


Craft Commerce multisite, different tax rates

As of Commerce 2.0, there is no support for multi-site apart from a product’s custom field information.

A cart exists in the session, once per Craft installation, and there are not separate carts per site.

Multi-site is something we plan to add in the future.

Having said that, a cart stores the current orderLanguage based on the current language of the site the order is being made in. A custom adjuster could be written to add custom tax costs based on this information: https://github.com/craftcms/commerce/blob/develop/docs/adjusters.md


getHeadHtml() not outputting CSS included with {% includeCss %}

This is just an order of operations issue. The documentation is correct, but incomplete.

getHeadHtml() will only output head HTML that was queued up for it before the function was actually called. Any head HTML that is queued up after you've called getHeadHtml() will end up getting inserted in the default location - right before the </head> tag.

So, if you had this in your template instead:

{% includecss %}
  .content {
      color:  red;
  }
{% endincludecss %}

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Title</title>
    <!-- Here should the CSS start -->
        {{ getHeadHtml() }}
    <!-- Here should the CSS end -->
  </head>
  <body>

  </body>
</html>

Then the CSS would get included between the HTML comments as you’d expect.


multi-environment config for {siteURL} not working

Multi-environment configs require you to create a '*' config array, even if it’s empty because there aren’t any config settings that you need to set globally. Simply having that '*' array is how Craft is able to determine that this is a multi-environment config, as opposed to '.dev' and '.org' just being normal config settings. (See the warning on http://buildwithcraft.com/docs/multi-environment-configs.)

So this should work for you:

<?php

return array(

    '*' => array(
        // It's OK if this is empty, as long as it's here.
    ),

    '.dev' => array(
        'environmentVariables' => array(
            'siteUrl'  => 'http://mysite.dev:8888',
        )
    ),

    '.org' => array(
        'environmentVariables' => array(
            'siteUrl'  => 'http://mysite.org',
        )
    )
);


Why is Craft extremely slow when using a shared, external database?

My suggestion would be to do what is outlined in Database & Asset Syncing Between Environments in Craft CMS

It's a little bit of logistical organization coupled with some scripts to do the asset/db synchronization.

It's going to be much, much faster than working with a remote db... and safer, too.


how to check for the 2nd, 3rd, 4th… image in an asset's field

Since in Craft you will loop over an Assets field, you could use the loop.index variable: https://twig.symfony.com/doc/2.x/tags/for.html to check for the nth iteration.


Why do the plugin resource paths include the localization prefix?

Good question... As far as I know, the plugin's resource paths should not include the localization prefix. The resources are being called via PHP in the most direct way possible:

craft()->templates->includeJsResource('smartmap/js/smartmap.js');
craft()->templates->includeCssResource('smartmap/css/smartmap.css');

I'm not entirely sure, but I suspect this may be a Craft bug. I've reached out to Pixel & Tonic in order to fully diagnose the problem. If the plugin code needs to be corrected, I will implement a fix as soon as we can figure out what's going on.


Plugin: Making a record's dateUpdated column update to CURRENT_TIMESTAMP

How are you inserting the data?

If you're inserting data through any of Craft's Active Record or DbCommand classes (craft()->db->createCommand()), then Craft will take of updating dateUpdated for you.

If you're using raw SQL, then you'll have to keep track of it yourself.


Localized Site -> howto redirect Browser

Here is what i have done. Not sure if it helps you. I can't add comments. So here you go. This is based on geo plugin

Plugin serviceclass:

//to get local ele
private function getLocalElement()
    {
        $source=craft()->request->getRequestUri();
         if($source==''){
             $source = 'home';
         }
        return  craft()->elements->getElementByUri($source);
    }

//finds locale and redirect
private function redirectToLang()
   {
       $value=$this->detectBrowserLang()."_".strtolower($this->detectCountryCode());
       if(in_array($value, craft()->i18n->siteLocaleIds)==1){
            $element=$this->getLocalElement();
            if(!is_null($element)){
                $localElementUri = craft()->elements->getElementUriForLocale($element->id, $value);
                header('Location: '.$this->configBaseUrl().'/'.$value.'/'.$localElementUri, true, 302);
            }
        }

   }

//browser lang
private function detectBrowserLang()
   {
        $browserLang=craft()->request->getBrowserLanguages();
        if(isset($browserLang)){
            $lang=substr(strtolower($browserLang[0]),0,2);
            return $lang;
        }
   }

//detect country code by geo
private function detectCountryCode()
    {
        $info=$this->getInfoGeo();
        $countryCode=strtoupper($info["country_code"]);
        return $countryCode;
    }

Basically checking browser lang and country code(geo) with craft locales.


Are you accessing the same databases? You need to make sure that the local database has been uploaded to the remote server. Then all your entries should show up.

You can back up your local database by going to /admin/settings on your local machine. Then you'll need to upload that database to the remote server.

You can also learn more about setting up a multi-environment config in the Craft documentation.


You are going to have a hard time if you want to use Yii2 with Craft 2 since they are totally incompatible. Craft 2 uses yii and Craft 3 uses Yii2. You can't mix them. Furthermore you'll need multiple custom changes when you want to drop the native Craft user registration and replace it with Yii2 (less powerful) user registration. (what's wrong about Crafts one?)

Do you have certain reasons why you are not going to use existing ways? I can't think of a "fast and easy" way to achieve your goal, especially if you are new to Craft because it's a lot of work to drop existing login/registration mechanisms.

Here is an example how to register users with Craft methods https://docs.craftcms.com/v3/templating/examples/user-registration-form.html you can include the permission to give them CP access and redirect them there


How secure is Craft and why is it secure?

Updated Answer for Craft 3

I've updated and consolidated the technical parts of this for Craft 3 and placed them in a security FAQ for easier referencing: https://craftcms.com/guides/security-faq

Original Answer for Craft 2)

Let me get this out of the way, first... there is no perfect software.  Bugs exist and some of those will be security related.

Having said that, we're pretty paranoid people (thanks NSA!) so we think about security a lot and take it seriously.

  What measures have been put in place in regards to securing Craft at the core level.

Off the top of my head here's some of what we currently do:

Perhaps the biggest thing Craft has going for it, in the event a security related bug is that we can get the fix deployed quickly to our users with Craft's one-click auto-updating.  In addition to that, we can mark a release as "critical", which gets special attention in the control panel UI making it obvious there is an update that needs to occur. Thankfully, we've yet to use that feature.
Craft/Yii uses PDO for all database queries, so all dynamic values are parameterized helping prevent SQL injection attacks. Don't think SQL injection attacks are still a problem? They are... even with the more popular apps.
Craft validate sensitive cookie data to ensure no cookie tampering has taken place between requests.
Craft has CSRF token validation support to help prevent CSRF attacks.
Twig auto-encodes all HTML by default, helping avoid XSS attack vectors.
Rich Text Fields have an HTML purification option that is enabled by default, which strips any malicious strings from the input. This is powered by the venerable HTML Purifier.
Craft ensures that sensitive data (server paths, stack traces, etc.) doesn't get exposed to an end-user in the case where an error occurs and Dev Mode is disabled.
Craft uses email verification for creating new accounts. You can configure how long the token in that email is valid.
Craft makes the control panel trigger configurable for better security by making it harder for people guess the entry point to your control panel.
Craft exposes the blowFishHashCost config setting which helps control how long a breached password hash will survive a brute-force attack.
If a user has an invalid login attempt X times within a Y window duration, you can force them to wait for Z minutes before they try again or permanently lock their account until an admin unlocks it. All configurable.
The user session duration is configurable.
The default file and folder permissions are configurable.
Craft jumps through some pretty significant hoops to ensure in-app purchasing is secure even on installs without SSL enabled.
Craft helps prevent session/cookie hijacking, by doing things like storing the browser's user agent string in the identity cookie and validating that it matches on subsequent session requests.
Craft will deny all requests to start a session that don't present a user agent string or IP address to prevent direct socket connections from trying to connect.
Craft uses elevated sessions that forces people to re-enter/validate their existing password for critical actions (changing passwords, emails, permissions, etc.). By default these elevated sessions are valid for 5 minutes, but that is configurable.
No one, not even admins, can directly change another user's password.
Craft's codebase has been frequently audited by third party security firms and with tools like OWASP's Zed Attack Proxy Project.
Craft has permission enforcement at the controller level for all actions that make changes to the site.
Craft requires PHP 5.3. Some applications are still supporting back to PHP 5.2.4, which is over 14 years old (approximately 980 internet years).  Craft 3 will require 5.6.
Craft requires mcrypt with blowfish for password hashing, arguably the currently most secure and reliable method of password encryption.
There is a help article explaining how to force SSL for all CP requests. (http://craftcms.com/help/force-ssl)
Craft inserts caution tape across the top of all control panel pages when running in Dev Mode, reminding you not to use it on production.
Craft can be configured to store PHP session files in a Craft folder (craft/storage/runtime/sessions) so they don't get mingled with other app's session files on shared host.
Craft provides granular permissions on user accounts and user groups via a intuitive/simple permission system.
Craft provides a preventUserEnumeration config setting for people that want to prevent user enumeration attempts on their forgot password pages.
Craft provides a validateUnsafeRequestParams config setting that will ensure certain request parameters, such as redirect, are not tampered with on a POST request preventing a Denial of Service (DoS) attack vector. This config setting will be removed in the upcoming Craft 3 and the behavior will be enabled by default in Craft itself.
Craft's session cookies get set to HTTP only.
By default Craft will set the secure flag on all cookies if the request is over https. You can set the useSecureCookies config setting to true to force the secure flag no matter what.
Because Craft requires OpenSSL, we have a cryptographically strong way of generating randomness for things like email verification and password reset tokens.
Craft keep logs of any error and/or suspicious activity to help track issues down.
Any uploaded files have their file names cleaned as well as any code embedded in the image stripped.
Craft's default folder structure encourages people to keep Craft's application files above the web root and the requirements page at yourdomain.com/cpTrigger/utils/serverinfo does a test and warns you if sensitive Craft folders appear to be in the public web root.
We provide an RSS feed for updates you can subscribe to that includes all bug fixes.
Craft sets the X-Frame-Options: SAMEORIGIN header on all control panel requests to prevent the CP from being loaded in an iframe to help prevent clickjacking.
Craft sets the X-Content-Type-Options: nosniff header on all control panel requests to help prevent some older IE/Ajax XSS attack vectors.
Craft uses timing safe methods for sensitive comparisons like checking password the equality of password hashes helping prevent timing attacks.
There is a “Securing Craft” support article to help guide people through securing their Craft installation.

And keep in mind that there are still plenty of additional security related things on "The List" that we plan on implementing.

  What measures have been put in place in regards to Craft's Plugins which make use of (connect to if you will) Craft's core?

Permissions are enforced at the user/user group level, so if a user is using a plugin as an admin, then they'll be able to use any of Craft's services that require an admin.

  If possible (without an opinion piece being written), is there anyway to make a comparison between other popular CMS and Craft in regards to security?

Someone smarter than me will have to do that.

  How does one know third party libraries which are used in Craft are secure? Craft is built on Yii PHP Framework and Twig. How secure are these?

Lumping these two together because as far as Craft is concerned, Yii and Twig are both third party libraries as well.

Remember... there is no bug-free software.

I'm much more comfortable with using 3rd party libraries for things like a templating language, an RSS feed reader, an email library, an HTTP client and even (especially) a framework instead of attempting to roll our own for various reasons.

It's not our core competency.  The people working on these libraries have gained very specific, very valuable domain knowledge about the problems their libraries are trying to solve. We can't (and shouldn't) try to be the experts in all of those areas and we should be focusing on what we do best. For example... if I had to write this code, I'd drink myself to death.
The libraries we use have been around a long time, are very popular and have been tried and tested across countless installs, configurations and use-cases.  On an order of magnitude greater than the Craft install base is. The more installs and eyeballs on the code, the more it's been exposed and audited.
Worst case scenario. A devastating security bug and exploit is revealed before the library has had a chance to release an update (which is kind of a jerk move). If we think the library authors are taking too long for a fix, we can fork the library, fix it with a patch of our own and merge in the official patch when it's been released.

  Has Craft ever had any security incidents to date?

Nothing that's been exploited that we're aware of. Nearly everything that we've found or that people have reported to us has been pretty minor.  i.e. XSS vulnerabilities that could occur in the control panel under very specific conditions.

  In the case there is a security incident how does the team at Craft notify people such incident occurred?

Depends entirely on the severity of the incident.

All fixed bugs get mentioned in the change log and we tweet about every release: http://craftcms.com/changelog

If it is severe, then we have the ability to mark an update as "critical", bringing special attention to it as well as filing an official CVE, blog post, etc.


Craft CMS - 3.6.11.1 - Why are Assets Backed Up to Temporary Storage?

We have isolated the issue to a crone job connected with the Remote Backup Plugin for Craft.
Commenting out the following stops the daily backup.
# /home/forge/www.example.com/craft remote-backup/volume/create
# /home/forge/www.example.com/craft remote-backup/volume/prune

I think there is an issue with trying to connect to the remote storage location.


Solspace Calendar (2.0.0-b9) returning template not found error in CP

Have you checked what values you have for the calendar(s) under the Site Settings: Event URI Format & Template

It's possible you might have something incorrect there. Perhaps the Template path inside the Event URI Format area, instead of a proper value like /calendar_demo/event/{slug}.


How to limit the amount of entries that is output when limit doesn't work

What you probably want is to order them by date and than select the first.

{% set news = craft.entries.section('news').order('postDate desc').first() %}

And if you want to use limit somewhere (but I don't think this is what you are trying to get here) you should add limit(1) to this {% set news = craft.entries.section('news').limit(1) %}


If this memcache cluster is purely for craft caching you could consider using redis instead.

I've found both the old and newer memcache implementations in php to be flaky, but those are personal experiences without any scientific proofs backing them.


I managed to make an entry type that won't let me create any entries. How can I fix it?

It sounds like you're trying to have a dynamic title for that section, based on an Entries field (Venue). Working out the nuances in this situation can be a little tricky, but I think this would do the trick for you:

{{ object.venue.first().title ?? '(no venue)' }}

Let's break down what's happening here...

In this use-case, object is your Entry. Which means that object.venue is your Venue field (which happens to be an Entries field type).

Since Venue is an Entries field type, that means it's going to return an Element Criteria Model. When dealing with an ECM, you need to append something like find() (get all) or first() (get one) to end up with an actual, useful result.

Once we've established that you only need a single Entry (object.venue.first()), let's go ahead and grab the title of that Entry (object.venue.first().title). The good news... that can all be chained together! The bad news... it'll throw an error if the Venue field is left empty.

Which is where ?? '(no venue)' comes in. The double question mark is called a null-coalescing operator. It provides a graceful fallback, suppressing error messages and allowing you to provide a safe alternative.

Put it all together, and you'll have a nice, safe dynamic title.


Check if a FieldHandle exists in Module without throwing 'Invalid field handle' exceptions

Without modifying your code too much, you could simply add an exception handler with a try/catch block.
Another method would be to retrieve the field handles for the entry type's field layout, and check for a match:
Getting the $entryType as necessary,
$etFieldHandles = [];
$fields = $entryType->getFieldLayout()->getFields();
foreach ($fields as $field) {
    $etFieldHandles[] = $field->handle;
}

if (in_array('yourfieldhandle', $etFieldHandles) ) {
    // the field exists in this entry type's layout.
}


I had this issue and solved it by ensuring that the locale checked against in the matchEntry() function in MyNewsChannel.php matched the locale of my site.

The example channel class provided in the plugin repo checks for a site locale set to en on line 27:

if ($entry->locale != 'en') {
return false;
}

My site locale was set to en_us; correcting it in my channel class solved this for me. Maybe this is also the case for you or someone else who has landed here with a similar issue!


I think I got this resolved the proper way... looks like you just need to make sure that your AJAX calls are localized.

In my main _layout template:

<script type="text/javascript">
window.siteUrl = "{{ siteUrl }}";
</script>

Then in my JS, I have this:

$.post(
    siteUrl + 'actions/myPlugin/myAction',
    ...
);

As long as your siteUrl is being localized properly, it should trickle down into the JS... and the localized AJAX path can then load a properly localized template.


Craft 2 - Returning Value in Variable from Plugin to Template

You're close, you don't necessarily need another class or function. Though you may want to change the function name to be a bit more clear, and you may want to move the heavy XML logic into a separate private method.

class AiPaginationTestVariable
{
        public function getXml($params = null)
        {
            // Compile XML
            $xml = $this->_compileXml($params);

            // Return XML or false
            if ($xml) {
                return $xml;
            } else {
                return false;
            }
        }

        private function _compileXml($params = null)
        {
            // Whatever it takes to compile XML
        }
}

Then in your Twig template, you can do something like this...

{% set xml = craft.aiPaginationTest.getXml() %}

{% if false == xml %}
    {# Handle no XML #}
{% endif %}

This might not directly answer your question, but I hope it's enough to get  you back on track.


hashing form fields to prevent tampering

If you're posting to Craft's EntriesController->saveEntry(), then it doesn't do any hash validation.

You'd need to post to a controller of your own (from a plugin or module if you're on Craft 3), then validate the data yourself like the example in the docs you linked to:

$foo = Craft::$app->request->getPost('foo');
$foo = Craft::$app->security->validateData($foo);

if ($foo !== false) {
    // data is valid
}

Then your controller would manually save the entry similar to how Craft does after your validation.


Error when trying to generate a PDF in Craft Commerce

Craft Commerce 1.x uses the Dompdf package to generate PDFs.

The issue is likely a font cache issue, Dompdf caches an index about all fonts. Removing the cache indexes should fix the issue. Remove:

craft/plugins/commerce/vendor/dompdf/dompdf/lib/fonts/dompdf_font_family_cache.php

This is as mentioned in the migration guide and occurs because Craft Commerce has gone from Dompdf 0.6 to 0.8:

https://github.com/dompdf/dompdf/wiki/Migration-Guide

  The class naming conventions required a change to the dompdf_font_family_cache.php file. Though we have attempted to accommodate this change your first step when encountering bugs (if you don't know where to start) might be to reset your font directory (i.e. remove custom font files and the related font metrics files, and remove the non-dist, generated, font family cache file).

First try removing the dompdf_font_family_cache.php as mentioned above. If that doesn't work try removing all files they list above from the same folder. I think that includes all .afm. The directory should end up looking something like the original: https://github.com/dompdf/dompdf/tree/master/lib/fonts


I use this to force the task icon to show up immediately:

Craft.cp.setRunningTaskInfo({
    "id": "task ID",
    "level": "0",
    "description": "description",
    "status": "running",
    "progress": 0
});
Craft.cp.trackTaskProgress();


Impossible to access an attribute on a null variable - on the one() method - all() works!

It feels like not all your products have a fieldPropertiesCategory value defined. Does that work?

{% set products = craft.entries.descendantOf(entry).all() %}
{% for product in products %}
    {% set properties = product.fieldPropertiesCategory.one() %}
    {{ properties ? properties.propCatFieldColor : '' }}
{% endfor %}


One select search for Users in user.group

I suggest you to read the docs about relations. You can search for relations by the following parameter

In its simplest form, you can pass in one of these things to it:
An AssetFileModel, CategoryModel, EntryModel, UserModel, or TagModel object
An element’s ID
An array of element objects and/or IDs

What you pass is a string or to be more specific a url
<option value="{{category.url}}">{{ category.title }}</option>

What you have to do is:
<option value="{{category.id}}">{{ category.title }}</option>

In order to find users related to a category id.
However I strongly suggest you to build your search with PHP if you are going to include multiple parameters (more categories/search terms/complex and+or bindings) it is going to be a mess with twig


Credit card fee to the final order in CP

I would save the response to an incognito field (or fields) on your order (probably both the entire response and also just the fee separate out).

https://github.com/mmikkel/IncognitoField-Craft

The readonly incognito field is particularly good for this sort of thing - I use a bunch of these fields in a debug tab on my order layout to save useful things.

Just create the fields, add the fields to your order, and you update the values with the usual <input name="fields[fieldName]"> syntax with any cart operation, or use setContentFromPost if you're in a plugin:

    $order->setContentFromPost(array(
        'fieldName' => $creditCardFee,
    ));
    craft()->commerce_orders->saveOrder($order);


Editing specific fields from a POSTed form in a plugin

You will want to use PHP's foreach to loop over each of the items (using $i here to keep track of the index). Then if the current item has a start date, do whatever it is you need to edit it inside the loop. Once you've finished iterating over each item, you will need to set that back to $_POST['items'], so that the MultiAdd plugin can pick up your modified array as usual, using craft()->request->getPost('items').

public function actionReorder() {
    // ... a bunch of stuff relating to the cart ...

    // loop through all the inputs for line items and amend any startDate
    $items = craft()->request->getPost('items');

    foreach ($items as $i => $item)
    {
        if (isset($item['options']['startDate']))
        {
            $items[$i]['options']['startDate'] = '???';
        }
    }

    // re-set back to $_POST
    $_POST['items'] = $items;

    // ok now pass it all over to the multiAdd controller...
    craft()->runController('multiAdd/multiAdd');
}


Getting my head round installing plugins from the command line

So this is a MAMP/local dev issue -- run via the CLI, Craft can't connect to the db. Probably it's looking for the wrong mysql.

Check out the MAMP with Composer and MySQL on the Command Line article for details.


Showing a list of selected/related categories to entry

Indigo Viking's code will achieve what you want, but if you want a simpler solution (possibly a bit more performant since there's no second for loop), you could do this instead:

{% set suitability = craft.categories.group('suitability').all() %}

{% for category in suitability %}

        {{ category.title }}

        {% if category.id in product.suitability.ids() %}
            Yes
        {% else %}
            No
        {% endif %}

{% endfor %}

The way this works is product.suitability.ids() returns an array of the element ids of the categories selected in your suitability field. Then you just check if the current category's id is in that array.

Fast, simple, and easy!


You can definitely access and use fields on the entry you're viewing within a matrix field loop. The only thing you need to watch out for is repeating the entry variable in your for loop.

You can simplify your if statement slightly by using {% if not entry.applicationsClosed %}


Deleting one or all Assets from a fieldusing a front end form

Assuming you are on a front end entry form editing an entry, there are a few steps to this.
First get all assets a user can choose from:
{% set allImages = myAssetQuery.all() %}

Next, get the ids of already chosen assets:
{% set alreadyChosenImages = entry.businessStandardImages.ids() %}

Loop over all images, check the ones already selected:
{% for image in allImages %}

    {{ image.title }}
        {{ input(
            'checkbox',
            'fields[businessStandardImages][]',
            image.id,
            { checked: image.id in alreadyChosenImages }
        ) }}

{% endfor %}

Altogether:
{# Get all possible assets #}
{% set allImages = myAssetQuery.all() %}

{# Get the currently related asset IDs #}
{% set alreadyChosenImages = entry is defined
    ? entry.businessStandardImages.ids()
    : [] %}

{# Loop over images and check any already selected ones #}
{% for image in allImages %}

    {{ image.title }}
        {{ input(
            'checkbox',
            'fields[businessStandardImages][]',
            image.id,
            { checked: image.id in alreadyChosenImages }
        ) }}

{% endfor %}

There is also a complete example in the documentation.


As far as I know you can't restrict users to certain folders in the Assets section of Craft, you can only set their permissions for the whole Asset Source.

The only workaround I can think of for you would be to actually remove Authors permissions on the Assets section of Craft completely.

That way the only way they can make Asset updates is when they are editing an entry, and with the permissions structure you have they can only edit entries they have made themselves anyway.

As they don't have access to other people's entries, they can't edit the assets on them.

It may not be the most elegant approach but it would give you the functionality you are looking for. I'm sure others might have a better way of handling it though. Hope that helps a little.


Urgent question - failed plugin and now getting internal server error

This seems unrelated to the Cache Flag plugin, and more likely due to some bad code in config/app.php (or app.web.php).

If you have either of those files, check what changes you’ve made to it/them recently.


Why don't you use the prepared ElementCriteriaModel in the category and change the query?

{% for category in craft.categories.group('whatever') %}
    {% set articles = category.journalismMainCategory.limit(7).order('postDate').find() %}
{% endfor %}

Your category.journalismMainCategory contains an ElementCriteriaModel that will fetch all related entries you can include a limit, change the sort order and execute it, so you'll receive 7 articles with the correct order for each of your categories

Edit: link to the docs


How to get the unverifiedEmail value of a user after a change email request?

You need to select the value

{% set user = craft.users
    .id(currentUser.id)
    .addSelect(['users.unverifiedEmail'])
    .one()
%}
{{ user.unverifiedEmail }}


Show only children of current page in submenu

Ran into the same issues you had. Pulled this from a working site I recently built.

Basically you have to get the topmost page. I found entry.getAncestors().level(1).first() works for that no matter what level you're in.

From there, you just get everything that's underneath it. But first check to see if there's actually any children using {% if topLevel.hasDescendants %}

       <! -- local navigation -->

        {% set topLevel = (entry.level == 1) ? entry : entry.getAncestors().level(1).first()  %}

        {# don't show the tree if nothing's under it #}

        {% if topLevel.hasDescendants %}

{{topLevel}}

            {% set subnav =  topLevel.getDescendants()  %}

            {% nav page in subnav  %}
            {% if page.id != entry.id %}
{{ page.getLink() }}
{%else%}
{{page}}
{%endif%}

                {% ifchildren %}

                            {% children %}

                {% endifchildren %}

            {% endnav %}

       {% endif %}


How to render an entry template in plugin?

If it is a frontend request

$html = craft()->templates->render('_emails/_layout.twig', $data);

and in a backend request

$oldPath = craft()->path->getTemplatesPath();
$newPath = craft()->path->getSiteTemplatesPath();
craft()->path->setTemplatesPath($newPath);
$html = craft()->templates->render('_emails/_layout.twig', array());
craft()->path->setTemplatesPath($oldPath);


Only Install migration is applying on plugin install

It sounds like it's working as expected.

When you add a new migration for your plugin, you're expected to update your plugin's Install.php migration with the new schema changes as well.

You can see the relevant code here: https://github.com/craftcms/cms/blob/develop/src/base/Plugin.php#L149-L161


How can I save a tag value in an entry in Craft 3

The trick here is that Tags are also elements, so you'll need to save them or look them up to assign them. Something like this:

    public function createOrGetTag($keyword, $groupId) {
        $tagQuery = new TagQuery(Tag::class);
        $tagQuery->groupId = $groupId;
        $tagQuery->title = $keyword;
        $tag = $tagQuery->one();

        if (!$tag) {
            $tag = new Tag();
            $tag->groupId = $groupId;
            $tag->title = $keyword;
            Craft::$app->elements->saveElement($tag);
        }

        return $tag;
    }

And then in your field setting, you'd do something like this:

$product->businessTag->id[] = $tag->id;


I don't think it's possible to do with out-of-the-box Twig/Craft, but it's a super-easy plugin to write.

All you'd need is to give your plugin a Template Variable so that you could do:

{% if craft.myAwesomePlugin.fileExists('somePath') %}
    YES
{% endif %}

And your MyAwesomePluginVariable class has a method like:

public function fileExists($path)
{
    return IOHelper::fileExists($path);
}


Yes, you can do the same in Craft using Twig's cycle function:

{% set myClasses = ['classOne', 'classTwo', 'classThree'] %}

{% for entry in entries %}
    {{ cycle(myClasses, loop.index0) }}
{% endfor %}


Everything is set up properly after all. I just wasn't referencing the actual image, but rather its parent record. Correct syntax in this context should have been:
{{ print.printImage.first().getUrl() }}

Feel free to delete this post, or leave it for the config details.


Using a variable that was set in a previous include

So what you're running into is Twig scoping rules, which is discussed at length in the article Twig Processing Order & Scope

The TL;DR is that a variable is only available in the context in which it is defined. Since you're setting the meetings variable in a file you included, that variable exists only in the context of the anonVisitor.logic file.

Additionally, variables defined in a parent context are available to any child templates that are included, but you can't change the values in the child templates, because you're given a copy of the context that goes away when the child templates are done rendering.

What you can do is leverage extends and embed, because templates that extends other templates have the same context as the parent that they extends.


There is a really nice multi-environment configuration method defined on the craft cookbook website, that creates a global php variable called CRAFT_ENVIRONMENT in your main index.php. It seems to me that you could also use this global to define the $craftPath.

switch (CRAFT_ENVIRONMENT) {
    case "dev":
        $craftPath = '../craft';
        break;
    case "stage":
        $craftPath = '../../craft';
        break;
    default:
        // default "production"
        $craftPath = '../../craft';
}

I generally use the above method (without the new switch part) in combination with this configuration method in my general.php config file.


Best way to organise sections and templates

I would use separate Structure for each content type, instead of having them all in a single structure.

Separate structures would allow cleaner 'relationships' between entries.

Your template structure looks good. (could you explain how 'content-page.html' differs from '_entry.html'?)

In addition: I typically add a 'static' Section for each content type so that I can display some introduction text or imagery for a page which displays a collection of entries. e.g.

Sections might be:

Single = "Housing Page"
Structure = "Housing"

Templates:

/housing/index.html would display the content from the Single AND Titles+links to each Housing entry page at:

/housing/_entry.html


Memory usage in sub tasks vs. regular tasks

I think this is difficult to answer properly because it depends almost entirely on what the tasks and subtasks are actually doing.

For example, the main task could do something that ate 400MB of memory and triggered 400 sub-tasks that did nothing but return null not using any memory.

Alternatively, the main task could do nothing but trigger subtasks (using very little memory itself) but each subtask could use 400MB of memory.

Obviously with subtasks you have to me more conscious of memory usage because usually there will be multiple subtasks and there is only ever one main task.


Saving new entry via Ajax then immediately showing it

Use that as your controller, this is the craft default controller actionSaveEntry that you use right now with a few changes. You can access it in Javascript when you use action: "pluginHandle/entry/saveEntry".

namespace Craft;

class EntryController extends BaseController
{

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

    /**
     * Saves an entry.
     *
     * @return null
     */
    public function actionSaveEntry()
    {
        // craft default things.. this is actually the exact same function
        // like you call at the moment, it does the same..
        // just go to the part where I have the !Important! note
        $this->requirePostRequest();

        $entry = $this->_getEntryModel();

        // Permission enforcement
        $this->enforceEditEntryPermissions($entry);
        $userSessionService = craft()->userSession;
        $currentUser = $userSessionService->getUser();

        if ($entry->id) {
            // Is this another user's entry (and it's not a Single)?
            if (
                $entry->authorId != $currentUser->id &&
                $entry->getSection()->type != SectionType::Single
            ) {
                if ($entry->enabled) {
                    // Make sure they have permission to make live changes to those
                    $userSessionService->requirePermission('publishPeerEntries:' . $entry->sectionId);
                }
            }
        }

        // Populate the entry with post data
        $this->_populateEntryModel($entry);

        // Even more permission enforcement
        if ($entry->enabled) {
            if ($entry->id) {
                $userSessionService->requirePermission('publishEntries:' . $entry->sectionId);
            } else if (!$currentUser->can('publishEntries:' . $entry->sectionId)) {
                $entry->enabled = false;
            }
        }

        // Save the entry (finally!)
        // !Important! so this is where your action starts
        if (craft()->entries->saveEntry($entry)) {
            $return['success'] = true;
            $return['id'] = $entry->id;
            $return['title'] = $entry->title;

            // after saving the entry you can render your template
            // the documentation can be found here https://craftcms.com/docs/plugins/templates
            // just read this site and you'll know what to do..
            // this allows you to render your "comments" template like when you
            // visit the page the first initially
            // you'll just do $("#idOfYourCommentsContainer").append(ajaxResponse['html']);
            // and thats it^^
            // in the template you have access to the variables $entry => the new entry
            // and the user currently.. if you need something else, feel free to ask
            $return['html'] = $this->renderTemplate('/path/to/template', array(
                'entry' => $entry,
                'user' => $entry->getAuthor()
            ));

            $return['authorUsername'] = $entry->getAuthor()->username;
            $return['dateCreated'] = DateTimeHelper::toIso8601($entry->dateCreated);
            $return['dateUpdated'] = DateTimeHelper::toIso8601($entry->dateUpdated);
            $return['postDate'] = ($entry->postDate ? DateTimeHelper::toIso8601($entry->postDate) : null);

            $this->returnJson($return);
        } else {
            if (craft()->request->isAjaxRequest()) {
                $this->returnJson(array(
                    'errors' => $entry->getErrors(),
                    'success' => false
                ));
            }
        }
    }
}

If there is an error you get the array with all "mistakes" and error messages. For example if you define the field "headline" as required and the user didn't insert something in the "headline" field your response will be

reponse = [
    "error" => [
        'headline'  => [
            'The Headline field is required //or something like that...'
        ]
    ]
];

You could select the headline field by name or class with javascript and append the error message as well


You should be able to utilize twig's built-in containment operator.

Your code would look like this:

{% if 'vascular' in craft.request.getSegment(3) %}
    ...
{% endif %}

Here is official documentation on the containment operator: http://twig.sensiolabs.org/doc/templates.html#containment-operator.


Services are not meant for rendering templates, but for business logic, saving data, and retrieving data. The setRouteVariables method should only be used in a controller to send some information to a variable.

You can use a controller to reach out to a service for some data, then use the controller to report that data back to the view for display using the setRouteVariables function. You can skirt around this by using Variables to directly call services, using a separate variable for each service function.

  On a related note, is it possible for twig to instantiate a plugin's
  model, with access to all it's properties?

Not directly, and this shouldn't be done. It is best practice to not have views directly instantiating models, but to have controllers and services act as the middle-men. It will help keep your code testable, reusable, and readable.

From the Craft documentation:

Controllers

  Generally speaking, controllers are the middlemen between the front
  end of the CP/website and your plugin’s services. They contain action
  methods which handle individual tasks.

Services

  All of your plugin’s business logic should go in services, including
  saving data, retrieving data, etc. They provide APIs that your
  controllers, template variables, and other plugins can interact with.


Nothing in Craft will automatically delete Matrix fields, and there haven’t been any DB migrations that would have deleted an entire Matrix field. (There was a recent migration that deleted some orphaned Matrix block rows in the DB, but that would only have affected the data, not the fields themselves, and wouldn’t have made any noticeable change in the Control Panel.) Someone must have gone in and deleted the field, or changed its name/field type.

If it happened recently enough, there might still be some evidence of it in your logs. We can take a look - just send in a ticket from your Dashboard and they will be included automatically.


Admin pages request a broken version of the craft.css file

The fix in this particular case was to modify and save /craft/app/resources/css/craft.css — this revs the timestamp in the query string.


I can't get the first image to show on the homepage

Just a slight syntax issue it seems.

If you want just the first image - always test if there is an image, then get it like this:

{% if entry.galleryPhotos.first()|length %}
    {% set image = entry.galleryPhotos.first() %}`

{% endif %

Or if you want to loop over a few images...note here you don't need the |length test as the for loop will not be entered if there is no image:

{% for image in entry.galleryPhotos %}


Direct access call for a twig template from a twig template gives 404

Not sure exactly what you trying to do here?  Call a Twig template from Angular?

Twig is a server side technology, Angular is getting parsed on the client side. The only way Craft is going to parse a Twig template is when it encounters a URL.

Instead of calling the Twig template directly, you call the URL, which could match a template. Inside templates, make a folder like angular-views and then inside that put a file called md-dialog.twig.  From the front end, now you can call it from Angular like http://example.com/angular-views/md-dialog (the .twig is optional).

If you're trying to use Angular inside of a Twig template, you may want to use something like {% verbatim %} and then put your JS/Angular templating between those tags to make sure Twig doesn't touch any of it.


Need difference sign up path for 2 groups

Should I write a plugin or just modify UsersService.php to split 2 directions on saveUser?

The first one.  The second one has many drawbacks:

Any changes you make in craft/app can (and probably will) get overwritten during an update.
Which means you'll have to reapply them after updating.
It's not supported.

Craft has a bunch of events that plugins can listen to and run logic when they fire without hacking core Craft files.  In your case, it sounds like onBeforeSaveUser or onSaveUser might be what you need.


Issues with returnJson not returning html?

It appears whitespace was the cause here, just running a quick whitespace filer on the return value resolved the issue:

$userHtml = craft()->logic->renderSiteMacro('_macros/elements', 'listing', $args);

$userHtml = preg_replace('~>\\s+<~m', '><', $userHtml);

$this->returnJson(array(
    'success' => true,
    'existing' => $userHtml
));


Enable client to add users to user group but not set permissions

doesn't work if the client doesn't have the "Assign user groups and permissions" checked.

That's not a limitation of the plugin, but a requirement of Craft.

  Is there a way to force every new user created in the CP by the client into a default group?

Yes, that's what the previously linked plugin will do, with the caveat that the currently logged in user has to have assignUserPermissions permissions.

The only way I can think of to do what you're trying to accomplish is build the user administration stuff for your client on the front-end of the site.  That way - though a plugin - you've got complete control over the user management business logic.


There might be other ways, but here's one possibility:
{{ craft.app.fields.getFieldByHandle('yourFieldHandle').className() }}

This will return a string of craft\fields\PlainText, craft\fields\Lightswitch etc, which you can then use in conditionals/switch statements.


Migrating Server - Craft isn't installed yet

Have you tried running ./craft setup to double check if your setup is correct?

If ./craft setup completes successfully ./craft should find the existing installation and complete any required setup.

In my experience, this is usually related to a non-default /config/db.php or problematic .env file.

Note: Always do a backup before trying anything related to setup just to be on the safe side.


Are there any tools for Craft similar to the Yii Code Generator?

There are third-party code generators, such as the Element Type Generator or the Craft Plugin Generator

You also have the migration tools that generate code. Using the querygen command you can output Records as db query commands.


Craft Locales and translatable image field

One way would be to create two Asset fields. One is the default field and one is the field which is translatable into each locale.

You could then steer the two fields via conditional logic: If no image is present in the default field, switch to the localised field.

You could add a light switch field which disables the localized field for further safety & usability.


You can use the Twig group filter.

{% set entries = allowedSearchableEntries.search(query).order('score').limit(100) %}

{% set entriesBySection = entries|group('section') %}

{% for section, entriesInSection in entriesBySection %}

{{ section }}

        {% for entry in entriesInSection %}

{{ entry.title }}

        {% endfor %}

{% endfor %}


If I had to guess, you need to add a $this->redirectToPostedUrl(); after your call to craft()->users->saveUser($user); to cause a proper redirect/page refresh after submission.

Update:

If you're doing this over AJAX, then you're going to be responsible for updating any DOM elements with their new values, or reloading/redirecting the page so they'll display.

In a non-AJAX context, a call to $this->redirectToPostedUrl(); will do the redirect for you.


How to build a great multi-lingual navigation with channels, structure, and manageable in the CP

Not sure I'm the best person to answer this having only built one Craft site but here goes.

I've created a Structure called Main Menu which has three Entry Types. (Entry types were the key for me when doing this)

A Structure allows drag and drop ordering and hierarchal navigation ordering for parent > child relationships.

Entry Link
Asset Link
External Link

Entry Link

Asset Link

External Link

Big, big (two bigs!) NavEE fan here, CraftNav has huge potential to replicate it but it's still a tad early when I tried it.

In short Entry Types were the key for me.

Note: For my own sanity at a later date it would be good to read this post on how to tell if your Structure Navigation has child elements.

Not sure if this helps but hope it does.


Plain text field - apostrophes are getting escaped

The only way I can see this happening is if the field was originally a Rich Text Field, the content was entered, then the field type was swapped to a plain text field.

If that's the case, the Rich Text Field would have encoded the entities and saved them into the database.


Width, length and dynamic pricing - Commerce

Sounds to me like this is a job for a Custom Purchasable.

Basically you write a plugin such that your created element meets the Purchasable interface, which handles it's own pricing calculations etc., and that custom purchasable becomes a sellable item through Commerce.

Documentation is here: https://craftcommerce.com/docs/purchasables

Other than that, I can't see why Commerce wouldn't work well for such a scenario as it allows for complete flexibility with front end presentation and checkout.


Smart Map doesn't currently support the ability to make an Address translatable. It's on the feature request list, and will be implemented at some point in the future.

In the meantime, you can use static translations to handle names of common cities & countries:

City: {{ entry.location.city | t }}
Country: {{ entry.location.country | t }}

* The t filter is an alias for translate.


i placed  a test file named test.json in web folder of Craft CMS and put test.json in feed URL and it doesn't work -so it is not relative to web root as default-.

but when it says absolute format i believe it is  /var/www/html/craft/web/test.json -in local ubuntu, in your case maybe {maybe top folders}/public/feeds/feed.csv- or as path alias format: @webroot/test.json which both of them works for me.

as you mentioned URL format http(s)://domain.tld/test.json or @web/test.json works too.

docs for path alias


If you enable devMode, you'll get code profiling information (execution times, memory used, stack traces, etc.) that you can use to debug templates with in your browser's console as well as in the craft/storage/runtime/logs folder.


Unable to run console commands (Craft 3, MAMP)

You might not have MAMP's PHP set as your CLI PHP. Have a look at this guide and see if it gets you further


It sounds like Sprout Commerce can handle your situation – multiple products, user-specific access, and Stripe.

At the time of this post, the product is still in private beta but if you'd like to drop us a note with more details (via the 'Request Preview' button on the site), we are happy to talk things through and see if your project would be a good fit.


Entry next sibling return a deactivated entry

The getNextSibling documentation says:

  getNextSibling() will return the next sibling whether or not it’s enabled. If you want to get the closest enabled sibling, you can do this instead:

{% set next = craft.entries.positionedAfter(entry).order('lft asc').first() %}

Similarly for getPrevSibling to get the previous enabled sibling you can do:

{% set prev = craft.entries.positionedBefore(entry).order('lft desc').first() %}


GraphQL: get prev / next entry from current entry (channel)

You should be able to use next and prev (see documentation and this issue).
query getEntryData($id: [QueryArgument]) {
  entry(id: $id) {
    id,
    slug,
    title,
    uri,
    prev(section: "blog", orderBy: "postDate desc") {
      id,
        slug,
        title,
        uri
    },
    next(section: "blog", orderBy: "postDate desc") {
      id,
        slug,
        title,
        uri
    }
  }
}


`entry` variable pre-populated on a frontend form

This example code makes use of the entry variable set by Craft to retrieve previously posted data. The variable is set if you encounter validation errors or if you want to modify upon an already saved entry (→ include the entryId in a hidden input field).

The problem is, that you already have an entry variable available to your template because every entry page comes pre-populated with one (if the URI is matched).

Easiest fix would probably be to make this single entry not match the URI set in the section's CP settings. Another idea would be to only fix that title problem and modify the example code:

{% if entry is defined %} value="{{ entry.title }}"{% endif %}

and use this instead:

{% if entry.errors is defined %} value="{{ entry.title }}"{% endif %}


Where do I add custom css for the Redactor editor in the Craft control panel?

I ended up using the Control Panel CSS plugin by Lindsey D to do this. Installed the plugin and then pointed it to an external style sheet with my redactor styles.

Here's the plugin:
https://github.com/lindseydiloreto/craft-cpcss

And in my stylesheet, the styles look like the below. These examples are for a custom item I added to the redactor formatting menu with a class pullquote__quote. The first style the menu item in the formatting dropdown menu. The second style the text in the editor.

.redactor-dropdown .redactor-formatting-p-pullquote__quote {
  font-size: 20px;
  font-weight: bold;
  color: #ffcb00;
}

.redactor-editor .pullquote__quote {
  font-size: 20px;
  font-weight: bold;
  color: #ffcb00;
}

And my redactor config file for this rich text field has this corresponding addition:

formattingAdd: [
    {
        tag: 'p',
        title: 'Big quote',
        class: 'pullquote__quote'
    }
]


Sorting entries based on an a bespoke algorithm

Looks like a solid plan to do this. And to get the entry models it the same order as you're passing the IDs to your ElementCriteriaModel there's this property: fixedOrder(true).

Other suggestions could only be to do this with plugin code, but I don't think this would speed up thing noticeably.


With update issues like this, you'll have to run composer update rather than using the CP update button. You can either SSH into your server to run composer update or update the files on your local computer and push the new files (they'll be in vendor > craftcms > redactor) to your server. Make sure you do a database backup before doing this. After doing this manual update, when you go to your Craft CP, you'll probably get a notice that Craft needs to make changes to your database, so just click ok or whatever it says.

If Composer says there's nothing to update, you'll need to edit your composer.json file. At the top of composer.json under "require" you'll see your Redactor plugin; edit the numbers to the version number you see in the Craft updates in your Control Panel, then run composer update.


How to display number of entries for a tag and not display if no entries?

Something like this should work:

{% set tags = craft.tags.limit(null).relatedTo(craft.entries.limit(null)).order('title') %}

{% for tag in tags %}
    {{ tag.title }} (craft.entries.relatedTo(tag).total())
{% endfor %}

Note that if you have a significant amount of tags, the above could be a costly affair, performance wise – consider alternative approaches.


Is it Possible to Assign Permissions Within a Content Structure

Currently there is no native way to do this, but you could:

...split the structure into multiple channels.
...write a plugin which checks: on what page a user is, and denies access if necessary
...ask P&T to add this as a feature.


Can I convert rich text field to have plain text output - with carriage returns?

Completely untested, but you should be able to do use something like the Craft-TwigPCRE plugin and some variation of this code:

{% set text = "
Some text
 tags as well as stuff like .|preg_replace('/\
/', '') %}

{% set text = text|preg_replace('/\<\/p\>/', '\\n') %}

\n is the Line Feed control character for Unix/OSX.


I finally found out craft allows multiple entry types. So a regular "structure" page can be of type "page" or, eg, of type "listpage".

I created the second entry type and gave it a field function instead of the content.

In my regular structure page, I did the following:

{# switch between content pages and list pages; if list page, display selected list #}

{% if entry.type == 'listpage' %}

{{entry.title}}

            {% switch entry.function %}
            {% case "interviews" %}
                {% include "interviews/_list.html" %}
            {% case "researchprojects" %}
                {% include "researchprojects/_list.html" %}
            {% case "seminars" %}
                {% include "seminars/_list.html" %}
            {% endswitch %}

{% else %}

{{entry.title}}

            {{entry.richtext}}

{% endif %}

Great!


DB not connecting on Namespro linux server

So if it can't connect to the database, then one of the following is not right in the config/db.php file:

server - usually it's localhost but perhaps they provide an external MySQL server?
database - the name of the database
user - the user authorized to access the database
password - the password used to connect to the database

FWIW, this type of issue (and also this lack of support) would make me want to keep the site on the Digital Ocean server, and not move it to Namespro.


Why are there now blank entry folders in my image assets folder?

I guess you or someone else made a subfolder in your upload folder. You can do this through Craft itself. This creates a folder you which might be happening in your case. Try adding a new one and see if it happens again. Go to assets and right click a folder to make a sub folder.


After some reordering of my logic and moving code to the init method of the plugins service I have been able to solve this problem with the below.

class SvgIconsService extends BaseApplicationComponent
{
    public function init()
    {
        $this->createResources(); // Method call to perform file operations

        parent::init();
    }

    private function createResources()
    {
        $folders = IOHelper::getFolderContents(craft()->config->get('iconSetsPath', 'svgicons'), false);

        if (is_array($folders)) {
            foreach ($folders as $idx => $f)
            {
                $iconSets[IOHelper::getFolderName($f) . IOHelper::getFolderName($f, false)] = IOHelper::getFolderName($f, false);

                // Create sprite sheet resources from Stylesheet
                $stylesheets = IOHelper::getFolderContents($f, false, '\-sprites.css');

                if(!empty($stylesheets)) {
                    foreach ($stylesheets as $stylesheetIdx => $stylesheet) {
                        craft()->templates->includeCss(IOHelper::getFileContents($stylesheet));
                        $this->getSpritesFromStylesheet($stylesheet);
                    }
                }

                // Create sprite sheet resources from SVG
                $svgs = IOHelper::getFolderContents($f, false, '\-sprites.svg');

                if(!empty($svgs)) {
                    foreach ($svgs as $svgIdx => $svg) {
                        $this->getSpritesFromSvg($svg);
                    }
                }
            }
        }
    }
}

I was originally calling craft()->svgIcons->createResources(); from the plugin init method.


"Updating search indexes" message in admin sidebar

Since you're on Craft 3.2+, the Update Asset Indexes Utility has been removed in favor of the craft resave console command, which will update the search indexes as a side-effect of re-saving the element and it gives you much more fine-grained control over which elements/search indexes to resave.

Will update the docs you linked to reflect that.

To debug your failed job in the queue, I'd start by searching the queue.log file in the Craft logs folder for the underlying error message.


Element Criteria Model: filtering by empty values

Okay, doesn't seem to be the most elegant but the only way I could achieve this was by carrying out the entries criteria query within my $fields loop. So, for example:

$entries = [];

foreach ($fields AS $field) {
    $criteria = craft()->elements->getCriteria(ElementType::Entry);
    $criteria->limit = NULL;
    $criteria->$field = ':notempty:';
    $tmpEntries = $criteria->find();

    $entries = array_merge($entries,$tmpEntries);
}


Save matrix block to new entry in plugin

ok just found out the answer to the second method. I was using the incorrect typeId apparently. I wasn't able to find this in any of the error logs, so this was just luck.

To make sure you get the correct typeId do so in this way:

$matrix = craft()->fields->getFieldByHandle("fieldHandle"); //look in craft_fields table
$matrixBlocks = craft()->matrix->getBlockTypesByFieldId($matrix->id);

You can iterate through $matrixBlocks and look at each blocks id but in my case I knew there was only one block so I just accessed the id like this

$typeId = $matrixBlocks[0]['id'];


Commerce - show description of discount without coupon applied to cart

I suspect there is a much better way, but I use something like this, looping over all cart adjustments, checking the type of adjustment.
We use the adjustment.sourceSnapshot for the coupon code, otherwise access the attributes on the adjustment directly, which is a Discount model.
        {% for adjustment in cart.adjustments if adjustment.type == "discount" %}
            {% set isCoupon = adjustment.sourceSnapshot.code ??? false %}
            {% if isCoupon %}
                Coupon: {{ adjustment.sourceSnapshot.code }}
            {% else %}
                {{ adjustment.name }}<br />
                {{ adjustment.description }}
            {% endif %}

         {% endfor %}

...that works.
Documentation, such as it is, is here:
https://craftcms.com/docs/commerce/3.x/adjusters.html#adjusting
And the available attributes for a discount model:
https://docs.craftcms.com/commerce/api/v3/craft-commerce-models-discount.html#app
(or src: https://github.com/craftcms/commerce/blob/master/src/models/Discount.php)
(Honestly, though, even looking at the documentation now, it's really not obvious how to come to this code....)


If you don't have tons and tons of creators, you could do that by querying creators and re-arranging the results:
{# Get all creators and eager-load the products #}
{% set creators = craft.entries()
    .section('creators')
    .with('products')
    .all()
%}

{# Declare an array to store all related product ID #}
{% set products = [] %}

{# Build an array of all product ID occurences #}
{% for item in creators %}
    {% for product in item.products %}
        {% set products = products | merge([product.id]) %}
    {% endfor %}
{% endfor %}

{# Group by product ID #}
{% set groupedProducts = products | group(v => v) %}

{# Sort by occurence count #}
{% set sortedGroupedProducts = groupedProducts | sort((a, b) => b <=> a)  %}

{# Now you can get: Product ID | Occurences #}
{% for c in sortedGroupedProducts | slice(0,10)%}
    Product ID: {{ c[0] }} | Occurences: {{ c|length }}

{% endfor %}

{# To fetch the products, extract the keys from the above and flatten to a comma seperated list of product IDs #}
{% set productIds = sortedGroupedProducts|keys|join(',') %}

{# Query #}
{% set products = craft.entries()
    .section('products')
    .id(productIds)
    .fixedOrder()
    .limit(10)
    .all() %}

{% for item in products %}
    {{ item.title }} ({{ sortedGroupedProducts[item.id] | length }})

{% endfor %}

This could probably be improved or even moved to PHP but if you have to do in Twig, it should work.


Firstly, my apologies for your issues, and its a direct result of the changes made in Craft 3.1.x. Fortunately, the Craft team has been amazingly helpful in coming up with a solution.

This issue should be fixed in Super Table 2.1.1 and Craft 3.1.2. Please update both Super Table and Craft as these changes effect both packages.


Log exception to a third party service like Sentry or Rollbar?

Update:

Went to look into this and while it's true that Craft doesn't have any explicit events around error handling, Yii already does in the form of onException and onError.

You can listen for them like so:

craft()->onException = array($this, 'myCustomExceptionMethodHandler');

and

craft()->onError = array($this, 'myCustomErrorMethodHandler');

Original answer:

Craft currently doesn't have any events around error handling, but it's probably not a bad idea to do so for situations like this.

I've added it to our list.

In the meantime, the only workaround I can think of is pretty sketchy, but a plugin could monitor the craft/storage/runtime/logs folder for [error] entries and parse the text for the information it needs.


aah

{% for category in entry.productCategory %}
    {{ category.title }} >
{% endfor %}


How to temporarily disable entries of one site version within a site group?

I finally ended up with this SQL query, which result to disable all Entries of a site version:
UPDATE `craft_elements_sites` SET `enabled` = '0' WHERE `craft_elements_sites`.`siteId` = 2;

Where 2 is the siteId. After that, don't forget to clear the templates caches.


How save data from form in headless Craft via Vue.js

You would not use the headless API to submit content in into Craft, as neither the GraphQL or Element APIs support writing.

The frontend entry form functionality is fairly well documented. You would just need your frontend to build out a post request including the correct action, CSRF token, and whatever fields are needed. The action endpoint will automatically return a JSON response if it is posted to by an AJAX request.


How do I setup my fields for a tumblr-like blog

I definitely would avoid using a Matrix field to add each of these types, as they'd all belong to a single entry, which isn't what you want to do (it’d get really unwieldy, really fast!).

What you're looking to do is use different entry types in your blog settings. Each entry type can have a different field layout, so you could then switch between each.

Here’s a blog article that covers the exact thing you’re trying to do.


Why is $DEFAULT_SITE_URL appearing in entries URL?

You probably have a misconfiguration in your environment variables - First go to the control panel and check what you have under Settings > Sites > [choose site] > Base URL. If it's set to an env variable (i.e. it begins with a dollar sign), go to wherever you store your environment variables (e.g. the .env file, or maybe server env vars if you're on the remote), and check that you have a variable there with the expected value.


Video frame for video file in a Rich Text field

If you want to upload and host the video on your site's server, then I would create a field with an Asset field type and restrict the type to Video. Without further details, it's hard to understand why you'd want to handle it within a Rich Text field.

Since you're hosting the video, you don't need an iframe. Just use the HTML5 <video> tag...

{% for video in entry.FIELDNAME %}
<video width="320" height="240" controls>
<source src="{{ video.getUrl }}" type="video/mp4">
</video>

Your servers will be handling the bandwidth for video delivery though; which is why most people post to YouTube or Vimeo and use the iframe to pass it through. To do that, you'd use the include that Brad mentioned.


Next / Prev and looping/cycling entries instead of reaching the end of the selected results

If there isn't a "next" sibling, entry.getNext() returns null – in which case you can use Twig's default filter to set an alternative value (i.e. your first entry).

Untested, but something like this should work:

{% set nextEntry = entry.getNext|craft.entries.section('mySectionHandle').first() %}


Tags are Elements and are stored in multiple places in the database, so editing the db directly may not be as easy as just finding the Tags you want and deleting them.

The tag itself is stored in multiple places including the tables:

content
elements
elements_sites
tags

You'll find the Tag Name that you recognize in the content table in the title column. However, the only way to delete the references to a given tag in all of the tables would be to delete it by it's Element ID in the elements table, which would cascade through the other tables and clean them up as well.

Quite possible to do via the db directly, but probably not advisable or convenient in many situations. Be sure to backup your database before you try, if you dare.

In the case this must be done manually, you could consider the following steps:

Export all tags from the db into a CSV file. Select all the ones you wish to delete. Use your spreadsheet to combine all the Element IDs of the tags you want to delete into a comma-delimited list. Then return to your database program and delete all the Tags by their Element IDs:

DELETE FROM elements
WHERE id IN (1, 3, 5, 7, 9);


Custom data source without options - Sprout Forms

A Custom Data Source does not require any settings. If desired, you could create a Data Source that only had a title and did whatever logic and queries that you wanted behind the scenes.

In Craft 2, getOptionsHtml returns null by default and shouldn't need to be set to anything in your Custom Data Source if that is desired:

public function getOptionsHtml()
{
    return null;
}

In Craft 3, the default is to not display any settings also:

public function getSettingsHtml()
{
    return null;
}


So it looks like you must get the correct block type in order for this to create new rows in the SuperTable.

First get the block type using the SuperTable service:

       //you'll need to reference this in your code
       use verbb\supertable\SuperTable;

       $field = Craft::$app->getFields()->getFieldByHandle('siteCustom');
       $blockType = SuperTable::$plugin->service->getBlockTypesByFieldId($field->id)[0];

Then use that same blockType id to set the type field:

       $globalSet = Craft::$app->globals->getSetByHandle("myGlobals");

       $globalSet->setFieldValues([
              'siteName' => "The Website",
              'siteCustom' => [
                   'new1' => [
                          'type' => $blockType->id,
                          'fields' => [
                              'firstField' => "some value",
                              'secondField' => "some other value"
                           ]
                   ]
               ]
       ]);

       Craft::$app->globals->saveSet($globalSet);

If you need to add more than one value to siteCustom you can do so with the same syntax, just make sure you increment the number after new each time (so new2, new3, and so on).


Author saved as NULL when updating entries from a plugin

Josh Angell's suggestion did work, I was just testing it on an entry that already had been updated with a NULL author. (Thanks Josh!)

For the record, I used $currentAuthor = $currentKit->authorId; to get my previous author, and then set the author with $kit->authorId = $currentAuthor. This does seem to maintain the author entirely.


Display X number of characters from an entry

You can use the Twig slice filter do do this, e.g.: entry.text |slice(0, 100)

If you want something that looks a little nicer, and you're using the SEOmatic plugin, you can use the truncateStringOnWord filter, which will truncate to the number of characters you want, but only on word breaks (and it'll add an …).


You can configure the Redis cache driver to use an external host, see the config page for the documentation and here for details on copying the default Redis config file and configuring it.

Long story short... Copy craft/app/etc/config/defaults/rediscache.php to your craft/config/ folder and configure the settings as you wish.


The error tells you that faqs is null. As you're using the first() function to execute your element query, this means that your query has no matches.

Are you sure that the section handle (FAQ) is in uppercase?
The correct way to create an entry query in Craft 3 is craft.entries(). Although it may work without the parenthesis, it can't hurt to add them.
You can replace .search('slug::' ~ entry.slug)  with .slug(entry.slug). It's easier to understand and should have the same effect.
Are you sure that the query always returned something in Craft 2? It may be worth adding a null check to avoid the error: {% if faqs and faqs.questionsanswers and faqs.questionsanswers|length > 0 %}


"An unknown error occurred" in assets screen

I got an emailed response from Andris from P&T:

  That indicates that at some point Craft was unable to index a file,
  leaving some corrupt data. If you look at craft_assetfiles table,
  you'll notice that at least one entry has the dateModified column set
  to null. Removing those should fix the issue for you. Probably the
  best way to remove them would be to actually delete the records from
  the craft_elements table, that have the matching IDs. The cascading
  delete should remove all related records.

  Please do make backups before tampering with the database, though!

Deleting the records fixed the issues.


Applying the activation link to linked text in the notification email

Probably this has been fixed since this old question, but just wrapping {{link}} variable in <a> tag lets me send custom HTML notifications with working clickable text links.

Screenshot of messages settings:

Screenshot of custom HTML email received:

Perhaps this won't work for the text version of the email, but if needed I suggest you to use this excellent plugin which let you send custom notifications in both HTML and text versions: Sprout Emails.


Is it possible to order related entries by relevance of tags?

I've made a plugin called Similar that does exactly this. Give it a go.


You can do this simply by setting your field type’s defineContentAttribute() method to return AttributeType::Mixed, which will tell Craft to JSON-encode its value before storing it in the database.

public function defineContentAttribute()
{
    return AttributeType::Mixed;
}

Then, whatever you submit in the field’s post data will be saved as-is.

For example, if your getInputHtml() method had this:

public function getInputHtml($name, $value)
{
    $lat = (isset($value['lat']) ? $value['lat'] : '');
    $lng = (isset($value['lng']) ? $value['lng'] : '');

    return '<input type="text" name="'.$name.'[lat]" value="'.$lat.'">' .
           '<input type="text" name="'.$name.'[lng]" value="'.$lng.'">';
}

Then it would be expected that the resulting post data for your field would look something like:

array(
    'lat' => '12345',
    'lng' => '67890'
)

And with AttributeType::Mixed, that’s exactly how it would get stored. Behind the scenes it will get JSON-encoded when getting saved to the DB, and JSON-decoded when getting fetched from the DB, but your field type will never need to know about that.


Add a public getSettingsUrl() function to your main plugin file that returns a URL string.

A full URL is not required -- you can simply return "pluginname/settings".
If this is left blank, a simple settings page will be provided, filled with whatever getSettingsHtml() returns.

You can then get the URL from elsewhere in Craft using the PluginsService.
craft()->plugins->getPlugin('pluginname')->getSettingsUrl();

or PluginsVariable:
{{ craft.plugins.getPlugin('pluginname').getSettingsUrl }}


This is a tricky topic for a simple answer. Off the top of my head, there are two general approaches you may fall in for this. I'll keep my answer fairly broad:

URL-Enabled Elements

You can create an Element Type and implement the method routeRequestForMatchedElement. This approach would require you to have a Custom Element, and have a need for that Element to be URL-enabled like Entries or Categories or Products.

For this approach you would not need to setup registerSiteRoutes .The Element API would handle the front-end request in the same way other URL-enabled Element requests are handled.

Your Plugin has a template in the plugins template folder that you want to render on the front-end of the website

The main concept to understand here is that Craft has two Template Modes: Site and CP. Depending on which template mode is active, Craft will look in different places for the template to load.

To set the template mode in your code, you can use the following:

// Tell craft to look in the front end craft/templates folder for a template
craft()->templates->setTemplateMode(TemplateMode::Site);

// Tell craft to look in the back end craft/app/templates folder for a template (where you can later update the path to target your plugin template folder)
craft()->templates->setTemplateMode(TemplateMode::CP);

Once you are on the right side of the fence, you can then render the template you want and return it to the page. You would do this in one of two places:

Controllers If your logic is taking place in a controller you will need to render the template and return the rendered template to the page as a variable. Two scenarios in controllers where this may occur:

Responding to a page with errors:

$output = craft()->curiousService->getTemplate()

craft()->urlManager->setRouteVariables(array(
  'stuff' => $output
));

Rendering a template as the final step in the controller action (this may apply to CP scenarios more than front-end scenarios).

$this->renderTemplate('curious/example', array(
    'stuff' => $stuff,
));

Variables If your logic is taking place in the middle of the page, you may need to create a custom variable that renders your template and outputs it when the variable is called:

{{ craft.myCuriousPlugin.getMyTemplate() }}

Be sure to Flip/Flop

In either case, since you are flip/flopping on which part of the site is rendering your templates, you'll want to be sure to set your Template Mode back to the Site side of things once you are done:

// Front end page calls your plugin

// Switch things to look for templates on the back end
craft()->templates->setTemplateMode(TemplateMode::CP);

// Do your thing
//
// Note the template path is just the name of the plugin
// and the folder in the plugins template folder that you
// want to access, and that we are omitting the word 'templates'
$html = craft()->templates->render('curious/example', array(
  'someVariable'      => $yourResults,
  'someOtherVariable' => $someOtherStuff
));

// Switch things back to look for templates on the front-end
// so that any template-related things that after you behave
// as normal
craft()->templates->setTemplateMode(TemplateMode::Site);


How to search for content in a specific Matrix field?

What I'm not clear of is if you are asking if you can query for entries that have a matrix field that contains x, or if you just asking if you can search within a matrix field of an entry that has already been returned by a query.

If it is the later, the following solution would work. This isn't a feature of Craft, but a feature of Twig. Thus, implementing it won't save on queries or anything, but it will help you filter the results returned by Craft.

Twig has a feature that allows you to apply a condition in addition to the for loop. It is documented here.

{% for cta in entry.homeCtas if cta.ctaTitle == "Lorem Ipsum" %}
    <h1>{{ cta.ctaTitle }}</h1>
{% endfor %}


Allowing a new locale to fallback on content from a default locale?

One solution (without needing to create a custom plugin) would be to add a lightswitch or checkbox field called useDefaultLocale, and add it to the field layout of any sections that you want to default to english. In your template you can test for the value of this field and display the default locale version of the content. You would of course need to target 'fr' locales for any sections that included this functionality.

{% if not craft.locale == 'en' and entry.useDefaultLocale %}
    {% set entry = craft.entries.section(entry.section).locale('en') %}
{% endif %}

Any content that is defined directly in the template using the translate filter (i.e. {{ 'Date'|t }} ) would still get translated of course, but maybe that's a good thing. There also may be a way to manually set the locale so as not to translate these as well, that I don't know about. If anyone knows, please leave a comment, and I'll add it to the answer.

Update: carlcs brings up a good point regarding SEO and duplicate content. To solve this you could define a canonical link using: (placed in the if clause above)

{% set canonical %}
    <link rel="canonical" href="{{ entry.url }} />
{% endset %}`

and then in the _layout template head:

{% if canonical is defined %}{{ canonical }}{% endif %}

The side effect is that some French users might get directed to the english url from search engines. Pick your poison I guess.


RelatedTo relation - checking matrix block status is enabled

I faced the same problem in Craft v3.4.10 and have been informed that this is a bug, which has now been fixed and will be shipped in v3.4.12.


Display rich text redactor menubar with superscript/subscript buttons

The definitive and most simple answer for all Redactor Inline Styles requests is this great plugin by carlcs:
https://github.com/carlcs/craft-redactorinlinestyles

Just perfect!

(found it thanks to this post How to add a non-breaking space to a rich text field?)


How can I disable sessions for most of my Craft site?

I'm not sure there is going to be an easy way to do this in Craft 2, unfortunately.

In the upcoming Craft 3, we refactored the session logic so that a session will only get started on requests that actually need session, which is basically what you're looking for.


How can I get cookies that were set in javascript from a twig template? [NEW]

Assuming this is for Craft 3, you can do something like this from a template to loop through all available cookies for a site:

{% set cookies = craft.app.request.getCookies() %}

{% for cookie in cookies %}
    {{ cookie.name }}
{% endfor %}


multi-domain setup: template entry.url includes index.php

OMG I'm so angry at myself!

Not 'omitScriptNameInUrls' => 'true',

but 'omitScriptNameInUrls' => true,


Outputting siteUrl consumes next closing tag

Try to set the siteUrl in config/general.php like so.

return array(
    '*' => array(
    ),
    'localhost' => array(
        'siteUrl' => 'http://localhost:3001/',
    ),
);

And then apply your replace filter.

<span>{{ siteUrl|replace({'localhost:3001': 'mysite.com'}) }}</span>


Craft Commerce has a COD method called the 'manual' gateway. Make sure you set it to authorize only and it will allow a customer to check out without submitting payment. When cash or cheque is presented you can 'capture' the manual transaction payment on the order edit screen.


Is it possible to totally reskin the admin panel with a new template?

You can certainly override the admin css by using https://github.com/lindseydiloreto/craft-cpcss from Double Secret Agency. It's rather nice.

Lindsey also has a Admin JS plugin too: https://github.com/lindseydiloreto/craft-cpjs

Regarding actual admin template changes and their ability to survive an update, I'll have to defer that to somebody who know's more about it than myself.


Kind of, but probably not what you're looking for.

Your plugin can certainly do a MyAssetFileModel extends AssetFileModel and (in the scope of your plugin) take advantage of existing AssetFileModel methods and properties and override them as needed.  But that's the catch... it will only be within the executing scope of your plugin.

There's no native way (without hacking core Craft files) to tell Craft "use MyAssetFileModel wherever you would normally use AssetFileModel".

However, this is certainly much more doable in the upcoming Craft 3 release since Yii 2 has native support for things like service locators and dependency injection.


The events plugin by Pixel & Tonic is an example of how to use custom Elements if you're building your own plugin. I don't think it should be used in a production environment (but please correct me if I'm wrong).

If you want to use it, you should take a look at the only variable for this plugin.
This variable gives you the ability to get all events, filtered by your criteria. There's no way to get all calendars, only events:

{% for event in craft.events.events %}

{% endfor %}

One other plugin you could have a look at, is this one, still in private beta.


did you copy the license.key from your Mac environment to the Windows/Vagrant environment? Maybe deleting the license.key would help in this case.


How do you clear the templatecachequeries table?

You can clear the cache from within the settings section of the control panel. It's possible to select which specific caches to clear if necessary.

You can try manually clearing the cache tables. Test it on a backup first but I have done this in the past with no ill effects.

It sounds like you need to be adding the "globally" keyword to your cache tags. This will drastically reduce the number of rows in the cache table and most likely speed things up too.


Just use a variable that has the same keys as the entry model will have.

{% set entries = [{title: 'hello', ...}, {title: 'hello2', ...}] %}

{% for entry in entries %}
    {# stuff #}
{% endfor %}

Then, when you want to move to using the database, just switch what  entries is set to:

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

That way the template will still look exactly the same.


Is there a way I can programmatically download the latest version of Craft?

In Craft 3:

You can download the latest Craft 3 release in zip or .tar.gz format by going to:

https://craftcms.com/latest.zip
https://craftcms.com/latest.tar.gz

Or since Craft 3 is Composer based, you can modify your composer.json's craftcms/cms line to install the specific version you're looking for.

In Craft 2:

You can get the latest Craft 2 version in either zip or tar.gz format by going to:

https://craftcms.com/latest-v2.zip
https://craftcms.com/latest-v2.tar.gz


User restricted access to content via a common template

I assume you have basic knowledge in creating plugins, if not I suggest visiting the docs.

It's actually pretty easy to achieve your goal.

Create a Plugin and store an array of permission's in it's settings

<!-- first permission -->
<input class="text" type="text" name="permissions[]" value="" autofocus="" autocomplete="off">

<!-- 2nd permission -->
<input class="text" type="text" name="permissions[]" value="" autofocus="" autocomplete="off">

<!-- 3rd permission -->
<input class="text" type="text" name="permissions[]" value="" autofocus="" autocomplete="off">

<!-- 4th permission -->
<input class="text" type="text" name="permissions[]" value="" autofocus="" autocomplete="off">

<!-- just include some javascript logic to add fields if needed to create them dynamically -->

Register those permission from your plugin

public function registerUserPermissions()
{
    $permissions = array();
    foreach($this->getSettings()['permissions'] as $rule){
        $permissions[$rule] = array('label' => $rule);
    }

    return $permissions;
}

Create a custom fieldType that displays all usergroups dynamically or (for testing) create a simple dropdown field that stores user groups

Add this field to a matrix element -> you can store a required group for each element
Go to your usergroups and add the permissions to those groups then you can check if the currentuser is in the group you selected in your dropdown
After you understood the process you can create a custom field type to store/link usergroups (so you can store multiple and select them based on all existing usergroups dynamically)
Make your plugin settings more complex.. in my example you can only store the handle not the label of your permission so if you type "Permission to do that" instead of "permissionToDoSomething" it will break


How to search for Entries that have a particular Category set within a Matrix field in the Control Panel?

Very simple answer: you just type the category name (no matter whether it's being set within a Matrix field).
The reason this didn't work in the first place was that my search index hadn't been updated properly by the auto-running task that triggered after an XML import I did with the Feed Me plugin.
I simply had to rebuild the search indexes manually to fix the issue.


It sounds like you're wanting to move templates around like this:

articles/index.html
articles/_entry.html

To this:

_layouts/articles/index.html
_layouts/articles/entry.html

There are three basic ways Craft figures out what template to use based on the URL:

Element routing like articles/_entry.html (matches a URI in an element's settings, e.g. section or category)
dynamic routes and URL Rules
Template path routing like articles/index.html

(Craft 3 docs on routing)

To get a URL like http//example.com/articles to use the template _layouts/articles/index.html, you have two options:

Set up a dynamic route or URL rule.
Create a Single with the URI set to articles.

Personally, I often create a Single for this like a Blog index page. Then it's easy to control parts of the index page like a header image or custom SEO tags.

A dynamic route would look like this:

A URL rules would work something like this in config/routes.php:

'articles' => ['template' => '_layouts/articles/index'],

A third option that I don't recommend is if you have a structured section called something like "Pages" (or Static Pages or Landing Pages), you could create different Entry Types called "Page" and "Articles Index" just for this.

├── About Us (Page)
│   └── Our Team (Page)
├── Articles (Articles Index)
├── Services (Page)
└── Contact (Page)

I'm not a fan of this for a few reasons, but the main one is that you can't point entry types to different templates in Craft so you'll probably have to use Twig includes to create a "routing template" that points the Article Index entry type to a different template. Also,  chances are you will never need more than one Articles index page, and you won't want to drag and drop it's location around the structure because the URLs will become out of sync with the child Article entries.


I am not sure if i get what you mean, do you want to have the categories as content blocks, which show the entries ordered by last updated, but the category blocks should be ordered as well e.g. if entry x in categort y is the newest the category block y should be on top of the list?

Otherwise that should work, displaying the latest 10 updated entries on top for 8 categories all in descending order relative the the update date

   {% set categories = craft.categories({
         level: 1,
         limit: 8,
         orderBy: 'dateUpdated desc',
     })
  %}

  {% set offers = craft.entries({
     relatedTo: categories,
     with: ['offerLogo'],
     limit: 10,
     orderBy: 'dateUpdated desc',
     })
   %}

   {% for offer in offers %}
      {% include '_card' %}
   {% endfor %}


How to parse environment variables and globals from a field

You could enable your client to use Reference Tags by adding the parseRefs filter.

{% set str = '
Since {globalset:42:yearEstablished}
' %}
{{ str|parseRefs|raw }}

But this would enable them to access field values of (almost) any element (entries, assets, tags, ..), not just from global sets.
And they would also have to remember the global set's ID.

So your current replace filter solution is a good approach in my opinion. You can pass multiple replacements pairs like so
(and no, you won't notice if there's 1 or 100 of them):

{% set str = '
Since {yearEstablished}
' %}
{% set replacements = {
    '{yearEstablished}': companyInfo.yearEstablished,
    '{siteName}': siteName,
} %}
{{ str|replace(replacements)|raw }}

You could also consider building that replacements array programatically.


Plugin Multi-Environment config not working

The issue is that you're putting the multi-environment config code in your plugins/pluginHandle/config.php file, which is just meant to supply default plugin config values.

Users can set custom values in craft/config/pluginHandle.php which is where the multi-environment logic would also go.


Saving remote image to assets field in entry

Your best bet to get the image in as an Asset in one go would be to use

$response = craft()->assets->insertFileByLocalPath($fileLocation, $fileName, $targetFolderId, AssetConflictResolution::KeepBoth);

$fileLocation would be the file's location on the disk
$fileName is the desired file name
$targetFolderId is the Assets folder, obviously. Look it up in craft_assetfolders table
The last argument is how to resolve any naming conflicts.

This will return an AssetOperationResponseModel object.

$fileId = $response->getDataItem('fileId');

This will get you the file Id. For an in-action example, see AssetsController::actionExpressUpload()

Note: This will copy the file to the location. This method is intended for importing a file into an Assets source from a different location, say, a temporary folder. It will probably work alright if the file is already in it's intended place, but I still feel like I need to warn you about this

You can also use this to import images to external sources, by the way.