Error With ContactForm Plugin - Internal Server Error

Craft's email SMTP settings are configured under Settings->Email in the control panel.

The error message you're getting:

2015/12/03 19:21:27 [error] [exception.phpmailerException] exception 'phpmailerException' with message 'SMTP connect() failed.

Simply means that PHP/Craft can't connect (for whatever reason) to the server you specified with whatever SMTP settings you've entered in Settings->Email.

Chances are the credentials are invalid or the settings are incorrect, but it can also happen is something (firewall, router, etc.) is blocking output SMTP access as well.


You can provide a link to download a PDF version of the invoice.

Set the path to your invoice template in the Commerce General Settings.

Then to provide a frontend link to download the PDF use {{ order.getPdfUrl() }}


HttpRequestService's getPost is what you're looking for:

$value = craft()->request->getPost('dataName');


One way to do it would be to use the Control Panel CSS plugin and hide the button with CSS. But I guess that would hide it for all users, including admins.
Maybe you could write a little plugin for it that checks who logs into the CP and hide it if it's a certain user(group).


500 error: uploading files (duplicate primary key)

Okay - have managed to resolve this. Needed to reset the auto increment value in the craft_elements to greater than the max(id) for the craft_assetfiles - not sure how those got out of synch but that seems to have resolved it. Hallelujah!


403 Error on homepage of second language

Did you define the the locale url in your config?

I do it like this:

.env

SITE_URL_DE="@web"
SITE_URL_EN="@web/en"
SITE_URL_FR="@web/fr"
SITE_URL_IT="@web/it"

general.php

// Global settings
  '*' => [
    'siteUrl' => [
        'siteDe' => getenv('SITE_URL_DE'),
        'siteFr' => getenv('SITE_URL_FR'),
        'gsiteEn' => getenv('SITE_URL_EN'),
        'siteIt' => getenv('SITE_URL_IT'),
    ],
  ],

Then you can use those as your base URL's:


PHP mbstring extension isn't enabled? (WampServer)

As these things go, after I posted my question, I clicked "Refresh" in the Wamp menu and now my site works. I'm not sure what changed, especially since I already restarted the entire program several times, but all's well that ends well.

Configuration after refreshing:


Does Craft have any default keys for flash messages?

Not particularly.

UserSessionService has setNotice() and setErrors(), which are just wrappers for Yii's setFlash() where we pass in an 'error' or 'notice' for the key.

Yii will take than and prepend the FLASH_KEY_PREFIX const which we set to Craft.UserSessionService.flash..

So an error's key will end up being Craft.UserSessionService.flash.error and a notice will be Craft.UserSessionService.flash.notice.


$this->renderTemplate() breaks the CP navigation

Alright! I've been able to fix my problem. I did a couple of things wrong so I'm writing this for whoever makes the same mistakes I made and is now trapped in an endless loop of despair and impending doom.
First mistake!
You should leave the action attribute of your form element empty.
Call you action by using a hidden input, like this
<input type="hidden" name="action" value="/import-products/product/create">

This will automatically keep the user on your page, so there's no need to redirect in the controller and break the CP while doing it.
Second mistake!
I shouldn't have used $this->renderTemplate() at the end of my controller. It's not the preferred flow of doing it. After your controller did everything it needed to do, you should either stay on the page and display feedback or redirect to another page.
Staying on the page to display feedback can be done by sending variables back to the template. That's done like so:
Craft::$app->getUrlManager()->setRouteParams([
        'variable' => $myVariable
]);

return null;

If you want to redirect to a confirm-page. You should use the redirectToPostedUrl.
To be able to use this, you need a hidden input field with a url as value. Luckily Craft has a Twig function to do so.
{{ redirectInput(url|hash) }}

The URL needs to be hashed otherwise craft will throw an Invalid Body Parameter error. In your controller you can end your action with:
//You should wrap this in an if that checks if there are no errors
return $this->redirectToPostedUrl($variable);


Feed Me Cron Job failing on 123-reg hosting

Ok after a bit of digging. It turns out I was able to run this with wget. But had to comment out the &'s as these were being read as commands in cron. Also worth noting you would need to do the same with %'s as well.
So the final solution is:
wget -q -O - https://domain/index.php?p=actions/feed-me/feeds/run-task\&direct=1\&feedId=1\&passkey=xxxxxxxxxx >/dev/null 2>&1

Hope this helps anyone else with a similar issue.


Sprout Forms: Populate checkbox field options with entry data

The best way to debug a form field using custom HTML is to output the field you want via the default displayForm tag and copy the code from there as a starting point:

