Conditional logic to add class for specific section entries

There are many possibilities for this.

One of them is to listen to the section handle if you want it to be triggered only on the blog template:

{% if entry.section.handle == 'blog' %}your-class{% endif %}


Is a lot of potential reasons for what issue may be. Is Craft handling the 404 error? If not, it could be your server is not pointing to the web/index.php properly.

Can check that just putting a die('hello world'); at the top of your index file at least.


Exclude "featured" entries from a "recent" entries {% for %} loop

What you could do is get the ids of the featured element, and exclude those from the second craft.entries call. Something like this:

{# Get the ids of the featured items you got above #}
{% set featuredIds = featured.ids() %}

{# Get entries in section 'blog' which don't have an id in featuredIds #}
{% set allEntries = craft.entries.section('blog').id('and, not ' ~ featuredIds | join(', not ')) %}

{# Loop and output #}
{% for entry in allEntries.limit(5) %}
  {{ entry.title }}
{% endfor %}

The use of the join filter may seem a bit cryptic. But, when excluding one id from a list of entries, you'd do .id('not 3'). When excluding more than one, you need to specify the conditional first (the and part) and then a comma separated list of not (id). So the join basically creates a string like .id('and, not 3, not 4, not 5'), if the ids of the featured articles where 3, 4 and 5.

Edit: added necessary space to join(', not ')


Trouble Installing Craft 2.5 on Windows 10 Using Wamp 2.5

Alec Ritson's comment solved the problem.  His advice was to try

localhost/sitename/public/index.php/admin

In other words, I had to add index.php to the URL (after public but before admin) and then everything worked fine.


RelatedTo Query Using Both "and" and "or"

Crisis averted, thanks largely in part to the versitile nature of the relatedTo targetElement processing. The relevation came that I could feed an array of category ids (inclusive) into that element, and use a single relatedTo "and" parameter overall to get my intended filtering:

{% set params = {
    section: 'technologies',
    limit: null
} %}

{% set paramRelation = ['and'] %}
{% if technologyIds|length %}
    {% set paramRelation = paramRelation|merge([{ targetElement:technologyIds }]) %}
{% endif %}
{% if institutionId != "" %}
    {% set paramRelation = paramRelation|merge([{ targetElement:institutionId }]) %}
{% endif %}
{% if paramRelation|length > 1 %}
    {% set params = params|merge({relatedTo: paramRelation}) %}
{% endif %}

{% set technologyResults = craft.entries(params) %}

{% paginate technologyResults.limit(10) as technologies %}
    ...
{% endpaginate %}

It's actually more simple this way as well, but I had initially underestimated how much heavy lifting the targetElement piece could do. Once again, Craft exceeds expectations. Thanks!


Is there a "sticky post" function built into Craft?

You could add a custom lightswitch field or similar and order your entries by that field.

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

If you need additional sort options, @Brad just shared how to do that with SQL in the order() parameter.


Based on the code you posted on pastebin, it seems like the problem is that you have your pagination outside of the cache tags (assuming this was the case when you had caching implemented). And, I'm assuming that inside your {% include "_includes/pagination" %} you're trying to access pageInfo, which is created by the pagination tag.

To make this work, and be able to implement efficient caching, you need to include your pagination inside your cache tags. In fact, I would also include the logic that creates the topicEntries element criteria above where you have the pagination tag today, inside the cache tag, as it creates DB queries and is directly related to the content you want to cache.

The overall structure of your code should then be:

{% cache globally using key craft.request.path ~ '/p' ~ craft.request.getPageNum for 2 hours %}
    <ul class="feat-box-container">
        {#  lots of code to get topicEntries #}

        {% paginate topicEntries.limit(10) as pageInfo, topicEntries %}

        {% for topic in topicEntries %}
            {# code that outputs list items #}
        {% endfor %}
    </ul>

    {% include "_includes/pagination" %}
{% endcache %}


Why would I choose Channels as opposed to Structures

From the official docs:

Channels are used for streams of similar content
Structures are good for times when you need to store multiple similar entries, and they need to be sorted into a specific order. They can also be hierarchical.

As per your question there's no performance overhead involved, but as a general rule it's usually a good idea to keep things as simple as possible.
Channels are bit simpler than Structures and if the content is neither hierarchical nor multi-level, there's no reason to use the latter. A blog is a good example of an appropriate use case for a Channel.


Select Related Entries from a specific category in CP

There is no native functionality for this at the current time.

You could write a plugin to extend the Products field-type (which itself extends the base entries field-type) - to provide this filter functionality.  That is you'd add a categories chooser to the field type and then filter the available products using that category in your plugin.

https://pluginfactory.io would get you started on the plugin scaffolding, and I'd look at /craft/plugins/commerce/fieldtypes/Commerce_ProductsFieldType.php and the native Craft categories field type to get started.


How can I select users that are not members of any user groups?

You could get the IDs of all users belonging to a group, and use these IDs prefixed with not as the id parameter in a second craft.users ElementCriteriaModel:

{% set userIds = craft.users.group('group1, group2, group3').ids() %}
{% set users = craft.users.id('and, not ' ~ userIds|join(', not ')) %}


Is this what you're after?

{% for row in block.tableHandle %}

    {% for columnHandle, columnValue in row %}
        {# If not col1 #}
        {% if loop.index != 1 %}

Do whatever you want with: {{ columnValue }}

        {% endif %}
    {% endfor %}

{% endfor %}


HappyLager Demo Site Forcing 'https://' on XAMPP

The issue here is actually the use of the TLD .dev. Google now owns that extension and in Chrome (which later, other browsers including Safari and Firefox enforced) it now forces the URL to go over SSL. If you don’t want to deal with all that self-signed certificate stuff to get SSL working locally, your best bet is to just switch the extension to something like .test and it should work just fine.


You can use Twig's date filter:

{{ "now"|date('Y') }} Sitename. All rights reserved.

More info in the Twig docs


Moving from staging (MAMP) to live production server

Everything looks good to go more or less, but #4 can be improved upon by creating a multi-environment config file.  This way, instead of having to change your site urls and base path (for assets) in the event you want to overwrite your local db with your live site db to sync it up, you just use a variable in the CMS like {siteUrl} or {basePath} that's set in your config file.

nystudio107 has a great article walking you through setting up a great multi-environment.

If you're feeling even more adventurous, I also highly suggest his Database & Asset Syncing article that allows you to run a command from your terminal to instantly pull down and import a copy of your database/assets from any environment you want into your local.


The Categories Settings let you set up Category Groups, define some behaviors for your Category Groups (for example, if you want them to have URLs and the pattern of those URLs), and assign Custom Fields to those Category Groups (which would allow all categories in that group to have custom fields just like all Entries have the same custom fields in a section).


To fetch the logo:

{{ craft.rebrand.logo.url }}

To check if a logo is uploaded:

{% if craft.rebrand.isLogoUploaded %}


Others have said what the problem is, but in the interest of clarity for future readers...

Cause: The database is expecting a newer version of Craft's filesystem than you have.

Solution: Replace the /app folder with one from a fresh Craft download and visit your admin trigger URL


Jon's answer is excellent, but if you want to keep the same month and year URL query params, I offer this.

The problem is that firstDayOfMonth and lastDayOfMonth are PHP class objects and can't be inlined as text. They need to be formatted as text with a date() or atom filter.

Here's your code with the filters added:

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

{% set firstDayOfMonth = now | date_modify('first day of ' ~ month ~ ' ' ~ year ~ ' 00:00:00') %}
{% set lastDayOfMonth = now | date_modify('last day of ' ~ month ~ ' ' ~ year ~ ' 23:59:59') %}

{% set entries = craft.entries.section('yourSection').postDate('and', '>= ' ~ (firstDayOfMonth|atom), '<= ' ~ (lastDayOfMonth|atom)) %}

You can make it extra readable by using the after and before methods since your query is based on Craft's postDate parameter.

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

{% set firstDayOfMonth = now | date_modify('first day of ' ~ month ~ ' ' ~ year ~ ' 00:00:00') %}
{% set firstDayOfNextMonth = firstDayOfMonth | date_modify('+1 month') %}

{% set entries = craft.entries
    .section('yourSection')
    .after(firstDayOfMonth|atom)
    .before(firstDayOfNextMonth|atom)
    .all()
%}

I'm sure you're aware, but it's worth noting for anyone finding this answer later: This is a bit fragile. If the URL query string does not have a valid month name and four-digit year number, it'll chuck errors.


Catch file-size errors in Guest Entries Form

What's probably happening on both of your cases is a PHP fatal error, which are notoriously difficult to recover from.

The upcoming Craft 3 (thanks to some clever tricks in Yii 2), however does handle fatal PHP error much better and in situations like yours, you would be receiving the actually underlying fatal error message.


Can image transforms decrease performance?

Nope. Once a transform has been generated once, Craft remembers that, and saves it right in your asset source. Future page loads will get a direct URL to that generated image, so it gets loaded via your webserver (or S3, etc.) directly. No PHP involved.


SOLVED: Best way to deploy Craft 3 to webserver?

At the risk of "link" answers, we talk about different deployment strategies here:

Website Deployment without Tears

...and there's a writeup of deploying Craft CMS here:

Setting up a New Craft CMS 3 Project

It's hard to do a TL;DR on this, because it's fairly involved, but essentially ignore your vendor/ directory, and do a composer install on your production/staging server to install the vendor/ directory there, synced up with your composer.lock

Using some kind of deployment tool like Forge or Buddy.works will also make your life easier.


Assuming you've already got the product (which is a ProductModel) in Twig, it's a simple as:

This product is available in {{ product.variants|length }} colors.


Craft 3 cannot find mysqldump command, console works

After a lot of digging I found an SO post which recommended updating the environment variable via PHP:

putenv("PATH={$_SERVER["PATH"]}:/usr/local/mysql/bin");

Adding that line into craft/config/general.php before the return statement did the trick for me. Craft does back up and Feed Me runs the feed successfully.

BUT: Is that a good solution?


Possible to speed up infinite scrolling?

You could open up the console and paste this then scroll to the bottom once.

After that, this will keep scrolling to the #footer every time a response from the getMoreElements request comes in.

$(document).ajaxComplete(function (event, xhr, options) {
  if (options.url.slice(-15) === "getMoreElements") {
    setTimeout(function () {
      $('#footer')[0].scrollIntoView(true)
    }, 10)
  }
})


How do I access a custom Asset field within an Assets field?

You’re close. When you do this:

{% for image in entry.logos %}
    ...
{% endfor %}

The code within the for-loop will be repeated for each asset that was assigned to your entry.logos field. Each time, the image variable will be assigned the current asset.

So, if you want to access a field that is on the asset (e.g. your logoUrl field), you would access that via image.logoUrl rather than logos.logoUrl. (You don’t actually have a variable named logos, so if you have Dev Mode enabled, that template would be giving you an error about that.)

{% set logo = { width: 175, height: 120, mode: 'fit' } %}

{% for image in entry.logos %}

{% endfor %}


Upgraded to PHP 7.1 - GD or ImageMagick is required

You'll need to contact your hosting provider. There are any number of ways that this "PHP switching" can be implemented, but typically each major PHP version has its own separate modules/config files that tell it which modules to use.

So the fact that ImageMagick is installed on the server doesn't mean that it's globally available to every PHP version that's running. So, contact your hosting provider.

Also, I feel obligated to mention that boutique hosting environments can be a source of issues like this, so I try to avoid them, as per: How Agencies & Freelancers Should Do Web Hosting


Is there a way to output more Matrix fields than one?

Not sure if this solves your problem, but you could try this:

{% set allMatrixBlocks = entry.matrixFieldhandle1.find | merge(entry.matrixFieldhandle2.find) %}

{% for block in allMatrixBlocks %} My stuff {% endfor %}


Craft 3 doesn't translate static strings

I'm simply trying to follow the docs as good as possible.

Try the following:

Example String we'll be using: "cheese" | "fromage"

in your config/general.php make sure you have your siteUrl set as an array with at least two entries, example:'siteUrl' => ['my_site_en' => 'http://localhost:1234, 'my_site_fr => 'http://localhost:1234/fr/'];
in your translations/fr/site.php make sure it only contains the following

<?php

return [
  'cheese' => 'fromage',
];

in your twig file add the following <h1>{{ "cheese"|t }}</h1>

4. important: Access your Control Panel (cpTrigger in config/general.php for the first part of the URL), => http://localhost:1234/%CP_TRIGGER%/settings/sites and make sure you have 2 sites, both in the same group, one in en, one in fr & their URLs must also be set!   It should look similar to this

As long as all 4 steps are followed, it should work.

Hope this helps!


for loop: get the title of the first element of an entries field

I could be not following correctly, so I apologize if I'm way off here.

If you want to grab all entries that are selected in your block field, but only want to single out the first one, you could do something like this:

Program Points

{% for entry in craft.entries.section('program_point') %}
    {% if loop.first %}

{{ entry.title }}

    {% else %}

{{ entry.title }}

    {% endif %}
{% endfor %}

The twig for loop has some pretty cool stuff built in that you could leverage to check for the first entry.

Hope this helps!


You can create a plugin that adds custom user permissions via the registerUserPermissions hook.


The answer on the previous question is a little bit off - you do not want to use json_encode to save the field. Just use the actual array:

$tableValue = [
  [
    "col1": "Product #1",
    "col2": "5",
    "col3": "10",
    "col4": "15"
  ],
  [
    "col1": "Product #2",
    "col2": "7",
    "col3": "14",
    "col4": "21"
  ],
  [
    "col1": "Product #3",
    "col2": "7",
    "col3": "14",
    "col4": "21"
  ]
];

$entry->setContentFromPost(array(
  'tableField'=> $tableValue,
));

Note that 'col1', 'col2', etc, refer to locations in the table. The handle of the table column is not used.


Can I extend entries listing views (currently or in the future)?

The current answer to this is no, not out of the box.

The unofficial answer to this is, it has been discussed several times out there in the forums and there are some good arguments to make that this is a core part of 'content management'.

The developer-friendly answer to this is yes, you can control those columns if you create a plugin with a new Element Type.  Your Element can extend the default Entries Element Type and customize the columns in the listing views.

Within your Element Type:

defineTableAttributes() - Returns the attributes that can be shown/sorted by in table views.

modifyElementsQuery() - Modifies an element query targeting elements of this type.

getSources() - Returns the element type's sources and can be used to trigger filters on the table view.

You can create a new listing template with these three lines of code:

{% extends "_layouts/elementindex" %}
{% set title = "Page Title"|t %}
{% set elementType = 'PluginName_Element' %}

Is this a smart thing to do?  It probably depends on your use case.  Elements are powerful, but they also take time to develop and maintain.  While you can easily extend a class, several parts of the Control Panel UI are not as easy to extend if you start adding variations on the intended use cases. Make your case to P&T about this feature being a core part of content management and if enough others do the same, you may save yourself a lot of custom development.  I think there is a strong case that this type of feature can only be done well in the core.


Problem updating to latest version of Sprout SEO

We were able to recreate your issue. The error caused by an older version of Twig.

The error should be fixed by upgrading to Craft 2.6.2771


I believe the only way to do this at present is to select the Include in Price option on the Tax Rate in Commerce settings.


The client must have added a new rule which was causing the problem.

changed from

RewriteRule (.+) index.php?p=$1 [L]

to

RewriteRule (.+) index.php [L]

Not exactly sure why they added that but...


What's the best way to skip CSRF for plugin controllers?

In Craft 3 this is a cinch:

class PluginController extends Controller
{
    // Disable CSRF validation for the entire controller
    public $enableCsrfValidation = false;

    ...

See the Yii2 docs for more control over inividual actions:
https://github.com/yiisoft/yii2/blob/master/docs/guide/security-best-practices.md#avoiding-csrf


How can I test if a request returns a 404?

That solution is viable. You can just test to see if the entry or the template matches your 404 template/entry. If you routed everything correctly to display a 404 in case of error, you should be fine.


Is there a way to hide Matrix blocks based on the Selected Entry Type?

No. Matrix blocks do not work in that manner. However you define it in the field is how it'll show when you edit it. If it's really important not to show that block type you can write a plugin that checks for an entry type, and hide certain block types based on that result. Granted that's a lot of work for very little gain. You would be better off ignoring the unwanted block types or building a new matrix field.


I would try and put the port in your siteUrl config param:

'siteUrl' => 'http://localhost:8888',

Alternatively you might be able to use this though haven't tested it (I believe the php server variable uses the server name & port number):

'localhost' => array(
    'siteUrl' => 'http://'.$_SERVER['HTTP_HOST'],
    'devMode' => true,
    'cacheMethod' => 'file'
)


Can the Entry URL Format of a Channel intersect with the Entry URL Format of a Structure?

Where the review list page is in the structure? Yes. This works just the way you would expect. Set the review channel url to products/shirts/reviews/{slug} and it will do just that.


MySQL exports only include the tables, not the database settings. You need to create a database first, open it and then import the tables.


Craft CMS Structure: How can I display parent and child items on an active parent page?

I hope I have understand your problem..

Let's look at your code:

One sidenote: It might be good to limit your pages-selection only to active pages:

{% set pages = craft.entries.section('about').level(1).status('live') %}

First of all, store the elements of the slug in an array:

{% set slugs = craft.request.segments %}

Here is the first for-loop for the first-level elements:

{% for page in pages %}
    {% set activePage = (page.slug in slugs) %}

        {{ page.title }}&nbsp;

{% endfor %}

The important part here is to check whether the slug of the page in the for-loop is active. In your code, you checked the slug of the entry (of the currently active page, not the page in the loop) with the slug of the request. This will always yield a true result, which is what you experienced.

Using the code above you will by now receive a list of all first-level pages, the active one with labelled with class="active".

Now let's look into the second loop for the subpages.

{% set activeSubPage = (entry.level == 2 and entry.getParent().slug == page.slug) %}
{% if activePage or activeSubPage %}
    {% set subPage = craft.entries.descendantOf(page) %}

        {% for child in subPage %}

{{child.title}}

        {% endfor %}

{% endif %}

This time it is not enough to check whether the slug of the active page in the loop matches the slug of the actual page (this will show children only if the parent page is selected), we also need to check whether the parent's slug matches the active page (to show children even if the active page is one of the children itself and not the parent).

With activeSubPage we check at first, whether the page is level 2 (therefore it has a parent and we won't run into an error for an undefined attribute on pages that are level 1 and do not have a parent) and if so, whether the parent's slug is equal to the slug of the current page in the loop.

We enclose the second for-loop with an if-clause that checks both of the results, whether the current item in the loop is either  activePage or activeSubPage. The remaining code is identical to your code.

You could now check again, whether the sub-item is active, by using the same principle: {% if  (child.slug in slugs) %}active{% endif %}

Here is the complete updated code:

{% set pages = craft.entries.section('about').level(1).status('live') %}
{% set slugs = craft.request.segments %}

{% for page in pages %}
    {% set activePage = (page.slug in slugs) %}

        {{ page.title }}&nbsp;
        {% set activeSubPage = (entry.level == 2 and entry.getParent().slug == page.slug) %}
        {% if activePage or activeSubPage %}
            {% set subPage = craft.entries.descendantOf(page) %}

                {% for child in subPage %}

{{child.title}}

                {% endfor %}

        {% endif %}

{% endfor %}

I hope this helps and solves your problem. If you have any questions or if you do not understand my explanation (sorry for my bad English, I'm not a native speaker): Don't hesitate to ask!

Further improvements:

With some small improvements you could put this code into a file and use it recursively for navigations with more than two levels. In your template, you would then be able to include it like this

{% include "_includes/nav_links_withchildren" with { 'slug' : 'about' } %}

and would then include itself again to list sub-pages.


If you set the title format to a string like "Note" in the channel's field layout, all your entries will be given this exact name. The entry slug will be saved prefixed: "note-1", "note-2", etc.

If you don't want them all to be named the same, you could add a date to it:

Note {{ 'now'|date('Y-m-d') }}

This approach has one problem, if you make an edit to the "Notes" entry at a later point, the title will get updated to a new 'now' date. To work against that you can add a conditional to the code, checking if a title is already saved for that entry:

{{ object.title ? object.title : 'Note ' ~ 'now'|date('Y-m-d') }}

In the case you add more than one "Note" a day the entries would still be named the same though. To solve that, you could format 'now' to add a time to the title |date('Y-m-d H:i'), or you could use a counter instead. Because entry IDs are saved across all sections you wouldn't want to use them here.

But what you could do is to use the entry title of the previous entry in your "Notes" section (sorted by title) and modify upon that. Just name your first entry in your section "Note 001" and then use this snippet as the title format:

{{ object.title ? object.title : 'Note %03d'|format(craft.entries.type('note').order('title').last().title|slice(5) + 1) }}


Generally best practice is to look into the source code and see what happens in the function

/**
 * Manually activates a user account.  Only admins have access.
 *
 * @return null
 */
public function actionActivateUser()
{
    $this->requireAdmin();
    $this->requirePostRequest();

    $userId = craft()->request->getRequiredPost('userId');
    $user = craft()->users->getUserById($userId);

    if (!$user)
    {
        $this->_noUserExists($userId);
    }

    if (craft()->users->activateUser($user))
    {
        craft()->userSession->setNotice(Craft::t('Successfully activated the user.'));
    }
    else
    {
        craft()->userSession->setError(Craft::t('There was a problem activating the user.'));
    }

    $this->redirectToPostedUrl();
}

The important part is $this->requireAdmin();. Copy the function into a custom controller and remove that line and you are generally done. You can even hook into the CP template and include this the button on your own.

My Solution

I wrote a plugin that uses above method. It is accessed via a controller. I just changed the line that requires the user to be an admin. Then I just put a button somewhere in the CP that uses this controller action.

- $this->requireAdmin();

+ if (!craft()->userSession->getUser()->can('accessPlugin-MyNewPlugin')) {
+    throw new HttpException(403, Craft::t("You don’t have the required permissions for this operation."));
+ }


Is there any way of setting / forcing a default image transform for images inserted via rich text blocks?

I don't think it's possible natively, yet (as of 2.3). However, the ImageSmith plugin addresses this need by providing a 'bulk transform' Twig filter which detects images in HTML, applies a specified transform, and rewrites the HTML to reference the transformed images.


Duplicating shipping details from an Order into a Cart

Simple error on my part. You don't pass the old order's "shippingMethod" model to the new cart's 'setShippingMethod' function. You pass the old order's shippingMethodHandle to the setShippingMethod function.

The following works:

public function actionReorder()
{
    // basic security precautions
        $this->requirePostRequest();

    // get the current cart
        $cart = craft()->commerce_cart->getCart();

    // get the fields passed to us in the form
        $oldOrderNumber = craft()->request->getPost('oldOrderNumber');

    // get the 'old' order
        $oldOrder = craft()->commerce_orders->getOrderByNumber($oldOrderNumber);

    // set the shipping etc on the cart to the same as the old order
        $cart->shippingAddressId    = $oldOrder->shippingAddressId;
        $cart->shippingAddress      = $oldOrder->shippingAddress;

        if (!craft()->commerce_cart->setShippingMethod($cart, $oldOrder->shippingMethodHandle, $error)) {
            $cart->addError('shippingMethod', $error);
            LogicPlugin::log("error adding shipping method to cart: " . $error, LogLevel::Error);
        }

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


How can I get a restricted Asset Allowed File Type upload to accept RTF files

Does this help you? It'll let you add additional file extensions that are allowed to be uploaded.

http://buildwithcraft.com/docs/config-settings#allowedFileExtensions


Is it possible to add a custom field to User model from a plugin?

First of all, you will need the Pro package to be able to customise the user profile.

Then you would have to use the onAfterInstall and onBeforeUninstall events in your plugin file. These events are called when installing and uninstalling the plugin.

After the install, you need to create a new field and add it to the user field layout. And before uninstall, you have to remove the field from the layout and delete the field itself.

The code below should work, but it doesn't keep the required fields (I didn't find a way to get them using the available functions).

<?php

namespace Craft;

class UserfieldPlugin extends BasePlugin
{
    public function getName()
    {
        return Craft::t('Userfield');
    }

    public function getVersion()
    {
        return '0.9.1';
    }

    public function getDeveloper()
    {
        return 'Mario';
    }

    public function getDeveloperUrl()
    {
        return 'http://craftshake.com';
    }

    public function onAfterInstall()
    {
        // Create the third party field

        $thirdPartyField = new FieldModel();
        $thirdPartyField->groupId      = 1;
        $thirdPartyField->name         = Craft::t('Third Party');
        $thirdPartyField->handle       = 'thirdParty';
        $thirdPartyField->translatable = false;
        $thirdPartyField->type         = 'PlainText';

        craft()->fields->saveField($thirdPartyField);

        // Create the new user field layout

        $fieldLayout = craft()->fields->getLayoutByType(ElementType::User);
        $fieldsIds = $fieldLayout->getFieldIds();
        $fieldsIds[] = $thirdPartyField->id;

        craft()->fields->deleteLayoutsByType(ElementType::User);

        $fieldLayout = craft()->fields->assembleLayout(
            array(
                Craft::t('Profile') => $fieldsIds,
            ),
            array(),
            false
        );
        $fieldLayout->type = ElementType::User;

        craft()->fields->saveLayout($fieldLayout, false);
    }

    public function onBeforeUninstall()
    {
        // Get third party field
        $thirdPartyField = craft()->fields->getFieldByHandle('thirdParty');

        // Remove field from layout
        $fieldLayout = craft()->fields->getLayoutByType(ElementType::User);
        $fieldsIds = $fieldLayout->getFieldIds();
        $fieldsIds = array_diff($fieldsIds, array($thirdPartyField->id));

        craft()->fields->deleteLayoutsByType(ElementType::User);

        $fieldLayout = craft()->fields->assembleLayout(
            array(
                Craft::t('Profile') => $fieldsIds,
            ),
            array(),
            false
        );
        $fieldLayout->type = ElementType::User;

        craft()->fields->saveLayout($fieldLayout, false);

        // Delete field
        craft()->fields->deleteField($thirdPartyField);
    }

}

I hope this helps.

Mario


What is the best way of managing multisite propagation post setup phase?

It sounds like perhaps the problem you've got is that you're not making fields translatable? That would explain what you said about "Otherwise the content edited overwrites each site page ". The idea is that pages should stay set to propagate to other sections (to the group in your case), and the fields store the translation data.

Assuming that's the case, I think your problem would be solved if you didn't change that to "Only save entries to the site they were created in' and set up the fields themselves to be translatable. That would allow you to create new sites and propagate the pages.


Customizing the destination after user activates the account

Craft support desk helped me, so I would like to share it.

The destination can be set with this. Add it on your general.php.

'activateAccountSuccessPath' => 'users/login',

Please be sure to change 'users/login' to the destination you want to set.

If it does not works, add this;

'verifyEmailSuccessPath' => 'users/login'


Get entries filtered by author's category

You probably have to query twice, first get all the users and then get all news entries
published by any of these users using the authorId parameter on your criteria model.

{% set userRegion = currentUser.region.first() %}
{% set regionUsersIds = craft.users.relatedTo(userRegion).limit(null).ids() %}

{% set regionNews = craft.entries.section('news').authorId(regionUsersIds) %}


How can I add fields in the Sprout design your form?

To start off, you will probably want to update to the most recent version of Sprout Forms on Craft 2. As of this message, it looks like v2.6.4 is the most recent version:
https://github.com/barrelstrength/craft-sprout-forms/releases/tag/v2.6.4

Sprout Forms manages Fields independently of Craft so you will not see any of your Craft Fields when editing a Form. Fields you create for a particular form will only be available to that specific form.

Once you create a Form, you should see a New Field button below the initial empty Tab. You will need to add a Field to the Tab before you save in order for the Tab to be saved.


How can I purchase Craft Client or Craft Pro?

Go to the Settings page (/admin/settings - reached by clicking on the gear icon at the top right of the control panel) and you should see the following link at the bottom of the page:

Click on the Show me link and the modal window pops up.


How can I add a dynamic "active" CSS class to the navigation on any given page?

Tip: To keep it short and reusable I would recommend that you wrap your preferred "check-method" in a Twig macro, I like Anna's version the most:

_macros.html:

{% macro is_active(segment) %}{% if craft.request.firstSegment == segment %}active{% endif %}{% endmacro %}

layout.html:

{% import "_macros.html" as macros %}

News
Blog


If you need the background image to be dynamic and controlled by the client then I would recommend using inline CSS in the template to set the image path. The rest of the required CSS can be in the CSS file itself.

e.g.,

<div style="background-image: url('{{ entry.image.first().getUrl('transformName') }}')" class="thing" ... >

Your CSS file could even have a fallback background-url
and in your CSS

.thing { background-size: cover; ... }


Is there a maximum number of fields in a single matrix?

This is because of a combination of settings in your php.ini file:  max_input_vars & post_max_size, not any limitation in Craft CMS. c.f.:

Matrix field input error from within the control panel


You could use the Twig functions merge and default to merge the two sets of entries.

{% set entries = craft.entries.search(query).order('score')|default([]) %}
{% set authors = craft.users.search('fullName:*' ~ query ~ '*')|default([]) %}

{% if authors %}
    {% set results = entries|merge(authorArticles) %}
{% endif %}

<p>
    You have {{ results|length }} {{ results|length == 1 ? 'result' : 'results' }}.
</p>

The default function is a handy stand-in for short circuit evaluation in twig, so that you can be sure to at least pass an empty array to merge.


How do I check if a structure has any entries at level 3 when I'm at level 1?

To make it works I had to query in the section for descendant entries at level 3 of a current entry variable.

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

{% if lvl == 1 and products.descendantOf(entry).level(3).first()|length %}
    // If the above statment is true we don't want that special link at level 1
{% elseif lvl == 1 %}
    // A special link
{% endif %}

{% if lvl == 2 and entry.children|length %}
    // A special link
{% endif %}

I welcome a smarter solution.

Updated: Thanks to @carlcs comment a performance has been enhanced

{% if lvl == 1 and products.descendantOf(entry).level(3).total() > 0 %}
    // If the above statment is true we don't want that special link at level 1
{% elseif lvl == 1 %}
    // A special link
{% endif %}

{% if lvl == 2 and entry.children.total() > 0 %}
    // A special link
{% endif %}


ImageOptimize not using image url specified in my multi-environment setup and my volume config

You need to re-index your assets to show the correct URL after changes to your volume location when using imageOptimize. Just re-save the volume from within Craft CMS. Even if you have made amends to your volume config file you will need to re-save from within Craft CMS.

To quote Andrew, the plugin author...

  "So I want to say that this is normal (though maybe not desirable?)l.
  The URLs in the OptimizedImages fields get resolved at asset save
  time. So the full absolute URL to each image will resolve to whatever
  the alias is.

  Potentially this resolution could be postponed until runtime, but in
  the interim, if you re-index your assets on the environment."


This happened to me and London is relatively new and unsupported at one point, try changing the location to Oregon to see if this works


Restricting relationship field by author

Craft's permission system doesn't go down to the field level, which is what you're looking for.

You'd either have to replicate the functionality you're looking for on the front-end of the site, or develop a custom field type that took into account custom permissions for your users.


Can I limit the available styles from the rich text field?

Redactor is the name of the Rich Text field itself, as this is a 3rd party component Craft has taken great use of!

With Craft you are able to create custom Redactor configurations whereby you have control over which options you would like useable (bold, italic etc), and these can be set on a per-field basis.

Have a look at the Craft site for details on how to set your own custom Redactor configurations: http://buildwithcraft.com/docs/rich-text-fields#redactor-configs

When you edit a Rich Text field in Craft you will see a 'Config' dropdown. These are the files you have created in craft/config/redactor (see above link for details)


Has anyone converted a Bootstrap based website to Craft?

I built Progress.org using Craft and Bootstrap—and it only took me about two months of part-time work. I’d say Craft and Bootstrap together are a match made in heaven. Here’s why:

1) Bootstrap is an out-of-the-box template that gives you great flexibility if you want to design your website how you want it to look. I found other frameworks like WordPress overly constraining.

2) Craft allows for near unlimited customizations as long as you know your front-end HTML/CSS.

If you know your HTML/CSS, then a Bootstrap/Craft combination is ideal, in my experience.


Taking out the comma after POST seems to work

Correct.  A common is only needed if you want to allow multiple HTTP methods like POST,PUT.

Here's the Yii documentation on the topic: https://www.yiiframework.com/doc/guide/2.0/en/runtime-routing#http-methods


How to fetch matrix block items with the ElementAPI

Matrix blocks are elements just like entries and assets, so this is just a matter of setting the elementType to 'MatrixBlock', and adjusting your criteria to fetch the block you’re after.

The simplest approach would be to pass the Matrix block ID in the URL, and apply it to the id criteria parameter.

'endpoints' => [
    'matrix-blocks/<blockId:\d+>' => function($blockId) {
        return [
            'elementType' => 'MatrixBlock',
            'criteria' => [
                'id' => $blockId
            ],
            'first' => true, // Just return one Matrix block
            'transformer' => function(MatrixBlock $block) {
                $assetsInfo = [];

                foreach ($block->myAssetsfield as $asset) {
                    $assetsInfo[] = [
                        'url' => $asset->url,
                        'title' => $asset->title,
                        // ...
                    ];
                }

                return [
                    'id' => $block->id,
                    'assets' => $AssetsInfo,
                    // ...
                ];
            },
        ];
    }
]

You can also use the following criteria parameters to narrow down the search:

fieldId (the Matrix field ID)
ownerId (the owner element ID, e.g. your entry’s ID)
ownerLocale (the locale of the owner element that the block should have been saved to)
type (the block type handle)


How do I select entries that have a particular block type?

You can write a custom plugin and make use of Craft's buildElementsQuery, to be able to add custom query statements to your ElementCriteriaModel.

Give your plugin a Template Variable addVideoBlockCriteria and with some lines of plugin code you will be able to do something like this from your template:

{% set criteria = craft.entries.section('blog').order('title asc') %}
{% set entries = craft.businesslogic.addVideoBlockCriteria(criteria) %}

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

Make your Template Variable pass the criteria to a plugin service, run them through buildElementsQuery, and you can now modify the query with some DbCommands.

public function addVideoBlockCriteria(ElementCriteriaModel $criteria)
{
    $query = craft()->elements->buildElementsQuery($criteria);

    $query->andWhere('matrixcontent_article.field_video_videoUrl is not null');

    $query->join('matrixblocks matrixblocks', 'matrixblocks.ownerId = entries.id');
    $query->join('matrixcontent_article matrixcontent_article', 'matrixcontent_article.elementId = matrixblocks.id');

    $results = $query->queryAll();

    return EntryModel::populateModels($results);
}

Use join to bring in the "matrixblocks" table and also your Matrix field's content table "matrixcontent_mymatrixfield". And add the conditions with andWhere;  the Matrix field's fields column names follow a scheme "field_myMatrixBlockType_myFieldInMatrixBlock".


Depending on what you are searching by, you can use something similar to this. You can see the properties you can search by in the documentation.

$criteria = craft()->elements->getCriteria(ElementType::Category);
$criteria->group = 'CategoryGroupName';
$criteria->title = 'CategoryTitle';
$criteria->limit = 1;

$category = $criteria->find();


You're correct in that animated GIFs will only have their animations preserved if your server has Imagick installed.

If you're getting an error installing Imagick on MediaTemple, the you're better off contacting them with the error and seeing if they can help resolve the issue.


How to call abstract method from interface

The normal way would be to instantiate and call non-statically like this:

(new \craft\base\Volume)->fileExists($path);

...However, that won't work here because it's an abstract class, which, by definition, cannot be instantiated. Assuming you're dealing with an Asset element(?), try calling getVolume() and then you should be able to call fileExists() from there. E.g:

$asset->getVolume()->fileExists();


Testing database credentials Craft 3 Setup

This might be the problem with the pgsql driver.
You need to install and activate postgresql extension in PHP
You can use below command to install it.
[sudo] apt-get install php-pgsql

For activating it, uncomment pgsql and pdo-pgsql extensions in etc/php/$PHP_VERSION/apache2/php.ini file.
After all this you need to restart you apache server and the try to connect again.


Is it possible to force Craft to recheck available sever modules?

Craft will re-run the requirement checks simply by loading that admin/utils/serverinfo page.  The results aren't cached.

It sounds like your box may have had the ImageMagic library installed, but not the PHP wrapper for it.  You can check by going to admin/utils/phpinfo and searching for imagick and if there are no results, it's not installed.

Alternatively maybe it is installed, but you're explicitly setting the imageDriver config setting to 'gd'.  Be default, it's set to null which means Craft will automatically use Imagick if it sees its available.


CraftCMS: Search entries by title in CMS

It does search for the title by default.

I'm assuming you're on MySQL for the database. The searchindex table uses the MyISAM storage engine by default and example happens to be of the default MySQL MyISAM stopwords: https://dev.mysql.com/doc/refman/8.0/en/fulltext-stopwords.html (see "Stopwords for MyISAM Search Indexes"), which it will skip.


Can not login in the control panel: Internal Server Error 500

The error was caused by the configuration in general.php, which works fine local and on three other websites.

For production environment, I added

'userSessionDuration' => 'P101Y',
'rememberedUserSessionDuration' => 'P101Y',
'rememberUsernameDuration' => 'P101Y',
'invalidLoginWindowDuration' => 'P101Y',

Now I removed it and can login in the cp - no idea why.


Translating static text in JavaScript files

For now I'm going with this solution:

<script>

    var translatedLabels = {
        'name' : {{'Uw naam'|translate}},
        'email' : {{'Uw e-mail adres'|translate}},
        'email_receiver' : {{'E-mail adres van de ontvanger'|translate}},
    }

</script>

The above is in a template file that gets included on the relevant pages, if it turns out I'll need those or other translated texts in multiple parts of the website, I might just include it in the basic layout directly.

It allows me to keep doing the translations from the backend with that translation plugin and I can now use the translated messages in my Javascript generated HTML.


Is it possible to convert plain text array to an unordered list?

Something like this should work:

{% set listItems = plainTextValue|replace('/[^, a-zA-Z0-9_-]|[, ]$/s','')|split(',') %}

  {% for listItem in listItems %}
    {% if listItem|length %}

{{ listItem|trim }}

    {% endif %}
  {% endfor %}

What the above does is to first use the replace filter to remove any character that isn't alphanumeric (except spaces and commas), before the resulting string (which would look something like 'Abdominal Pain,RUQ,Vomiting') is split on the commas. The resulting array is stored in a variable listItems. Finally, it's just a matter of looping through that array, to create the
 items.

Note that in the above example, plainTextValue is a variable containing the string '["Abdominal Pain","RUQ","Vomiting",""]' – so swap that out with entry.logGeneral_logInputIndications, or whatever fits.

Edit (OP added more info to the original question)

If your "symptoms" are in fact hierarchical, I'd suggest not using a PlainText field at all. You're quickly running into a situation where your back-end solution is way too simple, which will make your front-end solution way too complex.

My definitive recommendation would be to create a Categories group for the symptoms, and swap out the PlainText field for a Categories field.

Note that you can still render the actual symptoms form element on the front end as checkboxes, you'd just pass in an array of category IDs instead of a plain text string (the following example assumes a Categories group with the handle symptoms and a Categories field with the handle selectedSymptoms):

{# Get all available symptoms #}
{% set symptoms = craft.categories.group('symptoms').limit(null) %}

{# Get the symptoms that have been selected for this entry earlier #}
{% set selectedSymptoms = entry.selectedSymptoms.ids() %}

{# Loop through the available symptoms, creating checkboxes #}
{% for symptom in symptoms %}
    <input type="checkbox" name="fields[selectedSymptoms][]" value="{{ symptom.id }}"{% if symptom.id in selectedSymptoms %} checked{% endif %} />{{ symptom.title }}

{% endfor %}

...and to display whatever symptoms are already selected – in nested lists, as per the category hiearchy, you can use the {% nav %} tag:

{% nav symptom in entry.selectedSymptoms %}

        {{ symptom.title }}
        {% ifchildren %}

                {% children %}

        {% endifchildren %}

{% endnav %}


I ran into the same problems as you and I believe I've solved it, but it may be different for your specific use case.

There may be a way to control this with the init options but I wasn't able to find a way to do it, so I just edited the searchplus.js code directly in the searchplus folder. Look for something like e.getFacetValues(i,{sortBy:["isRefined:desc","count:desc"]}) and change it to e.getFacetValues(i,{sortBy:["name:asc"]}) instead (you can leave the isRefined:desc part at the front as well if you would like the filtered options to automatically populate to the top of the list). Keep in mind that changing the js file is a global change which would affect other faceted forms if you have more than one on your site.
When you define the facets in your init code: $(this).searchplus({facets: ['facet1', 'facet2'],});, replace facets with disjunctiveFacets and you should stop seeing filters disappear from the facet you're selecting (see faceting options on the Search Plus docs. The other facet's filters will disappear though depending on if there are valid matches or not, but it will at least prevent the other filters from your selected facet from disappearing immediately.


Extending Assets with oEmbed video references

Craft gives you the ability to combine different type of content in one single field, the matrix field. Configure one matrix block type for your images and one for your video links.

This setup still allows you to re-order your content (the matrix blocks) using drag & drop. You can further extend your entries with other types of content (maps, quotes, etc.) and have better accessibility to any fields assigned to your images and videos (not hidden behind double click).


You can try to use the following code to loop through the locales:

{% set locales = craft.i18n.getSiteLocaleIds()%}

{% for locale in locales %}
    {% set localeEntry = craft.entries.id(entry.id).locale(locale).first %}
    {{ localeEntry.title }}
{% endfor %}

A full solution for a language switcher is described under How can I build a language switcher?


I'll use myself as an example, so if something isn't right we'll know who to blame.

First thing I do is set up an environment variable in my craft/config/general.php file like this:

...
'.dev' => array(
    'devMode' => true,
    'siteUrl' => 'http://mysite.dev/',
    'environmentVariables' => array(
        'basePath' => $_SERVER['DOCUMENT_ROOT'] . '/',
        'baseUrl' => 'http://mysite.dev/',
    )
)
...

Then, when I am creating assets sources, I'll create a general "Images" source:

Name: Images
Handle: images
File System Path: {basePath}media/images/
URL: /media/images/

Note that I am using my environment variable in the file system path.

{basePath}

You can call that whatever you want, it just has to match.

So if you were to view the source of my site, an image that was uploaded would have the path of:

http://www.mysite.com/media/images/my-image.jpg

Hope this helps!


Firstly I'd recommend splitting the first name and last name into seperate fields. That way in your templates it would look nicer:

{{ member.firstNameField }} {{ member.lastNameField }}

than having:

{{ member.firstNameField }} {{ member.title }}

when outputting their names.

Once you have done that, in your entry type settings you can set the entry title to run off these first name and last name fields:

{firstNameField} {lastNameField}

The slug will be automatically generated from this as well. I may have mis-understood your question, but I hope that helps.


How to set cookie and redirect to page one time

Try this:

{% if currentUser %}
    {% set name = currentUser.firstName %}
    {% if craft.lj_cookies.get('account') != name %}
        {% do craft.lj_cookies.set('account', name) %}
        {% redirect name %}
    {% endif %}
{% endif %}

In you're original code you're setting the cookie before getting it into the redirect variable, so the {% if redirect == name %} conditional is always true.


There's currently no method to parse variables into the feed itself through this, or any means. Typically, we approach this as feeds being third-party, or otherwise non-editable. How would you see utilising issueNumber to work in this scenario?

You can use the concept of aliases in your URL if that helps?

Lastly, you could also make use of the (undocumented) Datatype::EVENT_AFTER_FETCH_FEED event to perform any parsing on the feed once its been fetched?


How to get next entry by date in matrix block but limit to just 1

I think this should do it.

{% for block in workshop.workshopSession.sessionDate('>=' ~ now|date('Y-m-d')).limit(1) %}

If not you always can go with a "dirty" fix by just showing the {% loop.first %}


How to fetch specific users OR admins with the ElementCriteriaModel?

You won't be able to do that using the ElementCriteriaModel or a single query (unless you use craft ()-> db-> createCommand() or \CDbCriteria to perform a conditional JOIN).

You will either have to 1) do post filtering or 2) get the ids for users in the groups you want and the ids for all admin users (which I would recommend). You can then merge both arrays and use the resulting array to get all users that match the containing ids.

You mentioned that you wanted to do it the clean way and doing a couple of queries using the public Element Query API is definitely the clean way to do it and the fact that you're doing a couple of queries to get the users you want should not feel "unclean" because that is happening in a lot of different places behind the scenes when you use the API instead of raw queries.

For example, when you add the $ criteria->groupId = array(1, 3); to a user query, Craft will hit the db once to get all ids for users in those groups and then hit it again as many times as necessary to do what it needs to do, like perform searches and such.

My point is, using the API means that you might not be able get everything in one go but your plugin won't break if Craft changes any internal APIs.


Excluding a single Entry ID of an Entry Type from craft.entries

You'd have to add a conditional and render the featured entry on the first paginated page only. You can access that info from the pageInfo variable.

Another thing I'd do is to remove the featured entry from the all entries criteria model by prepending the ID with 'not' in the id param (i.e. id('not 72')). You can probably reduce the amount of database queries with that change.

{# Get the featured entry #}
{% set featuredEntry = craft.entries.section('news').type('article').first() %}

{# Get all other entries #}
{% set idParam = 'not ' ~ featuredEntry.id %}
{% set entries = craft.entries.section('news').id(idParam) %}

{% paginate entries.limit(10) as pageInfo, pageEntries %}

{# Render the featured entry for the first page only #}
{% if pageInfo.currentPage == 1 %}
    {% include '/partials/_featuredArticleTemplate' with {
        entry: featuredEntry
    } %}
{% endif %}

{# Render all the other entries #}
{% for entry in pageEntries %}
    {# include partial #}
{% endfor %}


Craft CLI ./craft - can I tell it to use a specific php version when running composer via the CLI?

This is something I completely overlooked, but the Craft CLI is just a PHP wrapper that's executable on the CLI. So this will work:
/usr/bin/php73 craft help
or
/usr/bin/php73 craft update all
Will run the CLI with the PHP binary of your choice.


How do I use dynamic variables for plugin settings?

First - you don't need a template file. You can type the template right into the settings textarea like you already had, and like the other email twig templates do it. Then, in your service, you do:

$email->body = craft()->templates->renderString($settings->welcomeEmailMessage, ['firstName'=>$firstName]);

The settings textarea then need to have something like:

Hello {{firstName}}, welcome!

And then you should be all set!


Sounds like production has a case-sensitive file system and locally you don't.

For example, you're trying to render a template called mytemplate.html on the file system, but you're using myTemplate.html in the plugin code.


How to get parent categories from an entry?

Assuming you have a Categories field associated with the entry, you can get all of the related categories in your template via entry.myCategoriesField (replace with the actual Categories field handle).

So here’s how you would loop through all of them:

{% for category in entry.myCategoriesField %}

{{ category.title }}

{% endfor %}

If you just want the last 2 categories, you can use Twig’s slice filter:

normal syntax:
{% for category in entry.myCategoriesField|slice(-2) %}

shortcut syntax:
{% for category in entry.myCategoriesField[-2:] %}

If you want to set these categories to their own variables, so they can be referenced later on in your template, you could do this instead:

{% set parentCategory = entry.myCategoriesField.last() %}
{% set grandparentCategory = parentCategory.parent() %}


How can I set up tiered volume discounts without enacting a waterfall effect of multiple discounts being applied?

Currently at Craft Commerce 1.1 this is not possible with the current discount engine.

We would need to implement features like a min qty AND a max qty for the discount rules. It is on our radar.

Fee free to vote for extended discount conditions features here: http://feedback.craftcms.com/forums/295386-commerce/filters/top


Where can I edit the "Service Unavailable" page/template?

Try creating a 503.html file at the root of your templates folder. This should override the default template located at craft/app/templates/503.html.


Retrieve Matrix Field from Related Category in Element API

I've found a workaround for now. It's not ideal and I feel like it will probably be too intensive at scale but, for my uses, it will work.

Rather than using select() to reduce the data being returned from the initial query, I'm simply returning everything:

$related = Entry::find()
   ->relatedTo($entry)
   ->all();

I'm then looping over the returned object using foreach(), within which I'm dealing with the Matrix blocks in a seperate foreach(). At both levels I just pass back the data I want, something like this:

$reviews = [];
foreach ($related as $relatedEntry) {

   // Condense matrix blocks
   $critiques = [];

   foreach($relatedEntry->critique as $block) {
      $critiques[] = array(
         'title' => $block->seriesTitle,
         'copy' => $block->review,
         'date' => $block->date,
         'viewCount' => $viewCount,
      );
   }

   $reviews[] = [
      'id' => $relatedEntry->id,
      'slug' => $relatedEntry->slug,
      'title' => $relatedEntry->title,
      'critiques' => $critiques,
   ];
};

The output $reviews[] array is therefore equivalent to what I was doing with select() but not contains subarrays of my matrix field. Incidentally, I have managed to nest that one further with a SuperTable field within a matrix field. It needed another nested foreach() but it worked easily enough.

Once you have all of that, you can just pass it back to the endpoint like normal, so the whole thing (with above sections of code collapsed) looks like this:

'api.json' => function() {
   return [
      'elementType' => Category::class,
      'criteria' => ['group' => 'series'],
      'paginate' => false,
      'transformer' => function(Category $entry) {
         $related = Entry::find()
            ->relatedTo($entry)
            ->all();

         // Loop over related entries to extract just the information wanted
         $reviews = [];
         foreach ($related as $relatedEntry) {
            {...}
         };

         return [
            'id' => $entry->id,
            'slug' => $entry->slug,
            'title' => $entry->title,
            'reviews' => $reviews,
         ];
      }
   ];
}

As I say, not ideal so I'm leaving this unanswered. If anyone has a more elegant solution I'd love to know.


I ran into a similar problem with categories and routing a while ago and Marion's answer in this thread worked for me

How would I include the first category slug in the section's entry URL format?

Darrell


What's best practice for creating an index page for Channels?

If you are using a Structure to manage your site hierarchy, and the news index page naturally falls in that hierarchy, then yes, this can work well. Make an entry type for the index page, and in your template (which is the same for all the entry types),

{% include ['_page/'~entry.type, '_page/_default'] %}

(So if you haven't defined a template for this entry type you will use the _page/_default.html template instead of getting an error).

I think it is a good idea to use an entry for the index page (rather than just an index template) because there is very likely to be some content on that page other than just the list of news items, and you will want the CMS to manage that content for you.


Upload failed. The error message was: "SQLSTATE[23000]: Integrity constant violation:

Does this only happen with this one particular image? If so, try renaming the image file to golden-pothos-2.jpg or something and then uploading again.


Preserve formatting when exporting from Wordpress

Just needed to save each entry and formatting corrects itself.


I think I did this successfully with help from another answer on here. I removed the data from the craft_elements table by using the fieldLayoutId column to identify the entry type I wanted to remove. Seems it removed the data from the other tables as well.


Use conditional for Element API results?

If you want the latest of both, unless I'm missing something, you should just be able to query on dateUpdated.

When you create an entry the first time, its dateUpdated gets set to the same date as the dateCreated... So if you query your entries on dateUpdated only, you will get all entries created + updated in your time frame I guess.

As far as code goes, this should do it:

return [
    'endpoints' => [
        'entries.json' => function() {
            $timeframe = (new \DateTime('1 day ago'))->format(\DateTime::ATOM);
            return [
                'elementType' => Entry::class,
                'criteria' => [
                    'section' => 'entries',
                    'dateUpdated' => '>=' . $timeframe,
                ],
                'transformer' => function(Entry $entry) {
                    return [
                        'title' => $entry->title,
                        'url' => $entry->url,
                    ];
                },
            ];
        },
    ]
];


Please see Users relatedTo multiple categories for improved answer since this questions details are outdated.


How to pass an entry's Matrix fields as JSON?

I'd strongly recommend looking at the Element API plugin for this.

If you're dead set against that, there are other examples of how to pull out section data in Craft for rolling your own JSON.

For Matrix it'd be no different that if your were pulling Matrix data out to be output in HTML instead of JSON (looping through blocks, grabbing fields, etc). Lots of examples in the Matrix templating docs.

The error you're getting is because when you simply output entry.myMatrixHandle, you're technically given back an ElementCriteriaModel object and the Element API plugin tries to convert that to a string to display in the JSON data and it doesn't know how to convert that object to a string.


When I try to edit an entry: "Unable to find 'craft\services\EntryRevisions'"

Try to replace or upload all the files again. A file is not fully uploaded and the reason of this error is that.


Link to the product from the shopping cart

{{ item.purchasable.url }}

should do it.


Locked out of my Account, how to get back in?

This is not actually my answer since it's from Andrew Welch on Twitter here: https://mobile.twitter.com/nystudio107/status/1063135843441954816

If you have access to MySQL, you can change the admin user password to secret using this hash:
$2y$13$FfVKvo1W1N5Gsba3c19r8uz.x9R5NRQgRu8jmXvOjVCStg1sKGcoW


Could different entities have the same handle?

No, having a field and a category group (or a section and a user group etc) share handles isn't dangerous at all.

Being specific and semantic with handles in general can be a huge boon for keeping things easily memorable and templates and other source code readable, though – so for example you might want to have handles like genre (for the category group) and selectedGenres (for the categories field), instead of both using genre. Though technically, both can be named genre, no worries.


Retrieve matrix content from Entries form field in an Entry

When you loop through your matrix, you're missing the s on components. Should be:

{% for block in template.components %}

Each item in that loop will be one of the blocks in the matrix. So then you can call {{ block.component }} directly.

FYI, in your code, it looks like that component field in the matrix block is loopable as well? If you're trying to loop through an entries field, and then loop through a matrix field per entry, and then loop through another field per matrix block, expect some serious performance issues.

Full code reference:

{% for template in entry.chooseTemplateExample %}
  View {{ template.title }} example

  {% for block in template.components %}
    {% for component in block.component %} {!-- Is this field really loopable? --}
      {{ title }}
    {% endfor %}
  {% endfor %}
{% endfor %}


Allow Author to Build Multiple Choice Question?

There isn't a field type or plugin I know of that will let an admin choose only 1 correct answer.

One possibility would be to number the correct answer in another field like piotrpog suggests. I would argue this is possibly more confusing and brittle since an admin could accidentally update the answer choices without updating the correct answer field. The two fields aren't linked automatically.

I think it's pretty reasonable to ask admin's to only mark one choice as correct. You could also reinforce this in the field instructions. The lightswitch field makes it pretty easy to scan the column to make sure.


This does not target the database cache specifically but I wrote this simple plugin to clear all caches from outside of the control panel.

https://github.com/themccallister/craft.cache-clear

Would that work for you?


Check length of textfield in header file

This should do it for a text field:

craft.entries.section('aboutus').textField(':empty:')|length

To see if a Matrix field has any blocks, it's not as pretty.  There's probably a better way, but it's all I can think of at the moment:

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

{% set validEntries = [] %}

{% for entry in entries %}
    {% if entry.matrixField|length %}
        {% set validEntries = valid|merge([entry]) %}
    {% endif %}
{% endfor %}

validEntries is now an array of entries that have at least one block.


To do math in twig, you will need to use the set tag to do assignments, and the + operator to do addition. When doing math inside a for loop, you will need to keep in mind that

  loops are scoped in Twig; therefore a variable declared inside a for loop is not accessible outside the loop itself.
  If you want to access the variable, just declare it before the loop.

It looks as if you have a collection of things that represent seat counts, and you want to loop over them and calculate the totals. So, something like this:

{# define and intialize our variables outside the loop #}
{% set kidSeatTotal = 0 %}
{% set parentSeatTotal = 0 %}

{# loop over the seatCounts and add them up #}
{% for seatCount in thing %}
  {% set kidSeatTotal = kidSeatTotal + seatCount.seatsKids %}
  {% set parentSeatTotal = parentSeatTotal + seatCount.seatsParents %}
{% endfor %}

{# maybe we want the grand total as well #}
{% set grandSeatTotal = kidSeatTotal + parentSeatTotal %}

{# now we can output them: #}
kid seat total: {{ kidSeatTotal }}
parent seat total: {{ parentSeatTotal }}
grand total: {{ grandSeatTotal }}


Using Shortlist plugin to create product wishlist

You can definitely use Shortlist for this.  Here's some code to get you started.  Note in this I allow the favouriting of both products and pages/articles.

Code to let user add the favourites -

    {% set item = craft.shortlist.item(id) %}

And to display the favourites/wishlist - first we prepare by separating products from regular elements:

        {# Prepare the output data #}
        {% set lists = craft.shortlist.lists %}
        {% set favouriteArticleIDs = [] %}
        {% set favouriteProductIDs = [] %}

        {% if lists|length %}
            {# We just store everything in one list... #}
            {% for list in lists %}
                {% for item in list.items %}
                    {% set favId = item.elementId %}
                    {% if item.element.elementType == 'Commerce_Product' %}
                        {% set favouriteProductIDs = favouriteProductIDs|merge([favId]) %}
                    {% else %}
                        {% set favouriteArticleIDs = favouriteArticleIDs|merge([favId]) %}
                    {% endif %}
                 {% endfor %}
            {% endfor %}
        {% endif %}

...then to actually fetch & display the results we do this:

            {% if not favouriteProductIDs|length %}

                No favourite products?  Why not add some?

            {% else %}

                {% set products = craft.commerce.products.id(favouriteProductIDs).order('title').with('variants') %}

                {% import "_macros/productPreviewsLib" as productPreviewsLib %}

                {{
                    productPreviewsLib.productPreviews(products,
                    {
                        'display' : 'Table',
                        'showUnavailables' : true,
                    })
                }}

            {% endif %}

(The macro just does {% for product in products %} etc)

That should get you started!


Dev Mode introduces a lot of extra overhead for many processes. It profiles and logs all MySQL queries to the browser's console. For a detailed description of what Dev Mode does, please check out this page of the docs...

  What Dev Mode Does

Specifically, this line is critical...

"Dev Mode is definitely not suited for production environments."


How to create an auxiliary page with sub url?

First you'll want 3 templates — I'll call them 'news/index.html', 'news/_entry.html', and 'news/_extra.html'. (fyi... using an underscore before the template name is good practice as it prevents the template from being loaded directly; which would likely throw an error because no entry would be defined.)

You'll then want to create a custom route to the 'extra' page in settings, using the 'slug' token for one of the segments.

If your url looks like this: news/slug/extra (where 'slug' is the slug token)
Load this template: news/_extra.html

In the '_entry.html' template, you'll want to check your 'additional' field and create a link to your '/extra' page. Note: 'entry.url' should already include the 'news/slug' portion of the uri — we'll just be adding the '/extra' segment.

{% if entry.additional %}
    extra page
{% endif %}

In the '_extra.html' template, there should now be a 'slug' variable available to your entry.

{% set newsEntry = craft.entry.section('news').slug(slug) %}
{% set newsIndex = craft.entry.section('pages').slug('news') %}
{{ newsIndex.title }} — {{ newsEntry.title }}

Note: I don't know in what section your 'news' index page is. I just picked something at random — you'll need to change that to match your structure.


If you want to "redirect" all parent entries of your structure that have child entries, you could do something like this in your navigation (untested code!):

    {% nav page in pages %}

            {% if page.getChildren()|length %}
                {{ page.title }}
            {% else %}
                {{ page.title }}
            {% endif %}

            {% ifchildren %}

                    {% children %}

            {% endifchildren %}

    {% endnav %}

If you want to exclude specific parent entries from that behavior, you could do this like so:

{% if page.getChildren()|length and page.id('and, not 1, not 2, not 3') %}


You're correct. Craft will not run validation upon saving disabled elements.

This is not a bug – it's just designed that way (as far as I can tell from looking at the relevant source code in the ElementsService).

As for a workaround – you'll need a plugin.

This is the easiest approach I can think of:

Listen for the entries.onBeforeSaveEntry event
In the event handler, validate the entry model manually, if the entry is disabled
If validation fails, add error messages to the model and set the $event object's performAction attribute to false

This should stop the entry from going through, and should also display any error messages in your form:

craft()->on('entries.beforeSaveEntry',function(){
    $entry = $event->params['entry'];
    if(!$entry->enabled && !craft()->content->validateContent($entry))
    {
        $entry->addErrors($entry->getContent()->getErrors());
        $event->performAction = false;
    }
    return $event;
});

Anyway, since I wanted to test the above before responding here, I wrote the plugin. It seems to do the job, so hopefully it'll help you out!

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


No more than 10 blocks in globally used Matrix fields get saved

Brad Bell: "There's about a 99% chance you're bumping into your php.ini file's max_input_vars value and/or its post_max_size. If you bump those to higher values, it should start working as expected"

Matrix field input error from within the control panel


You're trying to your float variable using another variable at the moment that isn't defined. I expect you mean to set float to the string value "yes" like so:

{% set float = "yes" %}

You could also use a conditional around your class declaration so you don't end up with empty classes and it'd also remove the need to define float as an empty value.

<div{% if float is defined %} class="{{ float }}"{% endif %}> more code here </div>


What do multiple columns of a record being set to unique mean?

It means that no combination of those two columns can be the same in the table stated in the getTableName() of your record.


Is it possible to show more entries of the same entry type as the current entry?

Yes. This is certainly possible.

I'm not sure how you're templating / naming is setup but you can get entries by entry type and you can check an entry's type. To get entries by a specific type:

craft.entries.section('blog').find({type: 'imagePost', limit: 10})

Here's some helpful references for craft.entries:
Entries Cheat Sheet - Craft Docs For the Entry Model

You could structure some kind of comparison, to see if the current entry is a specific type, and if it is query and render the desired additional entries.

{% if entry.type == 'imagePost' %}
  {% for post in craft.entries.section('blog').find({type: 'imagePost'}) %}
...
{% if entry.type == 'textPost' %}
  {% for post in craft.entries.section('blog').find({type: 'textPost'}) %}
...

However there are many ways to do what you want depending on your setup. Please note I used the name imagePost instead of image, to avoid any confusion there might be with a common name like image. I'm not sure if that could cause name conflicts or if it's a reserved keyword / field etc.


How to modify entry with a users field in the front-end?

Sure... you'd just do it through whatever input tag you want using the name="fields[fieldHandle][]" syntax passing in the user's ID as the value.

There are examples of that here, under the "Relations" header:

https://straightupcraft.com/articles/craft-cms-field-guide-twig?view=input

You won't be able to do that should an anchor link GET request though... EntriesController::saveEntry() is explicitly checking for a POST request, so you'll want to do it though a proper form: https://craftcms.com/docs/templating/entry-form


Change asset upload path based on locale

{craft.locale} won't work because the single curly brace syntax is short for {{object.craft.locale}} where object is the element that is currently being edited (in your case, the entry).  You can read more about that here: https://craftcms.com/docs/assets-fields#dynamic-subfolder-paths

Your screenshot shows the double curly syntax, though (which should work fine).

Alternatively you could use {locale}, which would translate into {{object.locale}}, which would be the currently locale of the entry.


Using an IF-statement to define the Entry URL Format

Alright, I was able to figure it out myself:

channel{% if object.type == 'xyz' %}/{type}{% endif %}/{slug}

produces the desired results. The section for Dynamic Entry Titles in the docs pointed me into the right direction.


How do you save custom fields on an EntryFixture?

Prepending the field name with field: should do the trick.
<?php

return [
    [
        'sectionId' => $this->sectionIds['locations'],
        'typeId' => $this->typeIds['locations']['locations'],
        'title' => 'Location 1',
        'field:gmbId' => '123',
    ],
];

See https://github.com/craftcms/cms/blob/develop/tests/fixtures/data/entry-with-fields.php for reference.


Is there any way to prevent Craft from doing anything with uploaded GIF assets?

When you upload an image to Craft, the image is automatically “cleansed” using the same basic process that Craft uses to create image transforms. That happens to ensure that there are no malicious scripts hidden in the images, and it’s not something you can disable.


Refresh Craft for loop with form parameters

You will need to use JavaScript, either AJAX calling to a template that re-runs a new Twig for loop and returns the results in HTML, or a framework like Vue or React in conjunction with P&T's Element API that will create an endpoint of your section's entries in JSON format.

If you don't mind a page refresh, you can filter your entries dynamically using craft.request to grab pretty much whatever you want: a segment from the URL, query string, post data, etc. So basically, when the form submits, your redirect url should go to that page and either you add submitted data to the url via get or grab the data via post.

Also, fyi, you have a syntax error in your code: missing a ) at the end of your .relatedTo ;)


How to Prevent Composer from Updating Plugin?

If you have version 1.2.3 of the plugin installed and you don't want to Composer to update past that version, you'd just modify your composer.json file so it's locked to that exact version.

"require": {
    "plugindeveloper/pluginhandle": "1.2.3"
}


Force browser to download latest CSS file

There are several plugins that can do this.

With my plugin Stamp, you can add a timestamp to the filename or path in the following formats:

<script src="/assets/build/js/1399647655/scripts.js"></script>
<script src="/assets/build/js/scripts.1399647655.js"></script>
<script src="/assets/build/js/scripts.js?ts=1399647655"></script>

The last one, which is the one you're looking for is made with:

<script src="{{ craft.stamp.er('/assets/build/js/scripts.js', 'query') }}"></script>

You can also get only the timestamp, and use it however you want, like this:

{% set timestamp = craft.stamp.er('/assets/build/js/scripts.js', 'tsonly') %}

It's worth noting that you'd ideally want to not use a query string for this, as various frontside proxies could ignore it. But, you need to be able to set up the proper url rewriting in your webserver for the filename and folder versions, so that might not always be possible.

There is also Cache Buster from Focuslab which can add a query string, but also supports file revisioning based on a manifest file.

And there's Asset Rev from Club Studio which is primarily for file revisioning based on a manifest file, but falls back to a query string.


Why do some entries generate a template error on get next or previous post when others do not?

First – you're passing a string value ('posts') to the getNext() and getPrev() methods, which will produce unreliable results.

The getNext() and getPrev() methods actually expect either an ElementCriteriaModel instance, or an object representing an ElementCriteriaModel's attributes (i.e. a query like { section: 'posts' } – not a string, number or any other, non-iterable value.

I'm guessing 'posts' is a section handle, but Craft won't know that and it will just ignore the string and return any element matching the current element's type - so if you call entry.getNext('posts'), you're probably going to get an entry back, but it won't reliably be an entry from the 'posts' section; it could be an entry from any section in your system.

So here's how your code probably should look:

{% set criteria = { section: 'posts' } %}
{% set prev = entry.getPrev(criteria) %}
{% set next = entry.getNext(criteria) %}
...

If this code is in an entry template, you could even do something like this:

{% set criteria = { section: entry.section } %}
{% set prev = entry.getPrev(criteria) %}
...

An additional tidbit: The only instance where it's ok to call getNext() and getPrev() without passing an ECM (or pass an invalid value, like a string), is whenever your entry variable is already part of an element result set – for instance, whenever you're looping on the result of a craft.entries query:

{% for entry in craft.entries.section('posts') %}
    ...
    {% set next = entry.getNext() %}
    {% if next %}
        {{ next.title }}
    {% endif %}
{% endfor %}

As for the error message you're seeing:

The getNext() and getPrev() methods should always be wrapped in a conditional, because they won't realibly, always return an element (i.e., there might not be a "next" or "previous" entry in your current context):

{% set prev = entry.getNext(criteria) %}
{% set next = entry.getPrev(criteria) %}

{% if prev %}
    {{ prev.title }}
{% endif %}

{% if next %}
    {{ next.title }}
{% endif %}

The error message you're getting, is simply stating that there is no url attribute for one of your next or prev variables – meaning that those variables don't actually refer to valid elements, because the getNext() and/or getPrev() methods returned a NULL value. Simply wrap your code in conditionals, and the error will go away.

If you want to make sure that you're always displaying both a "next" and a "previous" link, you can make the links "loop" by having them point to the first and last entries respectively, whenever there isn't a next or previous entry in the set:

{% set criteria = craft.entries.section('posts') %}
...
{% set next = entry.getNext(criteria) ?? criteria.first() %}
{% set prev = entry.getPrev(criteria) ?? criteria.last() %}
...
{% if next %}
    {{ next.title }}
{% endif %}


General speed/performance on large Craft build

We are constantly seeing the deleting stale template cache timeout problem on our servers - try increasing the time PHP can execute for to something very long. It seems like clearing the caches counts as one PHP request and not a bunch of tasks, so they can time out.

Good use of cache tags helps, and caching globally can also help - but other than that all I've found to make complex Craft builds faster is using something like Varnish or nginx. Neither of which are simple and both of which I've avoided so far.

PHP7 will help a lot, but I'm not aware of any distro that has PHP7 available yet.


Setting up Craft's registration e-mails to be sent through GMail

I'm not sure how your email address got blocked, but Craft 3 uses the same SMTP smtp.gmail.com server and settings that Craft 2 uses when you choose to send email via "Gmail"

https://github.com/craftcms/cms/blob/develop/src/mail/transportadapters/Gmail.php#L91-L97

Sending email through PHPMail/sendmail is notoriously unreliable and I wouldn't recommend it on production.

https://craftcms.com/support/troubleshooting-email-errors#dealing-with-email-delivery-issues

And there are quite a few steps you can take to help ensure your email doesn't get treated as SPAM: https://blog.codinghorror.com/so-youd-like-to-send-some-email-through-code/


Developing in Teams - What is the best Craft setup?

The articles might be useful to you:

Database & Asset Syncing Between Environments in Craft CMS

Multi-Environment Config for Craft CMS


How can I reference images in a rich text field?

Sounds like you are coming from something like WordPress. In Craft there are asset fields where you can relate assets to your text. Together with matrix fields you can create a powerful layout rather than inserting everything into one huge wysiwyg.

If you really want to fetch images in html editors you'll need a plugin for that. It's not possible in Craft per default because it's not really the intended way


A Structure section with an entry to a channel index

I like what Matt P wrote in his answer:

try to consider how someone [else] will find the logic of the CMS design

The other factor you want to consider in information architecture is you only want store data once in the database. So how you intend to pull that data out also is going to influence your decision on how you store it.
The good news there is Craft really lets you pull data from virtually any place in the system very easily so it kind of comes down to an organizational choice. You have 2 options: Matrix or Entries.
Matrix Fields
You might consider a matrix field because these attach right on the entry itself. That way, a user edits the Leadership entry directly, they'll find the data there, in an intuive away. The other bonus is you can move the entries up and down in a certain order or turn them off right in the context of previewing the page.
Matrix is a good option if the data is more-or-less confined to that entry and you don't need to access the data anywhere else in the system.
Entries
If you need to relate content back to each other, or you find the leadership team data needs to exist in a context outside that particular page, it's probably the best option to bring them in as a channel (or structure).
Craft 2.5 made a huge change as to the way you can edit related entries right in the same entry. You might want to consider using an "entries" field that relates back to your Leadership channel and let the user pick exactly which team members you want to spit out on that page. The other benefit is in this way, you can open up  those "related" entries right from the Leadership entry, much like a Matrix block would—enhancing usability—but you still keep them as entries.
TL;DR
I don't know how many people are on the leadership team but if you have but more than a couple dozen, it might make sense to keep them as entries. Otherwise if you don't plan to use that data anywhere else in the system, a matrix field could be a nice option too.


How to log info from an onSaveEntry event?

After wasting all of Brad's time (sorry brad!) by sending him an incomplete plugin file with a missing line, I have discovered why I wasn't seeing logs in the console as expected.

Craft::log('...') or MyPlugin::log('...') function calls within onSaveEntry or onSaveUser events are in fact properly saved to the log files (craft/app/storage/runtime/logs/). They are just not available in the browser's console, because the event is taking place on the server, while the page is in the process of being redirected when the event fires.

Lesson learned: don't rely on the console for debugging!

The log files can be watched from the command line using tail -F /full/path/to/log/file rather than having to constantly reload the log in a text editor. Although apparently some text editors also support live updates as well.

Feel free to delete this question or leave it here in case others run into the same problem.


How can I display entry edit history on the front end?

Something like this might work.

{% if not craft.request.isAjax %}

    {% set versions = craft.entryRevisions.getVersionsByEntryId(entry.id, entry.locale) %}

    Versions:
    <select class="js-versions-dropdown">
        <option value="">Current</option>
        {% for versionEntry in versions %}
            <option value="{{ versionEntry.versionId }}">Version {{ loop.index }} ({{ versionEntry.postDate|date('m-d-Y') }} )</option>
        {% endfor %}
    </select>

{% endif %}

{% if craft.request.isAjax %}

    {% if craft.request.param('versionid') %}
        {% set entry = craft.entryRevisions.getVersionById(craft.request.param('versionid')) %}
    {% endif %}

{% endif %}

<div>
    {{ entry.title }}
    ...
</div>

In this example, you would want to listen for an onChange event on the dropdown list and reload the template via ajax, passing the 'versionid' as a post variable. Alternatively you could also just reload the whole page, in which case remove the 'if ajax' stuff. In this case, you'll probably also need to add some logic to the drop-down list so as to display the correct 'selected' option in the list.


Enforce search match multiple parameters

I think you're misunderstanding what with does. Or I am. Ha!

From what I understand with is for eager loading, but doesn't control anything in the relation itself. I don't think your relation makes any sense either because all you'll do is substitute a string into your spec variables.

Try something more like:

{% set products = craft.commerce.products({
    relatedTo: [
        'and',
        CONDITION1,
        CONDITION2
    ],
    with: [
        fieldYouWantToShow,
        otherFieldYouWantToShow,
    ],
    order: "title asc",
}) %}

And your conditionals should be something like:

{ targetElement: category },
{ sourceElement: craft.entries.section('reviews').status(null) }

The bottom example here is what you're needing: https://craftcms.com/docs/relations


Specify a field dynamically using section handle

I don't think your approach makes sense but you can use twigs Attribute function

{% for block in attribute(sidebar, entry.section.handle ~"Sidebar") %}


How do I query for all users that bought a license?

I don't think it's currently possible in as clean as manner as you'd like. I'd tackle the problem by writing a small plugin that queries the database and returns a list of user ids that match the criteria.

Remember, though, is that a license does not necessarily have a user id attached to it - a license must have either a user id or an email assigned to, so you might want to keep that in mind.


You can only do this with custom PHP otherwise this is going to be a high security risk. Imagine someone just changes your HTML and inserts a different group id: everyone could just join the group he/she likes.

Instead you can Enhancing a Craft CMS 3 Website with a Custom Module - there is already a default one and insert an event to do this by yourself but you need to be careful. I wouldn't trust user input in that case too much.

Event::on(
    Elements::class,
    Elements::EVENT_AFTER_SAVE_ELEMENT,
    function(ElementEvent $event){
        if(\get_class($event->element) === User::class){
            $joinSpecialGroup = (bool)Craft::$app->getRequest()->getBodyParam('joinSpecialGroup');
            if($joinSpecialGroup === true){
                Craft::$app->getUsers()->assignUserToGroups($event->element->id, [4]);
            }
        }
    }
);

Note: I woulnd't call the property joinSpecialGroup - it is just for demonstration


How to host a huge website on Craft (10k pages, over a dozen languages, 2GB database)

"Digital Ocean through Forge" is a good solution. Sounds like you're on a well-powered droplet as well.

I'd recommend moving your assets into the cloud to speed things up a bit. Something like Amazon S3 with CloudFront.

Honestly, the biggest drag is probably the use of multiple locales. Craft is making duplicates of pretty much all of the content in your database, whether you need it or not. It's also contributing to the massive size of your database.

Anecdotally... I recently removed 11 of 12 languages in a Craft 2 site (leaving only a single locale), and it reduced the size of the database by close to 90%. It made the transition to Craft 3 much, much easier.

Lastly, I'd recommend asking this question in the #devops channel on Discord. Lots of smart folks in that channel who would be able to give you even better advice than I can.


Why would I get a "CHttpRequest is unable to determine the request URI" when creating a migration?

That's a bug in our RedactorClips plugin, actually.  Just fixed it, so if you grab the latest from here (https://github.com/pixelandtonic/RedactorClips), yiic still should run fine.


When you are working with an asset field you are actually looking at the object so you need to call {{asset.url}} in order to actually output the path to the image or whatever asset you are working with.

{% for asset in entry.projectBanner %}

    <img src="{{asset.url}}>

{% endfor %}

As some additional information I would checkout eager-loading in craft as it can drastically help performance as your website grows!

https://craftcms.com/docs/templating/eager-loading-elements


Possible to Get grunt-uncss Working with Craft?

So to close the loop on this one, I actually ended up using a different grunt tool that essentially accomplishes the same goal called purifycss. I was able to target purifycss at the craft template folder, get it to look at bootstrap css selectors actually in use in the templates, compare it to the full bootstrap css files, and then have it output only the css that was being utilized in a final minified css file.

It ended up being that I was only using about half of the available bootstrap css selectors so it cut a bunch of unused css out of a very large file.

Also, I believe I could have taken the same or similar approach with uncss so if you prefer that tool, I believe you can use it in the same way (though I did not personally so can't speak in detail to it).

Here is the excerpt from my gruntfile.js:

purifycss: {
  options: {
    minify: true,
  },
  target: {
      src: ['./craft/templates/*.{html,twig}','./craft/templates/**/*.{html,twig}','./craft/templates/**/**/*.{html,twig}','./craft/templates/**/**/**/.{html,twig}'],
      css: ['./public/lib/css/dev/vendor/_bootstrap-theme.min.scss','./public/lib/css/dev/vendor/_bootstrap.min.scss'],
      dest: './public/lib/css/dev/vendor/_bootstrap-purified.min.scss'
  }
},


How to configure the system messages  url?

This issue was discussed a while ago here: https://github.com/craftcms/cms/issues/3029
As Brandon says, Craft basically has no knowledge of which site a user belongs to as they're all global.
Bear in mind that emails that are triggered from the front end will use the domain name where they were triggered from - this problem only really affects emails triggered from the control panel.
The workaround discussed at the bottom there is probably your best bet: use Twig's replace filter to dynamically replace the domain name in the link variable according to what you know about the user (in your case, their preferred language).
{% set link = user.preferredLanguage == 'en' ? link|replace('https://www.site.de','https://www.site.com') : link %}


CP search for entries where a specific field is empty

We use Zenbu for this exact thing. As we're importing a lot of data, we need to find which entries are missing data - https://zenbustudio.com/software/zenbu-craftcms


Send Emails to dynamic list of recipients

There are two things to consider here:

How to approach sending to a list
How to approach populating a notification with dynamic information

Sending email to a list of users

Sprout Email notifications use the default Craft email service. Each notification is sent to a single individual. To send to a list, what you'll need to do behind the scenes is loop through all the people in that list and send them each an email one by one.

Sending notifications with dynamic information

While Sprout Email uses the default email sending behavior in Craft, to send notifications programmatically you'll want to use the sendNotifcation method:

craft()->sproutEmail_defaultMailer->sendNotification($campaign, $object);

The $campaign variable should be an instance of a SproutEmail_CampaignModel and can be created by retrieving the Notification you want to send by it's ID like so:

craft()->sproutEmail_notifications->getNotificationById($id);

The $object is the data that will be processed in your template and any fields that accept dynamic variables such as the Subject, From Name, From Email, Reply To, and Recipients fields.

In your situation, it sounds like you are sending User-specific notifications and your template might be expecting a UserModel for any dynamic variables.

A very rough starting point for how to approach the sending could be as follows:

// Get all your users first

foreach ($users as $user)
{
    // Get your Campaign (SproutEmail_CampaignModel)
    $campaign = craft()->sproutEmail_notifications->getNotificationById($campaignId);

    // Get your User (UserModel)
    // This step is only needed if $user is not already a UserModel
    $user = craft()->users->getUserById($userId);

    // Send your Notification
    craft()->sproutEmail_defaultMailer->sendNotification($campaign, $user);
}


Password should fail on front-end registration form

Registration form errors only display for password when logged out. If you're logged in as admin they won't display.


In your plugin's composer.json, add the service to extra.components to make it available on the plugin instance. You should see the predefined service already listed there.

You might need to empty the vendor folder of your craft website and reinstall your composer dependencies as Craft appears to cache this information.


It is probably to do with your connection. I have the same problem here, and I had to use something that can resume downloads to get the complete zip.

For example Chrono Download Manager addon for Chrome might work for that.


Get a specific product with Element API, Commerce and Craft 2

If you want to get a specific product and it's variants by the productId you could simply do:

'api/product/<productId>' => function( $productId ) {
    return [
        'elementType' => Product::class,
        'criteria'    => [
            'id' => $productId
        ],
        'pretty'      => true,
        'transformer' => function( Product $product ) {
            foreach ( $product->getVariants() as $variant ) {
                $variants = [
                    'title'         => $variant->title,
                    'description'   => $variant->description,
                    'productId'     => (int) $variant->productId,
                    'purchasableId' => (int) $variant->purchasableId,
                    'status'        => $variant->status,
                    'type'          => $product->type->name,
                    'url'           => $product->url,
                ];
            }

            return $variants;
        },
    ];
},

you are able to get the product then via yourshop.domain/product/1234


Nested objects containing array in the Elements API plugin

Seems a bit unnecessary to cast it to an object.  This should work identically:

'transformer' => function(EntryModel $entry) {

    // Create an array of all the photo URLs
    $categories = [];

    foreach ($entry->categories as $category) {
        $categories[] = ['id' => $category->id, 'title' => $category->title];
    }

    return [
        'title' => $entry->title,
        'id' => $entry->id,
        'categories' => $categories
    ];
},