{# Output your checkboxes field here and look at the code generated #}
{{ craft.sproutForms.displayForm('yourFormWithACheckbox') }}

Test with the default code that is output as your custom HTML and if that works, adjust from there.

In general, we recommend using custom HTML with caution as it can increase the complexity of the code on the front-end a great deal.


How to update from a very old version of Craft?

Ok, after a lot of trial and error I've finally managed to get this site upgraded. Here's a rough outline of the process and what the problem turned out to be:

First, I tried updating one minor version at a time. This led me to find that the problem seemed to be with updating from the last build of 2.4 to the first build of 2.5
The error message on update wasn't super helpful ("There was a problem updating your database"), but by trawling through Craft's log file (craft/storage/runtime/logs/craft.log) I found that the update seemed to be failing when trying to create the table elementindexsettings because (for whatever reason) that table already existed (resulting in the error Failed to apply migration: m150827_000000_element_index_settings).
I can't think why this would be the case, since after each failed update attempt I fully restored my previous database, but since my elementindexsettings table was empty, I dropped it and tried the update again. At this point it worked.

So in summary, the solution was:

Update to Craft 2.4.2726 (and commit this to version control!)
Attempt a manual update to Craft 2.5.2750. When this fails, drop the elementindexsettings table and try running the update again (ie. go to /admin and press the "Finish up" button.
Update to the latest version.

As a side note, I found setting Craft's backupDbOnUpdate config setting to false made the update process much faster and less painful when having to do a lot of attempted updates followed by rollbacks (though obviously if doing this be careful to make sure you have a backup you can restore if the process goes wrong).


Difference between chained and batch element queries?

general

The first way creates an object of type EntryQuery, you then call the 2 functions section and limit

In PHP you would do the following:

$query = Entry::find()->section('news')->limit(10);

The second creates an array section => 'news', 'limit' => 10 you then call Yii2::configure($query, $array) with your EntryQuery which does:

public static function configure($object, $properties)
{
    foreach ($properties as $name => $value) {
        $object->$name = $value;
    }

    return $object;
}

Thus you don't call functions but define the properties directly. In PHP it would look like

$query = Entry::find();
Craft::configure($query, ['section' => 'news', 'limit' => 10]);

Performance

Because of the above it's important what you do. The first way calls functions the second way calls properties.

As for your comparison the first way is a little bit faster because you didn't attach functions that requires the use of magic methods => __call (in the ElementQueryBehavior) as soon as you search/filter for custom fields the Craft::configure way will always be a little bit faster because it can set the values directly instead of using the resource heavy __call function

For example:

// faster
$query = Entry::find()
    ->section('news')
    ->limit(10)

// slower
$query = Entry::find();
Craft::configure($query, [
    'section' => 'news',
    'limit' => 10
]);

Against

// slower
$query = Entry::find()
    ->section('news')
    ->limit(10)
    ->multiselect('test')
    ->subline('foo');

// faster
$query = Entry::find();
Craft::configure($query, [
    'section' => 'news',
    'limit' => 10,
    'multiselect' => 'test',
    'subline' => 'foo'
]);

Conclusion

Keep in mind when I say "slower" or "faster" I'm talking about a few milliseconds (when I run the last example 1000 times its 511ms vs 497ms) so in the end it does not really matter. If it's really important in terms of speed: as soon as you use the __call method because you need to change properties in the ElementQueryBehavior you would prefer to use Craft::configure.

Besides that: there is absolutely no difference between those two.. There are no hidden "benefits" you don't have more options, you can't do something "better"


Sending an e-mail to current user in FeedMe hook

As long as you have control of the CSV on upload, you could change its name to filename_test@test.test.csv (or some other properly escaped filename with the current user's email address in it). Then get the filename from the feed (must be in there somewhere) and extract the email address.

Bit of a workaround, but if it works, it works.


What’s the recommended way to set the site URL?

As of Craft 2, you should be using the new siteUrl config setting.

There are two advantages to setting your site URL using this config setting.

First, The value can be set on a per-locale basis, in a way where Craft is actually aware of all locales’ URLs on every request (unlike the CRAFT_SITE_URL constant, where Craft only knows the current locale’s URL). That’s a good thing because it means you can easily link to entries’ URLs across different locales, for example.

return array(

    'siteUrl' => array(
        'en_us' => 'http://example.com/',
        'de'    => 'http://example.com/de/',
    ),

    // ...

);

Its value can also be set directly on a per-environment basis. (Yes you can achieve this using the environmentVariables config setting combined with a {siteUrl} tag inside the Site URL setting within the CP’s general settings, but that’s much less direct/obvious.)

return array(

    '.dev' => array(
        'siteUrl' => 'http://example.dev/',
        // ...
    ),

    '.com' => array(
        'siteUrl' => 'http://example.com/',
        // ...
    ),

    // ...
);

Those of course can be combined as well:

return array(

    '.dev' => array(
        'siteUrl' => array(
            'en_us' => 'http://example.dev/',
            'de'    => 'http://example.dev/de/',
        ),
        // ...
    ),

    '.com' => array(
        'siteUrl' => array(
            'en_us' => 'http://example.com/',
            'de'    => 'http://example.com/de/',
        ),
        // ...
    ),

    // ...

);


Do you mean to have it just assign them one after the other? If so, then you can just use Twig’s cycle function.

{% set themes = [
    'yellow',
    'red',
    'teal',
    'blue'
] %}

{% for region in regions %}
 {{ region.title }}
{% endfor %}


Admin resources are accessible without being logged in

In Craft 2, this is expected behavior.

In Craft 3, we "fixed" it by using an Asset's UID instead of its ID, which makes it harder to guess.


Here's what I came up with: https://gist.github.com/timkelty/8de8531df688b6ac08d2da0713b6ff00

This allows you to pass everything through request params, including specifying the transformer class.

Right now it looks for the transformer in the elementapi folder: plugins/elementapi/ElementApi_MyCustomThingTransformer.php

If a full-fledged CRUD API is baked into 3.0, I'm assuming this will be irrelevant by then.


Can I disable logging 404 errors in my craft.log file?

Not currently, but I agree it's kind of annoying.

I thought maybe you could pull it off with a plugin since Yii does have an onException event, but there wouldn't be a way to disable logging of 404's without some code changes on our end.

I've added it to our 3.0 list to add a config setting to disable logging of 404's though.


How can I add Google MarkerClusterer library to Smart Map?

UPDATE
It looks like the underlying MarkerClusterer library has been moved (and theoretically improved).
The new library can be found here...

https://github.com/googlemaps/js-markerclustererplus

Not sure how much that affects the original JavaScript example below, but it's probably still a reasonable starting point.

ORIGINAL
As Jalen mentioned in his answer, this functionality isn't (currently) built into Smart Map. However, it's very easy to add yourself...
First, you'll need to add the MarkerClusterer library to your map page. You can link to it normally, just as you would with any other JS library.
Once you've got the library installed, you'll be able to cluster your markers with code as simple as this:
var map = smartMap.map['smartmap-mapcanvas-1'];
var markers = smartMap.marker;

var markerCluster = new MarkerClusterer(map, markers);

Pretty much everything else happens automagically!


Uploading assets to different locations based on environment

AFAIK, you can't change the type of your volume based on your environment. But if having a separate S3 account/bucket for dev could work for you, you can configure this with a volume.php config file. Check out this section in the docs about configuration for the gist on how to use it, and the section about per environment configuration in the readme for the AWS-S3 plugin for the specifics for that type of volume.


Your code returns an TagModel and saves it as "tag". You can now get all model properties like this:

{{ tag.property_name }}

In your case it would look like this:

{% if tag.name == 'Flower' %}
    Do stuff
{% endif %}


Get current date / time in specific timezone?

{{ now|date("H:i", "Europe/Paris") }}

As per: http://twig.sensiolabs.org/doc/filters/date.html


There’s no way to give a user group permission to create entries but not see those entries they created in the CP.

The only way to achieve what you want would be to write a plugin that provides its own “save-entry” controller action, which allows users to create the entries without actually having the permission. The Guest Entries plugin would be a good starting point - it has a GuestEntriesController with an actionSaveEntry() method that behaves very similar to Craft’s built-in EntriesController::actionSaveEntry(), but it skips the normal permission-based authorization logic.

In your case you might still want some level of authorization. For example, you can verify that there’s a currently logged-in user, and that they belong to a certain group. If that’s the case you’ll want to not add this line:

protected $allowAnonymous = true;

And at the top of your actionSaveEntry() method, add this:

$user = craft()->userSession->getUser();

if (!$user->isInGroup('authors'))
{
    throw new HttpException(403, Craft::t('This action may only be performed by authors.'));
}


First, when you attach event listeners using craft.on, the naming convention for the event name is assets.beforeSaveEntry, not assets.onBeforeSaveEntry (i.e., skip the on part). Both names appear to work, but the former is the one used in the docs and I'd recommend using that.

Second, the reason why your upload "gets stuck" is your call to craft()->assets->storeFile inside the event listener. Basically, that call results in a loop, because craft->assets->storeFile() will fire another beforeSaveAsset event – making your script execute continually before timing out.

As for actually changing the filename on upload; unfortunately, if there's a reliable way to change the asset filename before the asset is saved, I haven't been able to find it.

However, if you can work with the assets.saveAsset event (which is fired after the asset is uploaded and saved on the server), I found a way:

First, set up an event listener for assets.saveAsset. Inside the event listener, you need to check the $event object's isNewAsset property; making sure the filename is only changed the first time the asset is saved and preventing the loop mentioned above.

Concerning the actual filename, there's a couple of issues to consider. For one, the filename needs to be unique (to that particular folder, as least). If you attempt to store an asset with an existing filename, Craft will use the original filename for your upload (I'd expect Craft to either ask if you wanted to replace the existing file, or suffix the filename with a number, but that doesn't appear to be the case). Secondly, the filename needs to include the file's extension (i.e. jpg or pdf). And finally; because this code runs after the asset has been saved and the file is already stored on the server, it isn't enough to set the filename attribute to the AssetFileModel object (i.e. $asset), you'll also need to rename the actual file.

Keeping these issues in mind, here's a working example:

craft()->on('assets.saveAsset', function (Event $event) {

    if ($event->params['isNewAsset']) {

        $asset = $event->params['asset'];

        // Set the filename to a variable, appending the file extension
        $filename = 'filename-'.md5(time()).'.'.$asset->getExtension();

        // Rename the file on the server
        craft()->assets->renameFile($asset, $filename);

        // Set filename attribute and re-save asset
        $asset->setAttribute('filename', $filename);
        craft()->assets->storeFile($asset);

    }
});

Note that in the above example, I'm hashing the current timestamp and adding it to the filename as an easy fix to ensure that it's unique. I don't know how you want your filenames to look or if duplicate filenames would even be an issue in your case, but you could of course implement a solution that tests for duplicate filenames and/or generates unique filenames in a different manner.

To be honest, although the above should work I do feel this solution is a bit convoluted and I wouldn't be surprised if there's a better way – if there is, hopefully you'll have another answer.


Twig search function doesn't work after upgrading to Craft 3

The search parameter relies on the internal search index (whereas your other approach does not).
It's possible that something got tripped up during a migration to Craft 3, perhaps when the new drafts & revisions system was introduced.
Try rebuilding your search index. It might take a long time to run, but should hopefully solve your problem.


It sounds like you're attempting to access the getDeveloper method on your plugin's main service class, but the class doesn't exist.

You have two options:

Create the service class, and implement a getDeveloper method.
Call the getDeveloper method on your main plugin class (which I suspect is what you're really trying to do).

Option One: Service

Your minimal service class will look like this:

<?php

namespace Craft;

class CrmPortalService extends BaseApplicationComponent
{
    /**
     * Returns the developer name.
     *
     * You could either hard-code the developer name, or you could
     * retrieve it from the main plugin class, as described in
     * option two.
     *
     * @return string
     */
    public function getDeveloper()
    {
        return 'John Doe';
    }
}

Option Two: Plugin

Craft uses Services to expose functionality, in exactly the same way that plugins do. If you're trying to figure out how to do something, just look for a Craft Service with a similar name.

In this case, you want to retrieve your main plugin file, so the PluginsService is a good place to start. We're in luck, it has a getPlugin method, which accepts a plugin handle, and returns the plugin class.

Here's how you might use that, to call the getDeveloper method in your main plugin class.

craft()->plugins->getPlugin('crmPortal')->getDeveloper();


At the moment, both are not possible. The order is locked from recalculation when the order is marked as completed - the final price being locked in.

In a future release we will introduce the concept of order editing after order completion.

Right now, you could manually insert an adjustment row into the database, along with the changes to the order's order.baseShippingCost but you would need to make sure the order.totalPrice and other calculated fields would also be updated in the database to make the order internally consistent.


Element API Fetch Entries URL Within Matrix

That's because you don't actually fetch the entry. In order to receive the entry you have to execute your ElementCriteriaModel with first() or find() otherwise Craft tries to json encode a query

 $block->subPageDirect->first()

You should read the docs about relations and the Element Criteria Model

Btw stack exchange has a wonderful syntax highlighting please add your code directly the next time and not in a screenshot

Edit:

function panelsMatrix($array) {
    $panelBlocks = [];
    foreach ($array as $block) {
        switch ($block->type->handle) {
            case 'panel':
                $relatedEntries =  $block->subPageDirect->first();
                $attributes = $relatedEntries? $relatedEntries->getAttributes() : [];

                $panelBlocks[] = [
                    'heading' => (string) $block->heading,
                    'text' => (string) $block->text,
                    'image' => $block->image[0]->url,
                    'imagePosition' => $block->imagePosition,
                    'textBaseColour' => $block->textBaseColour,
                    'textHorizontalAlignment' => $block->textHorizontalAlignment,
                    'textVerticalAlignment' => $block->textVerticalAlignment,
                    'imageOffsetX' =>$block->imageOffsetX,
                    'imageOffsetY' =>$block->imageOffsetY,
                    'backgroundColour' => $block->backgroundColour,
                    'subPageDirect' => $attributes
                ];
            break;
        }
    }
    return $panelBlocks;
}


'Create a new entry' CP is blank if matrix field exists

Solution: Do it as in craft instructions asked 'PHP 5.3.0 or later with safe mode disabled' and all works perfect like a charm.

This problem came from settings in Mamp Pro. The debugger was active. And all other 'what to log' too. After uncheck - no problem any more.


How to use better loop for my product images

One way to do this is to query for the images once, and sort them into two different arrays. This uses twig's merge filter, which is the way to add things to an array in twig.

{% set mainImages = [] %}
{% set otherImages = [] %}

{% for image in product.productImages %}
  {% if image.productMainImage %}
    {% set mainImages = mainImages | merge([image]) %}
  {% else %}
    {% set otherImages = otherImages | merge([image]) %}
  {% endif %}
{% endfor %}

Then you can loop over the mainImages array to get the images with the lightswitch on, and the otherImages array to get the other images.

You will have three for loops, but only one database query.


The simplest way to transform dynamic routes into advanced routes, is to go to your craft_routes table and copy it out of urlPattern:

Example:

If you have set this in your backend:
news-sort/month/<year>/<month>

You'll find this in urlPattern:
news\-sort\/month\/(?P<year>\d{4})\/(?P<month>(?:0?[1-9]|1[012]))

Just remove the escaping \, and you've got your regex:
news-sort/month/(?P<year>\d{4})/(?P<month>(?:0?[1-9]|1[012]))


Adding second user to user field in plugin brings server to its knees

You've created an endless loop with calling saveEntry within the entries.saveEntry event listener. You can fix it with implementing a static variable.

craft()->on('entries.saveEntry', function(Event $event) {
    static $recursionLevel = 0;

    if ($recursionLevel == 0) {
        $recursionLevel++;

        // `saveEntry` in `addAnotherUserToNotify` triggers another
        // `entries.saveEntry` event
    }
});


How can I get custom user registration field parameters

From the onSaveUser event docs, there are two parameters that are passed to everyone listening.  One is isNewUser, which you're accessing correctly: $event->params['isNewUser'].  But the other is user, which is a full-blown UserModel object that you can access the properties of.

But onSaveUser isn't the event you want, since you want to make changes to the user before they've been saved.  You want onBeforeSaveUser, which has the exact same parameters.

Having said that, names are tricky things around the globe.  I highly recommend reading this article on falsehoods that programmers believe about names.

Here is some code that should work for the most basic use cases.

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

    // Only do this for new users.
    if ($event->params['isNewUser'])
    {
        $fullName = craft()->request->getPost('fields.fullName');

        // Make sure this isn't a user being saved from the control panel.
        if ($fullName)
        {
            $name = explode(' ', $fullName);

            // No spaces, it could be Madonna or Cher.
            if (count($name) == 1)
            {
                $firstName = $name[0];
                $lastName = '';
            }
            // It's a "normal" first and last name.
            else if ($count($name) == 2)
            {
                $firstName = $name[0];
                $lastName = $name[1];
            }
            else
            {
                // The first element is the first name. Combine the rest into a last name separated by spaces.
                $firstName = array_pop($name);
                $lastName = implode(' ', $name);
            }

            // Grab the user.
            $user = $event->params['user'];

            $user->firstName = $firstName;
            $user->lastName = $lastName;
        }
    }
}

Note that UserModel already has a getFullName method that does some basic logic combining the firstName and lastName properties.


Loading an existing entries drafts in template/frontend

After doing some digging around I found the getDraftsByEntryId(entryId, locale) method of the craft.entryRevisions service that might help.

The following should return the first draft of an entry. Note: there is a second argument for 'locale', which defaults to current locale if none provided. Also not sure whether 'first' or 'last' would be considered the most recent draft.

{% set drafts = craft.entryRevisions.getDraftsByEntryId(entry.id) %}
{% if drafts|length %}
    {% set draft = drafts[0] %}
    {{ draft.title }}
    ...
{% endif %}

You will need to load the entry manually (i.e. through a custom route of some kind) as the draft's entry is likely to be 'disabled' (although not necessarily) and thus not load through the entry's default url. Something like '/mysection/edit/slug' perhaps (where 'slug' is a custom route token).

{% set entry = craft.entries({
    section: 'mysection',
    slug: slug
    status: null
}).first() %}


You first need to query for the “airport” entry by using the first() method. $airport->myEntriedFieldHandle then returns an ElementCriteriaModel prepared to get all the entries selected in the Entries field.

$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section = 'airports';
$criteria->airportcode = 'BCN';
$airport = $criteria->first();

if ($airport) {
    $criteria = $airport->prefHotels;
    $airportPrefHotels = $criteria->find();

    if ($airportPrefHotels) {
        // do useful things with $airportPrefHotels
    }
}


Answered at https://craftcms.stackexchange.com/a/22468/7356

"Product Types are really for the content of the fields and field layout of each product plus basic options for things like tax/shipping category defaults.

For full categorization in menus and site structure, we recommend putting a category field on all products."


You can search any of your fields using the syntax "fieldHandle: search term".

See http://buildwithcraft.com/docs/searching for more info.


How to render a state abbreviation in Craft Commerce?

I received an answer on Slack from Stephen Callendar.

{% set addresses = craft.commerce.customer.addresses %}
{% for address in addresses %}
  {% if address.getState() %}
    {{ address.getState().abbreviation }}
  {% endif %}
{% endfor %}


Display matrix block which share the same date field value

I think what you're saying is that you only want to output the heading once it's different from the previous heading. So if you have two blocks with the same week, we only show it once.

You can set a variable of week and check that the current block's week (which I've set as tempWeek to keep code cleaner) is the same. If it isn't the same, it means we've changed week so display the title and then set week to be this new week.

{% set week = "" %}
{% for block in entry.timeSheet %}
    {% set tempWeek = block.week|date('j M Y') %}
    {% if tempWeek!=week %}
        W/C: {{ block.week|date('j M Y') }}

        {% set week = tempWeek %}
    {% endif %}
    {% if block.totalTime | length %}
        {{ block.totalTime }}

    {% endif %}
    {{ not loop.last ? '
' }}
{% endfor %}


How can I access the raw profile photo for any given user?

As you've discovered, you can get the full cropped version of the image with author.getPhotoUrl('original'), but Craft doesn't keep a copy of the original un-cropped version of the image around.

And Lindsey is more than 60% correct... user photos are 1st class Asset citizens in Craft 3, making this less awkward.


Can I set a JS variable to a Twig output tag?

In your first example, you are outputting an ElementCriteriaModel. That is a query for tags rather than the tags themselves. It doesn't output anything usable by JS You're almost doing the same in the second example, except that your reference to gameTags in the JS is just referencing itself rather than any Twig output.

What you want to do is to query the tags and output in the way that JS can use. Something like this:

<script type="text/javascript">
    var gameTags = [{% for tag in craft.tags.group('gameTags') %}"{{ tag.title }}",{%endfor %}];
</script>

That should output a JS array of strings with each string being a tag. Something like below.

<script type="text/javascript">
    var gameTags = ["action","adventure","platform","rpg","sports",];
</script>

If you're a stickler for commas in arrays, there's ways to not output that after the last tag.


I'm guessing that the path is not accurate.

If you're 100% sure that the path is correct, then check your file permissions. Small chance the permissions are locked down too tight.


How can I upload separate 1X and 2X images?

You can do that like so:

Create a new Assets field called “Hi-Res Image” (handle “hiResImage”) with the following settings:

Restrict uploads to a single folder: [ √ ]
Upload Location:

[same source you’re uploading 1X images to]
{folder.path}_2x/

Restrict allowed file types:

[ √ ]
[Images]

Target Locale: [Same as source]
Limit: 1

Go to Settings > Assets > [your source] > Fields tab, and add your new Hi-Res Image field to the layout.

With that set up, after you select 1X images in your main Assets field, you will be able to double-click on them and see your “Hi-Res Image” Assets field in their metadata modals. You can drag your 2X image into that, and it will automatically get saved into a _2x/ subfolder wherever its parent image lives.

From your templates, you can then output <img> tags that point to both images:

{% for image in entry.myAssetsField %}
    {% set hiResImage = image.hiResImage.first() %}

    <img srcset="{{ image.url }}
        {%- if hiResImage %}, {{ hiResImage.url }} 2x{% endif %}">
{% endfor %}


Can custom entry sources have their own URLs?

After a little more digging, I discovered this can be achieved by adding a data array with a handle value to the source, so that code becomes:

public function modifyEntrySources(&$sources, $context)
{
    if ($context == 'index')
    {
        $sources[] = array('heading' => 'Translations');

        $sources['translations:untranslated'] = array(
            'label'    => Craft::t('Untranslated'),
            'criteria' => array('translationCompleted' => array('0', null)),
            'data'     => array('handle' => 'untranslated'),
        );

        $sources['translations:translated'] = array(
            'label'    => Craft::t('Translated'),
            'criteria' => array('translationCompleted' => '1'),
            'data'     => array('handle' => 'translated'),
        );
    }
}

This doesn't appear to work for nested sources however.


This happens because you set the parameter on the ElementCriteriaModel to get entries with that specific datetime. If you omit a time when you compose a datetime with strings, you'll still get a time (00:00:00) and even a timezone set on it:

{% set myDatetime = '2014-08-12' %}

{# Print the datetime in ISO 8601 format / 2014-08-12T00:00:00+02:00 #}
{{ myDatetime|date('c') }}

This is how you set the parameter to accept datetime ranges:

{% set myDatetime = thisyear ~ '-' ~ thismonth ~ '-' ~ day %}
{% set entries = craft.entries.postDate('and', '>= ' ~ myDatetime, '< ' ~ myDatetime|date_modify('+1 day')) %}


Unexpected token "end of template" of value "" ("end of statement block" expected)

It looks like their "_head" template is missing the closing {% endblock %} at the end.


$request->send fails on one server but not the other

The problem was the service that was supposed to return the JSON feed was not returning anything. Meaning our server was simply waiting for a response that never arrived and eventually timing out a minute later.

I only discovered this by writing my own script to test for a response from two different servers, discovering the IP address of the server experiencing the problem was being blocked from accessing the JSON feed.

Please, if you're supplying data and decide to block someone's IP, at least tell them you're doing so. An error response would have saved me a lot of work.


It’s likely possible but would be tricky, since Craft has much more flexible content modeling features than WP. It would be a “lossy” conversion process, similar to converting a WAV file to a low bitrate MP3.

The best way to get content out of Craft is probably to use the Element API plugin. I couldn’t tell you how to get that content into WP though – you may have better luck asking about that on https://wordpress.stackexchange.com/.

Before you go down this road, it’s probably worth spending just a bit of time learning Craft CMS. You never know, you might just end up liking it! Here are a few recent articles that compare the two:

Roller Agency: Why we are moving to Craft CMS
Trajectory: Craft vs Wordpress: The Definitive Guide
OneSignal: Lessons Learned Building Our Website With Craft CMS
Honcho Agency: Why We're Craft CMS Developers

If interested, I highly recommend you check out CraftQuest’s Up and Running with Craft 3 course, which is free.


I don't think it's currently possible.  There are several places where we're explicitly checking for the plugin's handle as a folder directly underneath whatever craft()->path->getPluginsPath() is returning.


Showing specific category content as well as ALL

It sounds like you're pretty close. I'll work off of the assumption that you want the URLs to be structured like this:

/images

/lifestyle

/food

…and an individual image will be at /images/{image slug}.

Like you've done, I'd create a category group called photoGalleries. I'd set the URL format simple to /{slug} and a max level of 1. The two categories can then be added to that.

The images channel would have a URL format of /images/{slug}.

By setting up categories and the channel like this, Craft will automatically create variables when it matches those paths. You can then use these variables to do practical things.

To show images by category, you'll need to use to .relatedTo() method. When Craft matches a category route, it will create a category variable which can be passed into this method. In the template for a category, you'll need code like this:

{% set images = craft.entries.section('images').relatedTo(category).find() %}
{% for image in images %}

{% endfor %}

This asks Craft to find any image which has been categorised by (related to) a specific category.

You can then create a simple images listing via a template for /images. If you wanted to get really fancy, you could output what categories an image is under. To do that you'd need code like this.

{% for image in craft.entries.images.find() %}

    {% for category in craft.categories.relatedTo(image).find() %}

{{ category }}

    {% endfor %}

{% endfor %}

Hope that gets you going.


Is there a way to know if a discount is going to be applied on a product?

Discounts can only be determined if the item is added to the cart. This is what separates a discount from a sale.

A discount is actually not matched with the product but the line item as it sits on the order (with all of its context like the order's customer, etc)

You can determine if something is on sale with variant.onSale returning true or false.


I have solved it by myself.

$asset = $user->getFieldValue(FIELDHANDLE)->one();
$user->setFieldValues([ 'FIELDHANDLE' => $asset->filename ]);


Getting categories in elementAPI performance issues and help required

I'm no expert on the elementAPI, and a better answer will most likely come, but the country and port fields are relations to different elements (i.e. categories)....so Craft by default uses lazy loading to load this data only when it is called on by default, as I understand it.  And that would probably be why the execution time jumps up.

What you really want to do, I think, is eager load this data as part of your initial query.

For resource on eager  loading, see:

https://craftcms.com/docs/templating/eager-loading-elements
https://straightupcraft.com/articles/examples-of-eager-loading-elements-in-twig-and-php

...so the question is, can you eager load in the element API?  I am not sure, but I'd suggest adding the with part to your criteria and trying it! I'm just guessing on the syntax here, but it looks like:

return [
    'elementType' => 'Entry',
    'criteria' => [
        'section' => 'directory',
        'relatedTo' => ['targetElement' => $category],
        'limit' => 1,
        'with' => ['country','port'],
    ],

...would be worth trying.  My gut feeling is this will work and will distinctly lower your execution time over the lazy loading way, but I'd love to get a report back!


Contact Form plugin email is not being received, not clear if it is being sent

There's a good article here for troubleshooting email errors and well as email deliverability issues: https://craftcms.com/support/troubleshooting-email-errors

TL/DR: Don't use PHP's mail/sendmail methods in production and even in development, you aren't guaranteed email deliverability with those.


Multiple Prices based on User in Craft Commerce

User groups are not a FieldType so you can create a category that matches the title of the userGroup or put the actual category as a field on the User and the Variant. Then in your template do something like this:

{% set userGroup = currentUser.userGroup.first() %}

{% set variants = craft.commerce.variants.product(product).relatedTo(userGroup) %}

This would probably be the best way since you aren't reliant on string matching a title to find the correct variants.


How to append 'Continue reading…' link within the last paragraph of the Excerpt

I'm a total novice with Craft/Twig and I was hoping for some sort of simple and neat append function in Twig!

However, I've got close to a working solution using CSS, by overriding the Extract's
 tags' usual behavior with display: inline, and enclosing the 'Continue reading…' in a  tag.

Edit:
The following (including some additional logic for a 'Summary' field) seems to work well…

    {% if entry.summary %}
        {{ entry.summary }}
    {% else %}
        {{ entry.body.page(1) }}
    {% endif %}

    {% if entry.body.getTotalPages() > 1 or entry.summary %}
        Continue reading…
    {% endif %}

…and…

.excerpts p:last-of-type { display: inline; }


What server provisioner are you using? Forge? Something else? If it's Forge, it's most likely this:

https://twitter.com/nystudio107/status/895726366477344772

Also here are some Nginx configs (with Forge examples) that are known to work with Craft CMS 2.x and 3.x: Nginx-Craft


Twig include with noscript tag rendered as a string and not code

It's escaping the text in the default (html) context, which should not be happening for a template you include

I suspect this is due to a larger issue, as templates that are included should not be escaped in this manner.

You can change the escaping strategy using block tags around the code, though:

{% autoescape false %}
{% endautoescape %}

cf: autoescape


Populating an RSS feed with full post content?

I would use a lead paragraph field that you could then call into the RSS feed. Or you could add a post summary field. You could then call that whenever you need to, RSS or otherwise.


getVersionsByEntryId is deprecated. Can't find the new method?

You can use the revisionOf parameter (docs).

{% set revisions = craft.entries.revisionOf(element.id).all|default(1) %}


I found a solution for this one, actually, you can do this with:

Javascript: Craft.elementIndex.addButton($('').html('test'))

Template: Just add a div with class .buttons, Craft's javascript will check for that and you won't get duplicated divs.

{% block sidebar %}

     Download CSV

  {{ parent() }}
{% endblock %}

Done.
I hope this helps others too.


Craft Commerce: Displaying Individual Product Options in the Cart?

Answer is the example code for the cart:

{{ item.options.giftWrapped }}


In Craft 3 this should be:
  {% if entry.images | length > 1 %}
    {% set secondImage = entry.images.1 %}
  {% endif %}


Is there a way to auto-create a sections Site Settings and propagate when a new site is created?

You can use the EVENT_AFTER_SAVE_SITE event to create/update the new section settings

Event::on(
    Sites::class,
    Sites::EVENT_AFTER_SAVE_SITE,
    function (SiteEvent $event) {
        if ($event->isNew) {

            ProjectConfigHelper::ensureAllSitesProcessed();
            $siteId = $event->site->id;

            // array of sections you want to propagate
            $sectionsToActivate = [
                'test',
            ];

            foreach ($sectionsToActivate as $sectionHandle){

                $section = Craft::$app->getSections()->getSectionByHandle($sectionHandle);
                if($section !== null){
                    /** @var \craft\models\Section_SiteSettings[] $siteSettings */
                    $siteSettings = $section->getSiteSettings();

                    // the site you want to clone from
                    $siteSettings[$siteId] = clone $siteSettings[1];
                    $siteSettings[$siteId]->id = null;
                    $siteSettings[$siteId]->siteId = $siteId;

                    // eventually you want to change some other settings ¯\_(ツ)_/¯
                    //$siteSettings[$siteId]->template = '';
                    //$siteSettings[$siteId]->uriFormat = '';
                    //$siteSettings[$siteId]->hasUrls = '';

                    $section->setSiteSettings($siteSettings);
                   Craft::$app->getSections()->saveSection($section);
                }
            }
        }
    }
);

Explanation: As soon as you create a new site, you'll loop all sections you want to activate and grab their "main" site settings, copy them and set the id to null in order to create a new record


Why the entry-Variable doesn't exists after search?

Yeh this a common problem I've run into as well.
The issue is the entry variable only gets set when Craft is routing to an entry that's created in the CMS. Since you're routing directly to a template, Craft can't populate the variable.
I can think of a couple workarounds:
If your search form page is defined in the CMS, just grab that (or another page):
{% set entry = craft.entries.section('whatever').slug('search').one() %}

Another option is just to modify your code for fallbacks:
{% if entry is defined %}

    {% if entry.seoPageTitle is defined and entry.seoPageTitle != null %}
      {% set metaTitle = entry.seoPageTitle %}
    {% else %}
      {% set metaTitle = entry.title %}
    {% endif %}

{% else %}

    {# set the fallback from a global for example #}
       {% set metaTitle = defaults.metaTitle %}

{% endif %}

That's a lot of code for basically setting variables. What you could do to help clean this up is to use the null-coalescing operator or default filter in Twig:

{% if entry is defined %}
      {% set metaTitle = entry.seoPageTitle|default(entry.title) %}
{% else %}
      {# set the fallback from a global called "defaults" as an example #}
      {% set metaTitle = defaults.metaTitle %}
{% endif %}


Yes, globals can be localised. Make sure you have ticked "This field is translatable" in the field settings for the ones in your global set, and you should be good to go.


Yeah, but you need to make sure you pass an array to the with param and you can’t compose an array by injecting a string into the [ ] like you did in your example.

Try something like this.

{% set withParam = [] %}

{% if displayType == 'teaser' %}
    {% set withParam = ['leadImage', 'type', 'indexHeading', 'brief'] %}
{% endif %}

{% if someCondition %}
    {% set withParam = withParam|merge(['anotherField', 'andOneMore']) %}
{% endif %}

{% set entries = craft.entries({
    with: withParam
}) %}


Categories field that allows duplicate values

I'd probably go with a Matrix field, with one block type containing the Categories field. This would also allow you to include other fields for some extra meta data to distinguish one category assignment from another, otherwise identical one.

To use your playlist example, the Matrix blocks would let you set the order of the tracks as well.


Why would getEntryTableAttributeHtml(EntryModel $entry, $attribute) not return proper labels?

I did a little digging in the source, and here's what's going on:

When Craft builds an element index, it pulls all available element attributes from the ElementIndexesService, where the method getAvailableTableAttributes adds all custom fields to the available attributes, with keys 'field:'.$field->id.

The ElementIndexesService class was added in Craft 2.5.2750, when a lot of things changed related to element indexes (this is when the Customizable Element Indexes feature was added).

Before 2.5, things worked differently – custom attributes weren't "pre-fetched" by Craft, but had to be added manually using the modifyEntryTableAttributes hook, where the $attribute variable passed to getEntryTableAttributeHtml would be a custom field handle, not the current field:{fieldId} value.

It's unfortunate that the official docs for getEntryTableAttributeHtml appear to not having been updated since Craft 2.4, as its current example code won't actually work (for custom fields) since 2.5.

Either way, here's a workaround which should make things a little bit easier in customizing the HTML for custom field attributes:

public function getEntryTableAttributeHtml(EntryModel $entry, $attribute)
{

    // If custom field, get field handle
    if (strncmp($attribute, 'field:', 6) === 0)
    {
        $fieldId = substr($attribute, 6);
        $field = craft()->fields->getFieldById($fieldId);
        $attribute = $field->handle;
    }

    // Get html by attribute (field handle)
    switch ($attribute)
    {
        case 'customFieldHandle' :
            return '<span>'.$entry->$attribute.'</span>';
            break;
    }

}


Attribute default value is always being saved as an int

You can’t override that method from a plugin, if you really think it should be changed I’d suggest to file a feature request.

As a workaround you could try to set a default manually before the attribute is stored to the database or before the value is used. If it’s for a custom field type you could look into utilizing prepValue or prepValueFromPost for example.


File upload - maximum upload size of 0 B

I had the same problem, changing post_max_size in php.ini to something other than 0 (I used 8M) did it for me.

I'm not sure why this works: php.ini says a value of 0 should disable the limit altogether, and this was never an issue on my other Craft installs. Perhaps a bug?


Getting the URI of an Entries field in a Structure with no URLs

So this is what worked for me. It's a bootstrap drop-down menu system using the nav tag from the structure 'menu' with custom fields as described above

{% set menu = craft.entries.section('menu').hidePage('< 1') %}
{% set navlink = "" %}

{% nav entry in menu %}
    {% if entry.entryLink.first|length %}
    {% set navlink = entry.entryLink.first.uri %}
    {% else %}
    {% set navlink = entry.customMenuUrl %}
    {% endif %}

    {% if entry.level == 1 and entry.children|length %}

            {{ entry.title }}

                {% for child in entry.getDescendants().hidePage('< 1') %}
                {% if child.entryLink.first|length %}

 {{ child.entryLink.first.title }}

                {% endif %}
                {% endfor %}

    {% elseif entry.level == 1 and not entry.hasDescendants() %}

{{ entry.title }}

    {% endif %}

{% endnav %}

This has managed to produce a bootstrap drop down menu from the nav tag on a structure section with two fields: customMenuUrl (plain text) and entryLink (Entries field)


How do I get to the web UI in CraftCMS to install it?

How exactly are you running Craft?
Ubuntu/Debian are just Linux operating systems, they don't necessarily come with a web server stack installed but it looks like what you're running is at least partially working.

If you getting the welcome screen, it sounds like Craft got installed so I wouldn't try reinstalling unless you can confirm there's no tables for Craft in your database.

If you can get to http://examplesite.com/index.php?p=admin/dashboard, that typically means the web server's rewrites aren't working and what you have now is a webserver configuration issue—not uncommon.

To solve a web server issue:

Apache: make sure .htaccess is located inside Craft's web folder and AllowOveride All is in your virtual host config.
Nginx: you need some special rewrite rules to get it going.
You may also need to set omitScriptNameInUrls to true in config/general.php.

If you can't get to the dashboard or the login screen, something else happened, perhaps a botched install and you should revisit how your web server got installed.


Accomplished this by setting the get request url, then passing it into tweets:

{% set handle = entry.twitterHandle %}
{% set url = 'statuses/user_timeline.json?screen_name=' ~ handle ~ '&count=3&exclude_replies=true' %}
{% set tweets = craft.twitter.get(url) %}

Hope this helps someone else. Thx!


Switch Matrix block on handle rather than type

I think you already spotted it.

Change:

To:


How to show variations of a single entry? Even possible?

One option to consider would be to use a structure, with the 'building' as a parent entry and the 'units' as children entries (with corresponding entryType of 'building' or 'unit' to set a unique field layout if needed).

Based on whatever logic makes most sense you could then display the building, the building with some subset of data from the units (children), or just the unit. The logic could be either an explicit checkbox or switch on the building or unit entries, or just the mere presence of unit entries (children).

In the structure's settings you can also set whether the 'unit' (child) URI pattern is building/unit (i.e. {parent.uri}/{slug}) or building-unit (i.e. {slug} or {parent.uri}-{slug}).

This should keep everything organized in the CMS and give you a lot of flexibility in terms of what to display where. The building can access the unit data and the unit can access the building data as needed.


How to access Craft.EditableTable instance in CraftCM

So, after fiddling with it for a while, this is what I came up with it:

When using forms.editableTable make sure you don't initialize Craft.EditableTable. You can do that by setting the initJs to false:

{{ forms.editableTable({
    id: 'myTableId',
    name: 'myTableName',
    cols: yourTableCols,
    ...
    initJs: false,
    ...
}) }}

That means that you will have to initialize the Craft.EditableTable yourself:

{% includejs %}
(function () {

  var t = new Craft.EditableTable(
    "{{ 'myTableId'   | namespaceInputId   | e('js') }}",
    "{{ 'myTableName' | namespaceInputName | e('js') }}",
    {{ yourTableCols|json_encode|raw }},
    {
      onAddRow: function( tr ) {
        // attach event listeners to row fields here
      }
    }
  );

} ());
{% endincludejs %}

From this point on, you can add your own listeners to the fields in the row.


Since multiple line item can be updated or added to the cart at the same time, it would be hard to point to a specific line item that is newest.

The line items have a dateUpdate column you could sort and query on.

{% set result = craft.query()
    .select('*')
    .from('{{%commerce_lineitems}}')
    .where({
        'orderId': cart.id
    })
    .orderBy('dateUpdated ASC')
    .one()
%}

We could look to added a lastUpdateLineItem() method to the order element in future version of Craft Commerce. You can submit the idea here: https://github.com/craftcms/commerce/issues


What is the best way to include an Element's content?

I've determined what I think to be the best way to dynamically add Element's field content values to my responses.

First off, the reason why field content values are being returned using $element->getContent() regardless of the Element relationship with the fields, is because the content table has field values as columns themselves. So when a Content model is populated, all fields are included. If I setup a field for an Entry, it will appear as a field for a User when using this method.

My solution:

$entries = array();

$results = craft()->elements->getCriteria(ElementType::Entry)->find();

foreach ($results as $model) {
    $entry = array();

    $attributes = $model->getAttributes();

    foreach ($attributes as $name => $value) {
        $entry[$name] = $value; // Do some transformation here (type casting, etc.)
    }

    $content = $model->getContent(); // No extra DB queries here - Model is already populated with content values

    $fields = array_map(function (FieldLayoutFieldModel $model) {
        return $model->getField();
    }, $model->getFieldLayout()->getFields());

    foreach ($fields as $field) {
        $entry[$field->handle] = $content->{$field->handle};
    }

    $entries[] = $entry;
}

return $this->returnJson(array(
    'entries' => $entries,
));

In my particular development, I've separated a lot of the above logic into services, which I'm using like Transformers.

This helps me deliver field content values through my API. I spent hours pouring through source code, and I'm pretty confident this is the best solution based on efficiency, best practices, and similarity with logic concepts found throughout built-in services and models. Let me know what you guys think.


Craft Commerce: Export each order to a specific CSV file and send it throught email

You could write a custom Craft plugin (generate the boilerplate for it at https://pluginfactory.io) that listened to one of Craft Commerce's order events.  Likely onSaveOrder or onOrderComplete depending on your specific requirements.

From there, your plugin could build the CSV the old fashioned way in PHP, or use something like the CSV library to do the heavy lifting for you.

Once you've built the CSV, you can use Craft's EmailService->sendEmail() (accessible through craft()->email->sendEmail() to add the attachment and shoot the email off.


Fetching a Localized Global as a Static Translation Causes Error in How Plugins Load

This line:

$current_criteria->fieldId = craft()->fields->getFieldByHandle('translations');

should probably have a ->id at the end?

$current_criteria->fieldId = craft()->fields->getFieldByHandle('translations')->id;

But the whole code could probably be replaced with:

function get_dynamic_translations() {
    $translations = array();

    if (!craft()->request->isCpRequest()) {

        $i18n = craft()->globals->getSetByHandle('i18n');

        foreach ($i18n->getFieldValue('translations') as $current_block) {
            $translations[$current_block->content->key] = $current_block->content->value;
        }
    }

    return $translations;
}


Trouble with curly braces in Entry URL Format / renderObjectTemplate

It's not documented so I guess not officially supported, but you can use template variables in the URL formats. For example if you had a UrlFormats plugin, you could use something like this:

<?php
namespace Craft;

class UrlFormatsVariable
{
    // Use in the URL Format box:
    //
    //  {{ craft.urlFormats.yourSectionHandle(object) }}
    public function yourSectionHandle($entry)
    {
        // Craft checks the URL format with an array "object" first, to see if there's a {slug},
        // and so whether it should be checked for uniqueness and incremented if necessary.
        if (!$entry || !($entry instanceof EntryModel))
        {
            return '{slug}';
        }

        $relation = craft()->elements->getCriteria(ElementType::Entry)
            ->relatedTo(array(
                'targetElement' => $entry,
                'field'         => 'productConfigs',
            ))->first();

        if (!$relation)
        {
            // throw an exception or default to something
        }

        return $relation->uri.'/'.$entry->slug;
    }
}

Then you can keep your URL Format and Nested URL Format inputs cleaner:

{{ craft.urlFormats.yourSectionHandle(object) }}


A plugin to validate a field depending on another field's value

In your FieldType you have $this->element available, representing the Element the field is in. If you use $this->element->lightSwitchHandle you can access its value.


Is there a way to reduce the search index?

Craft 3:

In Craft 3, a plugin can listen to the Element::EVENT_REGISTER_SEARCHABLE_ATTRIBUTES event to modify the searchable attribute list of an element before it is indexed.

Craft 2:

Currently the answer is no.

Maybe it makes the case for some sort of onBeforeSearchIndex event a plugin could listen to and influence what Craft adds to the search index, but given that manually updating the search index isn't meant to be a common occurrence (Craft keeps them up to date in normal element saving operations), I'd probably add the workflow you're using that requires frequent updates to the feature request.


This isn't perfect by any means and might need tweaking but to get you on your way:

Assuming that on a user page, you are doing {% set user = ... %} somewhere (as you would do {% set entry = ... %} on an entry page), You just add another clause to your if statement, after checking for category, you check for user:

{# User is defined #}
{% elseif user is defined %}
  {% set url = lang.baseUrl ~ 'membership/directory/' ~ craft.app.request.segments|last %}
{% endif %}

Or if you have set the user:

{# User is defined #}
{% elseif user is defined %}
  {% set url = lang.baseUrl ~ 'membership/directory/' ~ user.id %}
{% endif %}


Is it possible to add a Section, Entries in basic/simple HTML page instead of Twig template?

You can't add a Section in Twig either. You have to use PHP in order to create logic. Html is only used to display things on you page but it does not include logic nor is it able to fetch elements (working with databases) Twig is a template engine, you could describe it as a middleman between HTML and PHP it is able to fetch elements and uses a limited amount of PHP to display them

You won't be able to work with Craft properly without using Twig at all unless you modify many things with PHP

Like mentioned in the other thread Craft might not be the correct  CMS for you


You could just set your "Entry URL Format" to:

my-section/{type.name}/{slug}

Your entry type names couldn't be as clean when composing entries in the CP as you'd need to set them to something like "example-entry-type", but it would work.

Now for the really clean way:

Install the Low Regex for Craft plugin.

Set "Entry URL Format" to:

my-section/{type.handle|regex('/(^|[a-z])([A-Z])/e', 'strtolower(strlen("\\1") ? "\\1-\\2" : "\\2")',(type.handle))}/{slug}

This will convert the entry type handle from camelCase to all lowercase with dashes as word delimiters. Set the entry type handles to be like "exampleEntryType" and they will become "example-entry-type" when in a slug.


You can get your past entries by month as explained here. Than it's just a matter of displaying them they way you want to.


I do all images through a macro, that substitutes in our logo if an image happens to be missing.

{% macro imageTransform(image, transform, caption, extraHTML) %}
  {# Fallback to our logo if the image is null... #}
  {% if not image|length %}
    {% set image = craft.assets.id('84').first() %}
  {% endif %}
  <img src="{{ image.getUrl( transform ) }}" width="{{ image.getWidth( transform ) }}" height="{{ image.getHeight( transform ) }}" title="{{ caption|default('') }}" alt="{{ caption|default('') }}"{% if extraHTML %} {{ extraHTML }}{% endif %}>
{% endmacro %}

We have a more complicated version for responsive images but that's the basic idea...

Also, to find things using assets, although I have never used it, I hear this is good:
https://github.com/iainurquhart/craft_introvert


Yeah, I think you are close, you've just go your variables a bit mixed up. You set entries, but then reference entry and I think getUrl should be called as a function getUrl() as it's not a property (it might work that way, I've never tried tbh)

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

{% for image in entry.podcastItunesImage %}
 <itunes:image href="{{ image.first.getUrl() }}" />
{% endfor %}

Edit
Oh I don't think you need {{ siteUrl }} when you call getUrl()


Problem with matrix if statement for hero image other content ends up in my div

The problem is that the if statements are not nested properly. If your matrix does not contain the cta block for example then the 2 closing div tags will never be output, which obviously destroys the layout.

The bigger question for me is why you would want to separate the fields into different blockTypes at all. An easier approach would be to create one blockType (called 'imageHero' for example) with all 5 fields in it ('image', 'heading', 'subHeading', 'ctaEntry', 'ctaText'), which you could access directly. In this way, the blockTypes could be used for different 'types' of hero, rather than for separating out a single hero's fields.

{% for block in entry.hero %}

    {% if blocktype == 'imageHero'%}

        {% set image = block.heroimage.first() %}
        {% if image %}

                    {% if block.heading %}

{{ block.heading }}

                    {% endif %}
                    {% if block.subHeading %}

{{ block.heading }}

                    {% endif %}
                    {% if block.ctaEntry and block.ctaText %}
                        {{ block.ctaText }}
                    {% endif %}

        {% endif %}

    {% endif %}

{% endfor %}


Password hashes aren't included in the default user query for security reasons, but if you want to force them to get added, you could use:

{% for user in craft.users().status(null).addSelect(['users.password']).all() %}


This article will help you set permissions properly for Craft CMS installs:

Hardening Craft CMS Permissions

It leverages Craft-Scripts to do the heavy lifting.


Is there any easy way (via the admin panel) to get a direct link for an asset?

You could utilize the modifyAssetTableAttributes and getAssetTableAttributeHtml hooks.

So, you would create a plugin, and in the main plugin file you could add something like the following:

public function modifyAssetTableAttributes(&$attributes, $source)
{
    $attributes['filePath'] = Craft::t('File Path');
}

public function getAssetTableAttributeHtml(AssetFileModel $asset, $attribute)
{
    if ($attribute == 'filePath')
    {
        $filePath = $asset->url;
        return $filePath;
    }
}

* Edit *

I did test this, and it works, but because of Craft's ability to reorganize Assets (i.e., drag them to a new folder) it's not just a simple matter of highlighting the link, copying, and pasting.

However, by taking this example a little further, you should be able to add a little JS and have a link or something to that effect output in getAssetTableAttributeHtml that when clicked copies the URL to the user's clipboard. If you go this route, make sure to include the JS in your plugin's init method. Something like:

public function init()
{
    craft()->templates->includeJsResource('yourplugin/your-js.js');
}

Or (hah), for a really basic implementation, you could wrap the string in a URL and just have them right click and "Copy Link Address":

public function getAssetTableAttributeHtml(AssetFileModel $asset, $attribute)
{
    if ($attribute == 'filePath')
    {
        $filePath = 'url.'">' . $asset->url . '';
        return $filePath;
    }
}


Constant exception.Craft\HttpException.404 in logs

You can try installing the Retour plugin to get a log of all of the 404 errors and their referrers, and potentially handle them via redirects.


301 Redirects Appends ?p=original/url/path - how can I remove?

The issue here is that your Redirect directive is conflicting with Craft’s index.php-hiding RewriteRule directive. (Redirect is a mod_alias directive and RewriteRule is a mod_rewrite directive. They’re two separate modules that can be used for the same thing, but lead to unexpected consequences when used together.)

To fix this, use a RewriteRule directive for your own custom redirects as well, rather than Redirect.

RewriteRule ^blog/category(/.*)?$ /blog/archive$1 [R=301,L]

Make sure that you place that before Craft’s redirect.


Plugins get removed after publishing to Heroku

This is the way Heroku works with its ephemeral file system. Anything written by the webapp (which includes plugins installed via Composer) after the fact can be wiped out at any time.

If you must ship it on Heroku, you probably should check all of vendor/ into the repo, so that it's part of the actual deployment, and not added post facto.


Search for href parameter in rich text field

Before Craft saves any keywords in the craft_searchindex table in the database, that content goes through a normalization process, including things like removing punctuation.

So the link "http://bit.ly/1eZFQMY" will actually get normalized to http bit ly 1ezfqmy.

If you really wanted to find all entries with bitly URLs in them, then using "http bit ly" should work.


Single not loading correctly with additional segments

If I understand your question correctly you might be better off using SEOmatic's Template Meta feature.

Using the Template Meta you're be able to set the meta info on a per template basis. So in this case you'd create a one to use for your calendar.html template.


Dynamic Blitz Template not loading currentUser

Your code looks correct. Test with the following code in brands/_followButton.
{{ currentUser ? 'Logged in' : 'Logged out' }}

For some reason, it's not working and I can't figure out why.

Can you explain what specifically is not working? And provide the version of Blitz that you're using?


Craft suddenly no longer works on Heroku

This bit us a few days ago, as well.

As far as I could tell from the build log, the cause was that Heroku bumping their PHP version from 7.3.x to 7.4.x, and exposing an incompatibility with one of Craft's dependencies.

To lock your PHP version to a 7.3.x release on the Heroku stack, just add this to your composer.json:

{
  // ...
  "require": {
    "php": "~7.3.0"
    // ...
  }
  // ...
}


What effect does nesting cache tags have?

Nesting cache tags shouldn't cause any new problems (assuming you've taken into account all the fun problems already caused by cache).

Each cache tag will store it's contents in a database table for easier access. We can illustrate this a bit easier using cache tags with keys.  Take the following example with two cache tags using the keys dog and cat

{% cache using key 'dog' %}
    BUSTER
    {% cache using key 'cat' %}
        KITTEN
    {% endcache %}
{% endcache %}

When the cache tags are run they store the following:

cat stores the value:

KITTEN

dog stores the value:

BUSTER
KITTEN

The spacing in my example above may not be perfectly accurate but the gist of what content is stored should be. In the case that the page is loaded a second time, when the dog cache tag is found, Craft will pull it's content from the database.  The cat cache tag will never get run, but it doesn't matter, because the full contents of the wrapping dog cache tag have already been retrieved.


Adding reCAPTCHA to the admin login page

We do this at Transform Studios at the DNS level by using cloudflare’s Web Application Firewall. You can basically add a rule which targets any url that matches the control panel login page and secure it with a captcha challenge before giving access to the page. I’ve found this is best to handle security before visitors even hit your site and more importantly prevents any core code base changes or creation of addons.


One way to get around this is to create a new Asset Source (let’s call it “Staging”).

Add the folder of unindexed images/assets into Staging, our new asset source (which should otherwise be empty).
Now, run the asset indexer via Settings > Update Asset Indexes only for our new source, Staging.
Once the indexer has done its job, go to the Assets section of the Control Panel and drag the freshly indexed folder of images/assets from Staging to the desired Asset Source.

Repeat the above process every time you wish to index a bunch of new assets without touching the previously indexed assets.


Is it possible to add an entries field to recurring events that can be changed per occurrence?

Calendar's event recurrences are only simulated/inflated by a repeat rule for the main event. Since there is no database entry for each recurrence, there's unfortunately no way to achieve something like this at this time.


One way to do it is to split the search query on spaces, and then join it with 'OR':

{% set query = craft.request.getParam('q')|split(' ')|join(' OR ') %}
{% set entries = craft.entries.search(query).order('score') %}

The above will convert the search term "salty dog" to "salty OR dog". It'll work regardless of the number of keywords in the original search query string.

You should probably also make sure that you remove redundant whitespace from the original query, if you don't then a search query like "salty  dog" (double space) will result in a query like "salty OR OR dog". Here's how you could do that using some regex and the replace filter:

{% set query = craft.request.getParam('q')|replace('/(( )+|(\\n)+)/', ' ')|split(' ')|join(' OR ') %}


Template path from plugin not working from CP

You probably just need to call PathService::setTemplatesPath() and pass in the path to your plugin's template folder.

It would look something like:

// Save the current template path.
$originalPath = craft()->path->getTemplatesPath();

// Set your plugin's template path.
$path = craft()->path->getPluginsPath().'/mypluginfolder/templates/';
craft()->path->setTemplatesPath($path);

//Send to each User
foreach ($users as $user)
{
    //Send Mail
    $email = new EmailModel();
    $email->toEmail = $user->email;
    $email->subject = 'New Question';
    $email->htmlBody = "{% extends '{$template}' %}".
        "{% set body %}".
        '

A new question has been posted by '.$entry->author->name.':

Question: '.$entry->title.'

Description: '.$entry->questionDetails.'

Attachments: '.$entry->questionAttachments->total().'

url.'" title="'.$entry->title.'">Answer Question

                    '
        ."{% endset %}";

    craft()->email->sendEmail($email);
}

// Reset the original path.
craft()->path->setTemplatesPath($originalPath);


As far as I understand it, the postLoginRedirect only affects login forms defined on the the front-end. If a user visits the login page (through a 'login' link for example), then they will be redirected to 'postLoginRedirect' after logging in. They will also be redirected there if they attempt to visit the login form directly when already logged in.

Your best option is to just create a quick login page template, like the one provided in the docs. Craft will automatically look for 'login.html' in your templates folder - otherwise you can specify the location using the loginPath config setting.

With that defined, if a user tries to visit any page that has {{ loginRequired }} specified, they will automatically get redirected to the login page and subsequently be redirected back to the original page request after login.


Uncheck "Use this field’s values as search keywords?" by default?

As of Craft 3.5, that setting will be disabled by default when creating new fields (see craftcms/cms#6390).


How to find entries that are not related?

You'll need to approach this in two steps:

Get all the entries that DO have relationships.
Filter those entries out of your ElementCriteriaModel, either by using the "not" syntax on the entries id parameter of the craft.entries variable, or by using the without Twig filter in your loop source.


Limit search by channel on the form rather than the results template

You'd do it just like querying for any other element in Craft.  i.e.

{% set results = craft.entries({
    search: query,
    section: 'news'
}) %}


How to get the order number of the current entry in a structure

There's a positionedBefore parameter for craft.entries. Use this with a criteria model filtered to
show the entries you are interested in only.

{% set parent = entry.getParent() %}
{% set siblingsIds = parent.getChildren().ids() %}

{% set positionedBefore = craft.entries({
    id: siblingsIds,
    order: 'lft desc',
    positionedBefore: entry,
}).total() %}

With the first two lines I'm getting the IDs of all of the entry's siblings. I then prepare a craft.entries criteria model using the siblings' IDs with the id parameter to query just for those entries, order them by lft in descending order (that's the db column Craft stores position info) and further filter with positionedBefore to get just the entries before entry.

Calling the total method returns the number of entries found.


/**
 * Class SearchRelationship record
 *
 * @property int $id
 * @property int $aaa
 * @property int $bbb
 * @property string $ccc
*/
class SearchRelationship extends ActiveRecord
{
    /**
     * @inheritdoc
     * @return string
     */
    public static function tableName(): string
    {
        return '{{%somename}}';
    }
}

All you really need to define is the table name.  Yii 2 uses reflection on the database table to generate the column/object property names at runtime (replacing the old setAttributes method).
Worth reading: https://www.yiiframework.com/doc/guide/2.0/en/db-active-record
Indexes should be initially defined in your plugin's install migration (replacing defineIndexes).


I've actually done this a couple of times... a very simple "password-only" page. Then there would be a large group of people who share that same password, and can gain access to that protected page.

  Disclaimer: This example was built using the Business Logic plugin template.

There are many ways to manage your password, but it sounds like you'll want something as simple as a Global field. Create a Global field for your password, and keep track of the Global Set ID and the field handle (you'll need that info in a minute).

On your secure page, you'll want something like this:

{% if craft.businessLogic.accessGranted %}

{% else %}

Enter your access code:

    {% if error is defined %}

{{ error }}

    {% endif %}
    <form method="post" action="" accept-charset="UTF-8">
        <input type="hidden" name="action" value="businessLogic/authorize">
        <input type="text" name="pw" value="">
        <input type="submit" value="Log In">
    </form>

{% endif %}

Upon submitting that form, your plugin's Controller will authenticate the user, and set a cookie to remember the user.

Something like this for your plugin's Controller:

<?php
namespace Craft;

class BusinessLogicController extends BaseController
{
    protected $allowAnonymous = true;

    // Login authorization action
    public function actionAuthorize()
    {
        // Get password
        $pwSubmitted = craft()->request->getPost('pw');

        // Check access
        if ($this->_validPassword($pwSubmitted)) {

            // Set access cookie
            $expires = time() + (60*60*24*7); // One week
            setcookie(md5('cookieNameToBeHashed'), 1, $expires, '/');

            // Redirect
            $this->redirect(craft()->request->getPath());

        } else {

            // Output error message
            craft()->urlManager->setRouteVariables(array(
                'error' => 'Invalid access code'
            ));

        }

    }

    // Check if password is valid
    private function _validPassword($pwSubmitted)
    {
        // Get global set
        $globalSet = craft()->globals->getSetById(156);

        // Get target password
        $pwTarget = $globalSet->passwordFieldhandle;

        // Return whether password matches
        return ($pwSubmitted === $pwTarget);
    }

}

Your plugin's Variable can check if the user is already authorized.

Something like this for your plugin's Variable:

<?php
namespace Craft;

class BusinessLogicVariable
{

    // Check if access cookie is set
    public function accessGranted()
    {
        $cookieName = md5('cookieNameToBeHashed');
        return array_key_exists($cookieName, $_COOKIE);
    }

}

Which of course, brings it full circle. Your secure page will check if accessGranted before showing either the secure content, or the login form.


I'm not sure what recentlyViewed() is and what it returns but to query today's entry, you can do:
{# Today in atom format #}
{% set timeAgo = date('today') | atom %}

{% set recentMerchantsOffers = craft.entries()
    .section('offers')
    .postDate(">= #{timeAgo}")
    .all() %}


I think the issue is that craft will sanitise (escape) any code before it goes into the database, to prevent any code injection and twig will also do the same at a template level (to prevent script injection).

If you have your entry title as DIVA! Becomes Famous &#8480 for example, it will appear like that in craft and in your templates, but if you do {{ entry.title|raw }} it will actually output ℠ in your template.

From the twig docs:

  The raw filter marks the value as being "safe", which means that in an environment with automatic escaping enabled this variable will not be escaped if raw is the last filter applied to it

See more in twig docs


UnexpectedValueException after loading plugin

The solution was to replace all references to "reference":null with  "reference":"" in /craft/vendor/composer/installed.json.


Getting Matrix field ID and Block ID for my Custom Field

The BaseFieldType class (which all FieldTypes extend) has a contentPostLocation property, which will give you the "path" to the field inside the entry model. The value is returned as a string, e.g. fields.myCustomFieldTypeHandle.

If your field is inside a Matrix block, the contentPostLocation path will include the Matrix field's handle – as well as the block ID – e.g.

fields.matrixFieldHandle.12.fields.myCustomFieldTypeHandle

Based on this, by exploding the contentPostLocation string and testing its length, you can figure out if the field is "standalone" or embedded in a Matrix block:

$contentPath = explode('.', $this->contentPostLocation);
if (count($contentPath) > 2) {
    // Not standalone (i.e. probably inside a Matrix block)
}

The Matrix' field's handle will be the second segment in the path. You can use the FieldsService to pull the actual field, in order to get its ID. It's probably also a good idea to confirm that it is indeed a Matrix field, which is easily done by checking its fieldtype's classHandle property:

$matrixFieldHandle = $path[1];
$matrixField = craft()->fields->getFieldByHandle($matrixFieldHandle);
if ($matrixField && $matrixField->fieldType->classHandle === 'Matrix')
{
    // Yup, it's a Matrix field!
    $matrixFieldId = $matrixField->id;
}

Finally, the block ID would be the next segment in the contentPostLocation path, i.e. $matrixBlockId = (int) $contentPath[2];

Putting it all together, something like this should do the trick:

public function onAfterElementSave()
{
    $contentPath = explode('.', $this->contentPostLocation);
    if (count($contentPath) > 2)
    {
        $matrixFieldHandle = $contentPath[1];
        $matrixField = craft()->fields->getFieldByHandle($matrixFieldHandle);
        if ($matrixField && $matrixField->fieldType->classHandle === 'Matrix')
        {
            $matrixFieldId = $matrixField->id;
            $matrixBlockId = (int) $contentPath[2];
        }
    }
}


Members' site in Craft possible out of the box?

Yes:

In Craft, all Elements — including Users — can have custom fields of their own. (So, for example, each User could have a "Bio" field.) You can use a User Profile Form to allow Users to edit their own profiles.
You can restrict the upload directory for each Assets field. So, for example, you could create an Assets field that stores files in a directory based on each User's ID, which would effectively keep one User from viewing/disturbing another User's files.


Getting PHP Error on upgrade from 3.0.36 to 3.1

If you restore from a 3.0.36 database backup, then update to the latest Craft 3.1 release (currently 3.1.2.2, this shouldn't be an issue anymore.


Using elements-api, how do i create a geojson structure with Features within a FeatureCollections

If anyone stumbles onto this, i gave up looking for a solution and created my own plugin, to get you started, someone else with the same problem posted some sample code here that returns json from a db query : With Element API, can I combine two entry types into a JSON object, keyed by type?


MySQL "Access denied for user" after moving to new server

Seems this is not a Craft issue at all, but an issue with MySQL connections over PDO. Not sure of the precise environmental conditions that cause this, but I was experiencing the issue on both an AWS EC2 Ubuntu server as well as a MySQL RDS instance.

I discovered the solution here: https://stackoverflow.com/questions/38809418/unable-to-connect-to-aws-rds-through-pdo

In short, the ! in my password was causing the problem. After replacing it with a ., the issue is resolved.

Thanks Amazon...


If Craft can't connect to the database, it will let you know.  Some other error is occurring. Check your craft/storage/runtime/logs files for an [error] entry, and that will have the error message that is occurring.

Also, in between installation attempts, be sure to delete any tables that were created in the database from a previous install attempt.


With freeform you can install some demo templates from which you can see how it works:
https://docs.solspace.com/craft/freeform/v3/setup/demo-templates.html#installing-the-demo-templates
You can also render your form with: {{ craft.freeform.form("formHandle").render() }}
Some additional info on that and additional custom formatting can be found here: https://docs.solspace.com/craft/freeform/v3/overview/formatting-templates.html


Simple Product Listing Pages by Category Slug

You're nearly there! You are missing the part that fetches the entries related to your category.
With your current set up, you would need to do:
{# Get the requested category slug from the URL #}
{% set requestedSlug = craft.app.request.segments|last %}

{# Fetch the category with that slug #}
{% set category = craft.categories()
    .slug(requestedSlug|literal)
    .one() %}

{# Fetch the entries related to your category #}
{% set entries = craft.entries()
    .section('yourSectionHandle')
    .relatedTo(category)
    .all()%}

{% for entry in entries %}
    {{entry.title}}
    {{entry.url}}
    {{entry.image}}
{% endfor %}

Replace yourSectionHandle with, well... your section handle :)
Alternatively, Craft provides a way to simplify the process a bit.

First, it doesn't look to me like you can create separate templates for each category, only the Category group, correct?

You can manually create a template for each category by making a file named as your category slug but this is tedious to maintain.
The way you could handle that would start when you define your category group's settings.
This is only an example but you should get the gist of it.
First, define Settings → Categories → Your Group → Category URI Format to be categories/{slug}, the Template to categories and make a categories.twig template at the root of your templates folder.
Now, when you access yoursite.com/categories/category-slug (category-slug being an actual category slug), Craft will auto-inject a category variable to the template (like the entry variable on entry pages) allowing you to only have the following in the template:
{# Fetch the entries related to your auto-injected category variable #}
{% set entries = craft.entries()
    .section('yourSectionHandle')
    .relatedTo(category)
    .all()%}

{% for entry in entries %}
    {{entry.title}}
    {{entry.url}}
    {{entry.image}}
{% endfor %}

Hopefully, that makes sense for you!


How to reference controller action from hidden action? Correct path?

After my changes, this worked:

value="psychEmail/publication/pubRequest"


Image transform with either width or height

A similar question has already been asked here: Is there a way to find out if images (assets) are landscape or portrait?

You will need to create the two asset transforms you mentioned in your question, and then in your template code use an if/else statement to determine which transform to use, depending on if the asset is portrait or landscape.

Thanks to Josh for the code, this is taken from his answer:

{% set myImage = entry.imagesField.first %}

{% if myImage.getWidth() < myImage.getHeight() %}
  {# portrait #}
{% elseif myImage.getWidth() > myImage.getHeight() %}
  {# landscape #}
{% else %}
  {# square #}
{% endif %}


Multisite, second language Live Preview not working

Issue within the .htaccess file!

These lines were causing the redirect to https to malfunction:

# Remove trailing slashes
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [R=301,L]


How to calculate the number of days left?

You want to use "a" as your DateInterval format parameter instead of "d".

Also, you may need to use Twig's date function on the end date, which "converts an argument to a date to allow date comparison".

This should give you the correct number of days between now and the future date:

{{ date( inschrijven.datumEvenement|date ).diff( now ).format('%a') }}

or

{{ date( inschrijven.datumEvenement|date ).diff( now ).days }}


Even if you set the limit to 1, Craft always returns an array of entries. So you need to add first() to access the first (and only) entry.

{{ entry.buttonTargets.first() }}

It you don't add a property, this returns the entry's title by default. So you additionally need to add url to output the URL of that entry.

{{ entry.buttonTargets.first().url }}


Where exactly are my element type custom statuses stored and used?

For starters I'd classify statuses in two groups - static statuses and dynamic statuses:

Static statuses are set explicitly
Dynamic statuses change according to other circumstances (other attribute values, lunar phases, whatever)

For static statuses you'd go with the approach Lindsey outlined and just define a column for that where to store everything, however, things get more interesting when you start tackling dynamic statuses.

For that, you should look at the Entry element type.

/app/elementtypes/EntryElementType.php
/app/models/EntryModel.php

You'll want to look at the EntryElementType::getElementQueryStatusCondition() method - adding this method to your Element type will allow you to use "status" criteria when searching for elements. As a nice side-effect, this will also make the status filter in the Element index work nicely.

Another method worth looking at is the EntryModel::getStatus() method - implementing this method ensures that your Element type actually returns the correct dynamic status when asked for it.


I think you are using the wrong string concatination operator. ~ is the twig string concatination operator (vs . for php and + for javascript).

Try this:

{%
  set entries = craft.entries.section('schools').find({
   search: 'body:' ~ queryKeyword ~ ' categories:' ~ queryLocation,
  })
%}


Currently, you unfortunately can't query all sites within your entires, you will have to separate your results out with a for-loop by site, as @aran did above.

Craft 3.2 will thankfully fix this by allowing you to pass sites to an array or query sites('*') to return entries from all your sites:

https://github.com/craftcms/cms/commit/d01702278bd84b84392e11da72aa4d0b6f4f0943


Sounds like you're looking for the Twig |striptags filter, which is a wrapper for PHP's strip_tags


How do I update the content of a field type in the onAfterElementSave() method?

This will return the content for the specific element instance you're on:

$this->element->getContent()

And from there you can do your additional content processing.

When you're ready so save it, you can call:

craft()->content->saveContent($this->element);

There are several examples in craft/app/fieldtypes folder where Craft's native field types do additional processing like this.


Solspace Calendar For Craft CMS - Importing ICS Files

Sorry, Calendar currently does not allow for importing of any events via ICS or other means.

source: Kelsey Martens, Director of Software Operations


MatrixBlockModel error - "Call to a member function on a non-object"

Matrix initializes its blocks’ field types multiple times – once for each existing block in the field, and one last time to get the initial input HTML that should be used when new blocks are added.

For existing blocks, $this->element will be set on the field types, referring back to the existing MatrixBlockModel objects representing each of those blocks.

That won’t be the case the time that your field type is just telling Matrix what the initial input HTML should be, however, since no corresponding Matrix block exists yet.

When you call this:

var_dump($this->element);

it’s not giving you any errors because $this->element will just be null when there is no element set, and there’s nothing wrong with dumping a null variable.

But when you call this;

var_dump($this->element->getOwner())

now you’re trying to access a method on $this->element, which won’t necessarily be set, and that’s when you’re getting that exception.

So what you need to do is ensure that $this->element is actually set before trying to access getOwner():

if (isset($this->element))
{
    $owner = $this->element->getOwner();

    if ($owner)
    {
        // ...
    }
}

Note that I’m also not assuming that getOwner() will actually return anything, because that’s not a certainty either. For example if you create/save a new entry but there are validation errors, when the Edit Entry page reloads, you will have MatrixBlockModel objects for each of the blocks you had created, which $this->element will point to, but they won’t actually have IDs nor an owner yet.


Very minor change to Brad's approach, and with a bit more checking to avoid issues like the product being deleted while the code is looking in that direction, etc. (based on Luke's advice).

foreach ($cart->lineItems as $item)
{
    // check the purchasable has not been deleted in the meantime
    if ($item->purchasableId)
    {
        // get the variant and the actual product so we can get to custom fields
        $variant = $item->purchasable;

        // If there is no product associated with this purchasable, it's a digital virtual product so just skip it
        if (!isset($variant->product))
        {
            continue;
        }

        // get the actual product element from the purchasable
        $product = $variant->product;

        // How to get a regular field on the product
        $title = $product->title;

        // How to get the product type - use handle rather than name, as this is less likely to change
        $productType = $product->type->handle;

        ...etc
    }
}


Craft 2.2 with enabled enableCsrfProtection: Failed to load resource: the server responded with a status of 400 (Bad Request)

I can confirm this is a bug on Craft 2.2.2579 when CSRF protection is enabled.  Will get a fix out for it shortly and update this answer when it's done.

Update:

Fixed in Craft 2.2.2582.


How to list all Matrix Blocks from anywhere, using a slug?

{% cache %}
  {% set entry = craft.entries.slug('team').last() %}
  {% for field in entry.getFieldLayout().getFields() %}
    {% if field.getField().type == "Matrix" %}
      {% set fieldHandle = field.getField().handle %}
      {% set matrixBlocks = entry.__get(fieldHandle).find() %}
      {% for block in matrixBlocks %}
        {{ block.team_name }}
      {% endfor %}
    {% endif %}
  {% endfor %}
{% endcache %}


How to set up Craft to use Google Cloud Storage?

Craft 3:

Once you have created your project in GC, navigate to GC Storage.

Create a bucket. You can only create a bucket containing the domain name if you are able to prove ownership. For example, I (personally) could not create files.craftcms.com as my bucket. Otherwise it can be anything you'd like. Or check out the Bucket and Object Naming Guidelines
Navigate to IAM & admin. We'll need to create a Service Account that can be used to give Craft access to the bucket.
Give your Service account a name. For example, "Cloud Storage". Google will create a service account ID that will look something like cloud-storage@<project-name>.iam.gserviceaccount.com. For Project Role, (you can filter) but choose "Storage Admin". You'll also want to select the checkbox labeled, "Furnish a new private key". Choose json as the format and click "Save".
A file will be downloaded to your computer - awesome. Next install the Google Cloud Plugin for Craft: composer require craftcms/google-cloud
Once installed, create a new Asset Resource and instead of "Local" choose "Google Cloud Storage" as a volume type.
Give your resource a name. For example, "Images". If you choose to have public url's use this url: http://storage.googleapis.com/. Unless you have a specific DNS record set up to serve images from that you want to use, you could do that too. Enter the project ID of your project. You can find that by clicking on your project name - very top (blue) nav bar. For example, it could be my-project
Finally, remember that .json file that was downloaded? Open that with your favorite text editor and paste the contents into "Contents of the access key file". Hit the "Refresh" button, and you should now see the name of your primary bucket. In my case files.mysite.com. You might also notice that Craft will update the base url to the files: http://storage.googleapis.com/files.mysite.com/

From there, you could create sub-folders in GCS. In my case, I've created one called images. I will update that in the Subfolder input: images.

Save your newly created resource!


It depends on the type of errors that are being thrown.  If they are Twig/template errors, then you can can set the suppressTemplateErrors config setting to true and they will simply get logged and the page request will continue as usual.

If they are non-Twig exceptions, then you'd have to do something more fancy like make a plugin that's essentially a facade for the Imager plugin and wraps all of it's calls in a try/catch block that just swallows any exceptions.

Or make a pull request that added support for it to the plugin itself.


In Craft, assets are always "absolute" paths to the webroot, not relative to the URL (although you can make it like that).
So in your example, @AssetPublicPath/images is going to be replaced with https://dev-craft3-f59ef5d673d0.hyperlane.co/uploads/images.
If you want something to go into a subfolder, in this case work, you'd need to either specify that as another Craft Volume or specify that in the featuredImage asset field.
Looks like have "restrict uploads to a single folder" checked but there's nothing set in that field so Craft is getting confused as to where to put things.


Craft periodically goes down due to plugin migrations

Okay so the site hasn't gone down in 2 days, so fingers crossed that we actually fixed this.

Following Brad's initial comment, we noticed that the schemaVersion key was missing from that plugin's class file. We went ahead and added one:

/* this was there */
public function getVersion()
{
  return '1.0.0';
}

/* We went ahead and added this */
public function getSchemaVersion()
{
  return '1.0.0';
}

And now since the schema version === the current version, it no longer throws errors.


Is there an issue with debug mode in 2.4?

There is a bug in the current release that's been fixed for the next one where PHP Errors/Warnings/Notices won't have the full stack trace shown even if the site is in devMode.


Headless CraftCMS: How can I tell Craft to load live preview from a different (sub)domain?

Since Craft 3.3.1, you can create a custom alias that resolves to your frontend base URL, and add that alias to the relevant preview targets' "URL Format" setting.

For example, assuming you put something like the below in your config/general.php file:

'aliases' => [
    '@previewBaseUrl' => 'https://domain.com',
],

...you'd be able to use that @previewBaseUrl alias in your preview targets, e.g. @previewBaseUrl/posts/{slug}


Environment variable doesn't work in Assets field settings

"Upload Location" doesn't reference you're environment variables. Instead, you've got a dropdown menu of your pre-defined Assets sources. Whichever one you choose will be used as the base of your file path.

Anything you put in curly braces after that will become a subfolder of that asset source. So your subfolder names will be created based on whichever Entry fields you define.


How to persist locale in site navigation?

Did you configure siteUrl in general.php, so Craft knows what the base URL is for your entries?

return array(
    'siteUrl' => array(
        'en' => 'http://craft.dev/en/',
        'cy' => 'http://craft.dev/cy/',
    ),
);