How to get started with ElementAPI & Ajax This is related to the question previously asked and answered by OP. I tried to follow this method but couple of things that I don't understand (and of course can't solve the issue because of that).

I have a page where I fetch data based on a field (it is text field whose values are mm/yy and then I need to look for data that belong to certain categories but that is for round 2). I have drop downs, click on year, then click on the month and that would be the filter for entries.

1: How to do I call the code (even though I tried using this code ElementAPI - Can I use javascript/ajax to load json). I have a button which is supposed to call news.json but nothing happen.
2: He is using _layout.html to put that ajax call. I have many pages where I need to fetch data with different parameters, so ideally I would like to have the ajax code in the template itself rather than _layout.html

What am I really asking is for a working example that I can look at as I find it very confusing at this point. Like how would I debug/ look at the return values from news.json?

Any help is appreciated.
Thank you

I don't think I quite understand, so I apologize in advance for what will be some revised answers.

news.json doesn't really exist. Meaning, I don't have a physical file called news.json in the filesystem anywhere. It is just an endpoint, and you'll want one for each of your calls.

For example: news.json or blog.json or events.json

  I have many pages where I need to fetch data with different parameters

That's no problem. I would still keep your javascript in the _layout template just to keep things clean. If you put js in each of your templates, you'll end up having chunks of js all over.

You can define different listeners for different things within a single docReady

$(function(){
    $('news').click(function(){
        // Ajax for news
    });

    $('events').click(function(){
        // Ajax for events
    });

    $('blog').click(function(){
        // Ajax for blog
    });
});

  Like how would I debug/ look at the return values from news.json

I use chrome for all development - so I'll right click anywhere and choose "Inspect Element". I'll then click on the network tab. That way I can see the XHR requests.

Once you click the button, you can see the request being made, and the response that is returned. It will look something like this:

 {"data":[{"title":"We just installed Craft!","url":"http:\/\/craftsandbox.dev\/news\/2016\/we-just-installed-craft","jsonUrl":"http:\/\/craftsandbox.dev\/news\/3.json"}],"meta":{"pagination":{"total":1,"count":1,"per_page":100,"current_page":1,"total_pages":1,"links":[]}}}

From there you will parse through the response and handle it however you want. In the past I've used things like mustache to keep the templates as clean as possible.

Hopefully this helps a little? Let me know and I can revise the answer to help get you rolling. There is much about the ElementAPI I am unfamiliar with myself, but since you were referencing a thread I answered I thought I'd try and help.


_entry.twig isn't reading css while index does This is the template im using and the index of the file is taking the css and printing it nicely however, the _entry.twig is only loading text, please check out the screenshots.

Below is the index of directory which loads css completely fine.

And one after is the _entry.twig which isn't taking any CSS.

Thanks!

Are you using a relative file path? Try to omit them where you can and see if it resolves?


How can I find users by field value? I have a field in my users of type user. This field holds a user's employer (another user).

How can I get a collection of all the employees in a plugin?

I tried craft()->users->relatedTo($currentUser); (where $currentUser is the employer) as that's pretty much how I'd do it in a template, but of course relatedTo isn't part of the usersService.

So how can I do this without just getting every user, checking their employer field and filtering out the matches?

ElementCriteriaModel supports 'users' as well as 'entries'.

$criteria = craft()->elements->getCriteria(ElementType::User);
$criteria->relatedTo = array(
    'targetElement' => $currentUser,
    'field'         => $employer
);
$employees = craft()->elements->findElements($criteria);


Matrix block Element API call on null error I get this JSON error when trying to output content of a matrix block called proLinks using the Element API.

  Call to a member function all() on null

The code is as follows (I've shortened it and removed the other content, this is the only one that I can't get to work):

<?php

use craft\elements\Entry;

return [
  'endpoints' => [
    'discproj.json' => function() {
      return [
        'elementType' => Entry::class,
        'criteria' => ['section' => 'dPs'],
        'transformer' => function(Entry $entry) {

          $linkBlocks = [];
          foreach ($entry->proLinks->all() as $block) {
            switch ($block->type->handle) {
              case 'external':
              $linkBlocks[] = [
                'externalTitle' => $block->externalTitle,
                'externalLink' => $block->externalLink,
              ];
              break;
            }
          }

          return [
            'projectLinks' => $linkBlocks,
          ];
        },
      ];
    },
  ]
];

I've looked at the other questions about this here, and they all seem to do things a little bit different from each other. I think I have the general structure, but there is obviously something missing.

I figured it out. Not every entry uses the matrix block, the error appears when the script hits that empty/non-existing block (null) it can't go looking for something inside it. Adding a conditional around the foreach solves it.

<?php

use craft\elements\Entry;

return [
  'endpoints' => [
    'discproj.json' => function() {
      return [
        'elementType' => Entry::class,
        'criteria' => ['section' => 'dPs'],
        'transformer' => function(Entry $entry) {

          $linkBlocks = null;
          if ($entry->proLinks) {
            foreach ($entry->proLinks->all() as $block) {
              switch ($block->type->handle) {
                case 'external':
                $linkBlocks[] = [
                  'externalTitle' => $block->externalTitle,
                  'externalLink' => $block->externalLink,
                ];
                break;
              }
            }
          }

          return [
            'projectLinks' => $linkBlocks,
          ];
        },
      ];
    },
  ]
];


Limiting form entries per day in FreeForm I am using freeform to manage forms on my site.

I'd like to limit the number of entries on a form to 200 per day.

The method I thought would be best is to get the submissions for the form, and use the dateCreated parameter to only return those that matched today's date.

Here's my code

{% set form = entry.form %}
{% set submissions = craft.freeform.submissions({
    form: form.handle,
    dateCreated: 'now' | date('d M Y')
}) %}

{{ submissions | length }}

But it isn't working. Am I getting the date parameter wrong?

I managed to get this working in the end. Here is my final code;

{# Calculate entries per day #}
{% set form = entry.form %}
{% set todaysEntriesIndex = 0 %}
{% set submissions = craft.freeform.submissions({
    form: form.handle
}).all() %}

{# Count each submission from the day #}
{% for submission in submissions %}
    {% if submission.dateCreated | date('d/m/Y') == 'now' | date('d/m/Y') %}
        {% set todaysEntriesIndex = todaysEntriesIndex + 1 %}
    {% endif %}
{% endfor %}

Once this has been setup you can use the following to check the amount:

 todaysEntriesIndex >= 200


Set Up Route to Template - then variable Entry is undefined I've got a blog listing channel set up where I'm trying to filter entries listed by the entries field blogAuthors based on url segment.

/articles-and-excerpts/ loads the blog fine

added a route

but when I go to a page like this /articles-and-excperts/author/john-doe I see errors until I add this to the template

{% if entry is not defined %}
    {% set entry = craft.entries.section('blogListing').one() %}
{% endif %}

Then it works correctly. Why doesn't Craft recognize that this is the blogListing channel?

Also even though this works and displays the content SEOmatic doesn't recognize it now either.

Ultimately I need the following to load on this template:

/articles-and-excerpts/
/articles-and-excerpts/author/author.slug
/articles-and-excerpts/category/category.slug
/articles-and-excerpts/category/category.slug/author/author.slug

Currently I have categories using a separate template but haven't attempted to add in the author filtering.

Is there a better approach to this? I had started trying to combine url segments and a query string, but got stuck there as well Filtering entries by category and author channel

Variables like entry are only auto-injected for routes that match the Section's Site Settings routes:

If you're using custom routes, they won't match, and you'll need to set entry (or whatever) yourself manually. SEOmatic uses the same Craft mechanism for recognizing injected entrys (or whatever), so the same applies there. Vide: Rendering Metadata From Another Route


How to filter entries by multiple checkbox field types I've set up checkbox fields for photos in a photo gallery called "photoColor", "photoSubject", and "photoSize", all of which contain a bunch of options.
On the gallery page I have filters and I'm using Ajax to update the page when a checkbox is clicked.
<div id="filters">
 <input type="checkbox" name="colors[]" value="red" /> Red
 <input type="checkbox" name="colors[]" value="green" /> Green

 <input type="checkbox" name="subjects[]" value="human" /> Human
 <input type="checkbox" name="subjects[]" value="animal" /> Animal

 <input type="checkbox" name="sizes[]" value="small" /> Small
 <input type="checkbox" name="sizes[]" value="large" /> Large
</div>

I'm gathering the values of the checkboxes like this
  var colors = [], subjects = [], sizes = [];
  $('input[name="colors[]"]:checked').each(function() {
     colors.push($(this).val());
  });

  $('input[name="subjects[]"]:checked').each(function() {
     subjects.push($(this).val());
  });

  $('input[name="sizes[]"]:checked').each(function() {
     sizes.push($(this).val());
  });

Right now I can filter for one option of one field type, i.e. this works:
{%  set galleries = craft.entries.section("gallery").photoColor(value) %}

(where value = "red" for example)
But I'm struggling to figure out how to write the query to combine ALL 3 field types in an "or" query, i.e. the results only need to match one of those properties, not all of them.
In other words, if a user checks off red, green, animal, and small, it will show all the results matching either red, green, animal, OR small - not just red/green animals that are small.
In pseudo code, it would be something like:
{% set galleries = craft.entries.section("gallery")
  where .photoColor is red or green
   or .photoSubject is animal
   or .photoSize is small
%}

I've been searching StackExchange and trying things I saw in other answers for days, but none of the situations were quite like mine, so I haven't been able to get it to work. Can someone point me in the right direction? Any help is greatly appreciated.

Apologies if I’ve misunderstood your question and over-simplified things, but wouldn’t the search() method give you precisely what you need?
As in:
{% set valsToFind = "field_photoColor:red OR field_photoColor:green OR field_photoSubject:animal OR field_photoSize:small" %}
{% set galleries = craft.entries.section("gallery").search(valsToFind).all() %}


In Commerce how can I have a customer update custom fields on an order after the order is completed? I'm using Commerce, and Orders can have a custom field on them. I need customers to be able to update that field from a front end form. I can't use the built in contoller for Orders because that requires Admin users.

Create a new plugin with a new controller class that enables this.

e.g.,

plugins/myplugin/MyPlugin.php

<?php
namespace Craft;
class MyPlugin extends BasePlugin
{
    ... the usual stuff from https://pluginfactory.io/ etc ...
}
?>

plugins/myplugin/controllers/My_OrdersController.php

<?php
namespace Craft;

class My_OrdersController extends BaseController
{

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

        // get the fields
            $orderNumber = craft()->request->getPost('orderNumber');
            $customField = craft()->request->getPost('customField');
            $order       = craft()->commerce_orders->getOrderByNumber($orderNumber);

        // do the stuff
            if ($order &&
                $order->customer->userId == craft()->userSession->getUser()->id &&
                $customField != '')
            {
                    $order->setContentFromPost(['customField'=>$customField]);

                    // Lets also change the Order Status
                        $order->orderStatusId = 3; // this line changes the Status if wanted. Use the ID of the custom status.
                        $order->message = "Order status changed to 'To be cancelled' by customer";

                    craft()->commerce_orders->saveOrder($order);
            }
    }
}

Front end form:

<form action="" method="POST">
    <input type="hidden" name="action" value="myplugin/orders/updateOrder">
    <input type="hidden" name="redirect" value="shop/customer/order?number={{ number }}">
    <input type="hidden" name="orderNumber" value="{{ number }}">

        Custo Field
        <input type="text"
                name="customField"
                value="{{ order.customField }}"
        />

    <input type="submit" class="button warning" value="Confirm"/>
</form>


Solspace Calendar For Craft CMS - Importing ICS Files I'm using Solspace Calendar for Craft CMS for an upcoming project.

The client has asked if they can initially import all of their events from an .ics file from Outlook.

I can't see anything in the docs. It doesn't appear to be a feature, however has anyone else come up with a solution to this? I'm sure it's not the first time it's been asked.

Thanks :)

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

source: Kelsey Martens, Director of Software Operations


Check if a Relationship field has a relationship without extra query Is there any way to check if a relationship field has a value/is assigned to other elements (assets/entries) without having to add an extra query?

I have a Channel with an Asset field assigned to it. Now let's say I have a list of 100 entries. This list should show a thumbnail and the entry title. I only want to "fetch" the related image thumbnail if the user has choosen to select any image to reduce the amount of queries used.

The "standard" way which results in ~100 queries

{% set image = entry.image.first() %}
{% if image %}

{% endif %}

The way I tried it, but |length adds (1) query making it ~100 queries + the queries for each found thumbnail

{% if entry.image|length > 0 %}
    {% set image = entry.image.first() %}

{% endif %}

Is there a third option I can use to check (without a query) is the entry.image has any related content assigned to it?

Thank you

There isn’t currently, but it’s on our list to make it possible.

UPDATE

As of Craft 2.5, you can set relational field params to 'not :empty:' or ':notempty:' to only show elements where something is selected within the field; and you can set them to ':empty:' to only show elements where nothing is selected within the field.


Preview PDF doesn't work in Safari but works in other browser I'm trying to figure out why I am able to preview a PDF in all other browser apart from Safari. The PDF is generated using DOMPDF (printmaker plugin) and output to the browser though PHP using Craft CMS.

An example of the PDF is https://kendal.ac.uk/courses/2018.pdf

Any help with this would be greatly appreciated

I think this question does not really belong here but I'll answer it anyway. Sarafi changed the way it displays PDF documents. You can see instructions from Adobe how to enable the browser view. Besides that you have not really a chance to force other Safari users to open PDFs in their browsers. You can as well see other multiple other discussions about it the Apple Forum


Login redirect is not working I am currently trying to make it so when I have logged in on my website as a user it redirects to a certain page.

However it is not working.

I have tried adding the following redirect in the configuration file however no luck:

'postLoginRedirect' => 'profile/test'

Any tips or suggestions will be appreciated.

Thanks guys. I solved it.
The issue was that I was logging in as the admin not an ordinary user.


Craft URLs intermittently being cached as /index.php/my-page/ or /index.php?p=my-page Cross-posting from here, as I'm not sure if this is a Craft issue or specific to the cache-clear plugin.

Intermittently (twice in a day now), I've seen templates being cached with Craft URLs outputting as either /index.php/my-page/ or /index.php?p=my-page

Once this happens, clearing cache via the plugin url (http://domain.com/actions/cacheClear/clear?key=myKey) doesn't seem to fix anything, but clearing cache in the control panel does.

Any ideas?

There is an explanation of why this can occur on the Craft help section here: http://buildwithcraft.com/help/why-index.php


PNG-8 upload to S3 hangs We're having trouble uploading PNG-8s. PNG-24s and JPGs work fine, but after selecting a PNG-8 to upload, the progress bar appears and fills to max in a couple of seconds, but then hangs indefinitely. Sometimes a message appears saying "Upload failed for 'filename.jpg'", sometimes it just hangs with no error message. If we then refresh the page, the image is in the assets list but no thumbnail has been created for it. The PHP error log gets this:

[03-May-2017 14:03:48 UTC] PHP Fatal error: Maximum execution time of 30 seconds exceeded in /home/sitename/webapps/sitename/craft/app/vendor/pixelandtonic/imagine/lib/Imagine/Imagick/Image.php on line 313

We could of course make them all PNG-24s but the file size is often way higher.

We're on Craft 2.6.2958, and the assets are on Amazon S3. Any advice on how to diagnose this would be much appreciated!

To fix that particular error, you'd need to bump your php.ini file's max_execution_time setting to something higher than 30 seconds to allow more time for the request to complete.


Filtering by categories AND tags with full match We're trying to filter by categories AND tags in the one form. However can't seem to get things working as we would like.

Essentially, we have a form that pulls in the tags and allows multiple filtering dropdowns. The below is out results page code, which outputs odd results. We need all params to match the entries categories/tags but it just doesn't work as expected. Where are we going wrong?

    {# Get params #}
    {% set mainCategory = craft.app.request.getParam(‘category’) %}
    {% set season = craft.app.request.getParam(‘season’) %}
    {% set age = craft.app.request.getParam(‘ages’) %}

    {# Set arrays #}
    {% set mainCat = mainCategory ? craft.categories.group(‘courseCategories’).slug(mainCategory).all() %}
    {% set seasonCat = season ? craft.tags.group(‘season’).slug(season).all() %}
    {% set ageCat = age ? craft.tags.group(‘ageRange’).slug(age).all() %}

    {# Set relatedTo #}
    {% set categoryParam = mainCat ? {targetElement: [‘and’]|merge(mainCat)} %}
    {% set seasonParam = seasonCat ? {targetElement: [‘and’]|merge(seasonCat)} %}
    {% set ageParam = ageCat ? {targetElement: [‘and’]|merge(ageCat)} %}

    {# Get entries #}
    {% set relationParams = [categoryParam, seasonParam, ageParam]|filter %}
    {% set entries = craft.entries({
        section: ‘courses’,
        relatedTo: relationParams ? [‘and’]|merge(relationParams) : null
    }) %}

You are always one level too deep. Craft is able to proceed parameters like

[
    'and',
    ['targetElement' => [1, 2, 3],
    ['targetElement' => ['or', 1, 2, 3],
    ['targetElement' => 1],
    ['targetElement' => ['and', 1, 2, 3]
]

And so on.
Yours is

'targetElement' => ['and', [1,2,3]]

I would suggest you to dump your array

<pre>
{{ dump(array) }}
</pre>

To see the result. If you don't care about performance just using .one() instead of all() might solve the problem.


Plugin to report when site becomes unavailable I have a Craft installation on DigitalOcean, with the smallest package:

512MB Memory
1 Core Processor
20GB SSD Disk
1TB Transfer

I installed the default LAMP droplet.

PROBLEM:
MySQL crashes from time to time. There were no significant server load either.

What might be a root cause?

Bonus question:

Is there a plugin that automatically reports when the site is down?

There's no plugin for that... it wouldn't quite make sense. If the site went down, the plugin would be down too.

Your best bet is to find a 3rd party service to monitor the site's uptime. There are several services which will alert (via text or email) if your site becomes unavailable. Here are a few examples...

Uptime Robot
New Relic
Pingdom


Possible to redirect elsewhere after saving an entry? I'm editing an entry in the CP...

mysite.com/admin/entries/mySection/33-my-awesome-entry

Now when I save this entry, it will redirect me back to the entry index page. However, I'd like to override this behavior, and get redirected to a different page upon saving.

Is it possible to override the redirect target when saving an entry?

Yes!

Assuming you're using some sort of business logic plugin (if you don't have one, get one), then simply put this code in your main *Plugin.php file...

public function init()
{

    // Trigger template hook
    craft()->templates->hook('cp.entries.edit', function(&$context)
    {

        // Check to ensure that you're in the right section
        if ('mySection' == $context['sectionHandle'])
        {

            // Specify the preferred URI
            $uri = 'special-page/'.$context['entry']->uri;

            // Set the "Save" button redirect
            craft()->templates->includeJs("
                $(function () {
                    $('input[name=\"redirect\"]').val('{$uri}');
                });
            ");

            // Set the `cmd + s` shortcut redirect
            $context['saveShortcutRedirect'] = $uri;

        }

    });

}


How can I show next/previous paging that's limited by specific criteria? I'm adding prev/next links to a detail page and can't get craft.entries to return the correct entries.

Specifically, I need craft.entries to return entries in the "leadership" section where the leadershipType field matches the current entry's leadershipType value.

My code returns all entries instead of the ones specific to my field parameter.

{% set params = craft.entries.section('leadership').find({ leadershipType:entry.leadershipType }) %}

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

{% if prev %}&lt;{% endif %}
{% if next %}&gt;{% endif %}

You can only pass an object or an ElementCriteriaModel (what you get when you type 'craft.entries') into getNext() and getPrev().

Calling find() on an ElementCriteriaModel, as I'm doing in my code, turns it into an actual array of entries, which is not something getNext() and getPrev() can work with.

So changing the first line to this will work:

{% set params = craft.entries.section('leadership').leadershipType(entry.leadershipType) %}

Or this using the object syntax for setting parameters:

{% set params = craft.entries({
    section: 'leadership',
    leadershipType: entry.leadershipType
}) %}


Problems with tasks and max execution time We've set up a task that's supposed to run through an external folder with images and resize them into 3 sizes each. This results in about 13000 tasks (one task per image). I thought each task was on a separate thread? But now the tasks are running for only 60 seconds (max_execution_time), then stopping. The task says running in the database, but it has just stopped, and the error log says max execution time was exceeded.

Is there a way around this? Would sub tasks change any behaviour?

Tasks are just another PHP request and they are subject to the same web server and php.ini limitations as a "normal" request.

Sounds like you just need to up your max_execution_time.


Password Reset via SMS Is it possible to send the Password reset email via SMS instead of email? I'm signing users up using their mobiles and a 6 digit pin + a randomly generated email.

Not natively, but there are some SMS related plugins for Craft 3 that might be useful.

https://github.com/bertoost/Craft-3-Mailjet

https://github.com/bertoost/Craft-3-Messagebird

Otherwise, you're looking at a custom developed plugin specific to your needs.


Front end profile does not save data - form action I've been having trouble getting a front-end profile template to save any data.
It was quite complex so I've gone back to a base install of Craft with no custom fields for a User.

Using the example code from the docs it still doesn't save any data.
http://buildwithcraft.com/docs/templating/user-profile-form

This is running the full version of Craft on localhost.

I have a custom route of /profile set to a template called 'profile'.

Loading the page loads all currently stored data exactly the same as the CP.

Submitting the form reloads the page but none of the input data is saved and redisplayed. Going to the CP also shows nothing was saved.

After a few hours of trouble-shooting I discovered, on submit from the front-end template, the saveUser method was not running. It was from the CP.

Adding action="{{ siteUrl }}" to the form gets it working. But oddly then introduces the front controller in to the URL after submit, eg. http://localhost/index.php/profile.

There's no mention in the example code of a form requiring an action value. I can't work out why the example code doesn't work or why I need action. I'd rather not have the pretty URLs messed up.

Help?

Profile

<form action="{{ siteUrl }}" method="post" accept-charset="UTF-8" enctype="multipart/form-data">

    {{ getCsrfInput() }}

    <input type="hidden" name="action" value="users/saveUser">
    <input type="hidden" name="redirect" value="profile">
    <input type="hidden" name="userId" value="{{ currentUser.id }}">

    <fieldset>
        <legend class="visually-hidden">Personal details</legend>

        First name *
        <input id="firstName" type="text" name="firstName" value="{{ currentUser.firstName }}" placeholder="Jane" required="required" aria-required="true" autofocus="autofocus">

   </fieldset>

    <input type="submit" value="Save Profile">
</form>

Update 10-08-2015

The profile form submitting seems to be a red-herring. When installing Craft I couldn't get it to work with clean URLs so I edited Apache's config to set 404s to redirect to crafts index.php. I'd since forgot. Local config:

Mac OS X 10.10.4
MAMP (not pro)

By default MAMP has AllowOverride None. That was stopping the .htaccess file from working. I'm using vhosts so I've manually set this in the vhost config. Another gotcha is Crafts config of omitScriptNameInUrls and usePathInfo. Craft caches test results for 24 hours, so I had to clear the cache before my updated vhost config worked.

<Directory "/path/to/craft/public">
    Options FollowSymLinks
    AllowOverride All
    Order Allow,Deny
    Allow From All
</Directory>

The title of this SE question is all wrong now but it's valuable info. OK to change? I'd also say this is a common enough set-up to be in the official docs?

The answer is now included in the question. Don't be a dingbat and make sure MAMP or Apache (or whatever webserver you're using) is configured properly.


how to output all images in an entry's loop Unfortunately I'm still very new to Craft, but I have a question to which I haven't found an answer here or in the Docs or the ones I found don't seem to work in my case.

I want to output all the images for each entry in this loop and I don't understand how I get the "set image = entry.startbilder" to work that way?

I understand that ".one()" only outputs the first image but how do I change that to output all images? changing that to ".all()" results in an error.

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

        {% set image = entry.startbilder.one() %}
        {% if image %}

        {% endif %}

{% endfor %}

thanks in advance for any help!

You should use .all(), but that will give you an array of Assets. You can't call .getUrl() on an array, so you'd have to loop that array:

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

        {% set images = entry.startbilder.all() %}

        {% if images |length %}
            {% for image in images %}

            {% endfor %}
        {% endif %}

{% endfor %}

If you'd want to eager load the images, this is how you'd do it:

{% for entry in craft.entries.section('projekte').with(['startbilder']).all() %}

        {% if entry.startbilder |length %}
            {% for image in entry.startbilder %}

            {% endfor %}
        {% endif %}

{% endfor %}


How to search on multiple (custom) fields using Element API I am using the Element API to search for entries that match a search query: either the title OR the excerpt should contain the query term. The entry is very simple and has these fields:
-title
-excerpt
-link
when I use this to only search in the title field it works:
$section_handle = ['item'];
$q = Craft::$app->request->getParam('query');

$criteria = [
   'section' => $section_handle,
   'search' => 'title:'.$q
];

So I thought I just add the excerpt field like this:
$criteria = [
   'section' => $section_handle,
   'search' => 'title:'.$q.' OR '.'excerpt:'.$q
];

but this did NOT work and I found out that it just won't search that excerpt field, this also does not work:
   $criteria = [
   'section' => $section_handle,
   'search' => 'excerpt:'.$q
];

After some research I found out that when I use this as the 'criteria' it works:
$criteria = [
    'section' => $section_handle,
    'excerpt' => "*{$q}*"
];

And now I wonder how to proceed. How can I either get the first example to work to search in the excerpt field, or add the OR title clause to my latest example where I am able to search in the excerpt field...
I hope this makes sense and that someone can point me in the right direction!
Thanks very much,
Wouter

In your last example:
$criteria = [
    'section' => $section_handle,
    'excerpt' => "*{$q}*"
];

You are making a fuzzy search by surrounding your keyword(s) with * (see docs for syntaxes) and I wonder if that's why you are seeing results (I'd need to see the keywords/entry).
However, if that works, then this should work for you:
'criteria' => [
    'section' => $section_handle,
    'search' => ($q ? 'title:' . $q . ' OR '.'excerpt:*'. $q . '*' : null),
],

Alternatively, make everything fuzzy (not as precise):
'criteria' => [
    'section' => $section_handle,
    'search' => ($q ? 'title:*' . $q . '* OR '.'excerpt:*'. $q . '*' : null),
],

One final thought, if your section has three fields, if you only check Use this field’s values as search keywords on your Settings → Fields → excerpt field then you can search on both title + excerpt simply by doing:
'criteria' => [
    'section' => $section_handle,
    'search' => ($q ?? null),
],


Entry not saving through command line I'm trying to create a command line function, in my plugin, to import some data into entries. The problem is that the Craft\EntriesService->saveEntry() method seems to call the Craft\TemplatesService->renderObjectTemplate() method which uses the SERVER_NAMEconstant. Obviously there is no SERVER_NAME because the application is being run from the command line.

Is there a way to manually set this, or can this be bypassed in any other way?

I will include my stack trace here as well:

PHP Error[8]: Undefined index: SERVER_NAME in file myproject/craft/app/framework/web/CHttpRequest.php at line 352
0 myproject/craft/app/etc/console/ConsoleApp.php(252): Craft\ConsoleApp->handleError()
1 myproject/craft/app/framework/web/CHttpRequest.php(352): Craft\ConsoleApp->handleError()
2 myproject/craft/app/services/ConfigService.php(420): Craft\HttpRequestService->getHostInfo()
3 myproject/craft/app/helpers/UrlHelper.php(422): Craft\ConfigService->usePathInfo()
4 myproject/craft/app/helpers/UrlHelper.php(196): _getUrl()
5 myproject/craft/app/etc/templating/twigextensions/CraftTwigExtension.php(493): getUrl()
6 myproject/craft/app/vendor/twig/twig/lib/Twig/Environment.php(1276): Craft\CraftTwigExtension->getGlobals()
7 myproject/craft/app/vendor/twig/twig/lib/Twig/Environment.php(1200): Craft\TwigEnvironment->initGlobals()
8 myproject/craft/app/vendor/twig/twig/lib/Twig/Environment.php(1217): Craft\TwigEnvironment->getGlobals()
9 myproject/craft/app/vendor/twig/twig/lib/Twig/Template.php(355): Craft\TwigEnvironment->mergeGlobals()
10 myproject/craft/app/vendor/twig/twig/lib/Twig/Template.php(366): __TwigTemplate_5f77fd774cac1595e134b05c66db80e7998372598504ff29b7e2487f820a3d8c->display()
11 myproject/craft/app/services/TemplatesService.php(336): __TwigTemplate_5f77fd774cac1595e134b05c66db80e7998372598504ff29b7e2487f820a3d8c->render()
12 myproject/craft/app/services/EntriesService.php(157): Craft\TemplatesService->renderObjectTemplate()
13 myproject/craft/plugins/myplugin/services/Myproject_SomeService.php(312): Craft\EntriesService->saveEntry()
14 myproject/craft/plugins/myplugin/services/Myproject_SomeService.php(280): Craft\Myproject_SomeService->update()
15 myproject/craft/plugins/myplugin/consolecommands/ImportEmployeeCommand.php(24): Craft\Myproject_SomeService->createOrUpdate()
16 unknown(0): Craft\ImportCommand->actionImport()
17 myproject/craft/app/framework/console/CConsoleCommand.php(172): ReflectionMethod->invokeArgs()
18 myproject/craft/app/framework/console/CConsoleCommandRunner.php(71): Craft\ImportCommand->run()
19 myproject/craft/app/framework/console/CConsoleApplication.php(92): Craft\ConsoleCommandRunner->run()
20 myproject/craft/app/framework/base/CApplication.php(185): Craft\ConsoleApp->processRequest()
21 myproject/craft/app/etc/console/yiic.php(81): Craft\ConsoleApp->run()
22 myproject/craft/app/etc/console/yiic(4): require_once()

I'm assuming you're using a multi-environment config.  From wherever your plugin is bootstrapping yiic, you need to manually set the CRAFT_ENVIRONMENT PHP constant to the environment you want yiic to load in the config files.


CP assets uploads are reverse ordered after upload Problem
CP assets uploads are reverse ordered after upload.
Description
I have a folder with 5 images:

1.jpg
2.jpg
3.jpg
4.jpg
5.jpg

I want to upload these images in the Craft CP. I have an Asset field and add the images by clicking the ‘Add an asset’ button. When I'm done the order of the images in the field is:

5.jpg
4.jpg
3.jpg
2.jpg
1.jpg

Example
Before upload:

After upload:

Question
Is there a way to upload assets in the same order?

Did some more tests. In my finder I have two files:

1.jpg
2.jpg

When I upload these files, 1.jpg is uploaded first and 2.jpg second. In the control panel 2.jpg is the latest uploaded file and therefore the first visible asset. This clarifies the reversed order.
A little trick when uploading multiple files from the finder and keeping the same order, is to reverse the file order in the finder (start with Z and end with names starting with A).


Element API - Entries Related to a Category In Craft 3, I want to list all the categories in a group and all the entries related to them. How can I do this?

The slower but easier approach is to fetch all of them and search for related entries

'elementType' => Category::class,
'criteria'    => [
    'group'   => 'yourGroup',
],
'paginate'    => false,
'transformer' => function(Category $category) {
     $entries = Entry::find()
        ->relatedTo($category)
        ->select(['title'])
        ->asArray()
        ->column();

    return [
        'title'   => $category->title,
        'entries' => $entries
    ];
}

Learn more about Element Queries especially the different ways to fetch entries via one(), all(), column()


Can the HTTP status be set with the redirect tag Although undocumented, according to this answer How do I force a 301 http status code using the redirect tag? adding a 301 parameter to the redirect tag should change the status. I am using this but am still getting a 302 status.

{% redirect entry.getChildren().first().url 301 %}

Should this work to create a 301?

That should work fine.  I just did a test in a simple template with:

{% redirect "http://google.com" 301 %}

And I can see it's a proper 301 redirect.  Try clearing your browser's cache?


Password Update form accepting any data for currentPassword I'm adding an update password form. This is not a reset password in case of a forgotten pw, but a form that allows users to update at their leisure. I have the current password field name="currentPassword" and the new password field name="newPassword".
When I run the form locally, it works as expected, and does not save the user when the currentPassword value is incorrect. When I run it on our production site, the current password field accepts any value at all, still saves, and changes the password to the new password value despite the current password not being correct. Is there some environment setting I could be missing here that's responsible for this?
Running Craft 3.4.30, no Commerce.

If the user already has an elevated session then they do not need to enter their current password. You can see the relevant code for this check here:
https://github.com/craftcms/cms/blob/bd3820f19a0680c635a89c7f16805299964d97f2/src/controllers/UsersController.php#L1713-L1721
That is the only explanation I can come up with for the difference in what you are seeing locally and in production.


Complete user profile after social public registration I use Dukt plugins (-oauth and -social) for public front-end registration. I would like complete user profile after registration (e.g. license agreement checkbox).

How is it possible to accomplish this?

I would like intercept social callback after authentication and show a custom page.... I suppose OnBeforeSave event is not useful for this scenario. Thanks

Via https://dukt.net/craft/social/docs/templating/craft.social#getLoginUrl you may give up a page like { redirect: 'user/finish' } on which you could check if a user agreed to the license agreement and if they have redirect them to the regular page.

Here is an example profile edit page that might be useful https://github.com/dukt/social-demo/blob/master/craft/templates/social/profile.html


FeedMe plugin and weather.gov XML This should have been simple.  A client's site is required to display current weather observation data retrieved via XML from w1.weather.gov.  My solution was to use the on-demand features of FeedMe in a twig template to accomplish this.

As it turns out, weather.gov recently began requiring inclusion of a user agent string in the header to identify the requestor of any XML feed.  If no user agent string is present, it returns error 403.

Is it possible to configure Craft or FeedMe to send a custom user agent string in all GET requests for external data?

This would be up to the FeedMe plugin.

It looks like they're using cURL directly, so they would need to either directly set CURLOPT_USERAGENT or allow for it to be configured via a setting.

Feel free to create an issue / pull request on their repo.


What would prevent my assets from reindexing on a local MAMP install Having an issue with assets not reindexing from the Update Asset Indexes option.  If I add new folders to the file system they do not appear after I run the Update Asset Indexes, if I upload them manually in the backend then they do appear as normal.

How would I diagnose this?  Running Apache as my logged in user so it's does not seem to be a group / permissions related issue.

If the Update Asset Indexes fails on a MAMP install, double check to make sure ALL assets source paths are correct and exist on the file system.

I had defined a asset source to a folder which I had planned on using but had not yet created on the file system, and this caused the Update Asset Indexes to fail w/o any warning messages, save for a JS error in the console.


Listing all available default variants Folks:

I figured this would be simple but apparently not (for me, anyway).

I have a product with two variants (orange and yellow).
I have a page that lists all the available products.
On that page, both variants appear. I really just need one and users
can select their variant from a drop-down on the checkout page.

What I've got:

{# get the products from the categories #}
{% set products = craft.commerce.products.type('shirts,shorts') %}

{# show the product main image and link to the product page #}

    {% if product|length %}
        {% set asset = product.productHeroImage.first() %}
    {% endif %}

I did try {% set products = craft.commerce.products.defaultVariant.type('shirts,shorts') %} but get the same results.

OK, so this did have a really simple solution. Just use isDefault.

{% if variant.isDefault %}Show the product{% endif %}

Works like a charm.


How to add content to pages using a plugin? I am developing a plugin for Craft 3. And I am trying to add some content to all pages in the CMS using this plugin. How can I do that? Is there a method or class call I can use for this? I am not sure where this is mentioned in the docs either.

Basically I want to add a few lines of HTML, CSS and JS in all the pages of the CMS if my plugin is installed and enabled in that Craft installation. Any ideas, anyone?

If you are able to place a hook tag in all templates then you could register a new template hook method in your plugin.

Twig:

{% hook 'my-custom-hook-name' %}

Your plugin:

Craft::$app->view->hook('my-custom-hook-name', function(array &$context) {
    $context['foo'] = 'bar';
    return '
Hey!
';
});

For injecting CSS or JS you would use

\Craft::$app->getView()->registerCssFile("file.css");
\Craft::$app->getView()->registerJsFile("file.js");

If you can't modify the template files to place a hook tag there you could dynamically generate the markup in your JS file, depending on your use case.


Freeform unsubscribe and redirect non admin users away from admin area Good Evening all,
I have a site that lets users subscribe/unsubscribe using Freeforms Stripe payments.
Everything is working fine, except for when the user unsubscribes, the link that is required is within the Craft Dashboard, therefore the user has to have a basic amount of panel access, which I want to avoid if possible, however as a fix, is there any way of redirecting non admin users away from the login/dashboard if they type /admin?

Sorry for the trouble. This is a known issue and we will have a fix for this available in Freeform 3.10.8 in a few days (February 15-16, 2021). :)


How to convert Unicode in a field I imported German text through Feed Me, but the special characters show up as unicode characters:

“Ich interessiere mich sehr f\u00fcr Alte Musik”

I tried a filter when outputting the text, but no success: |convert_encoding("ISO-8859-1","UNICODE-1-1")
However, would prefer to have the text be readable in the backend as well not just on the frontend with the filter.
Any help would really be appreciated!

If this were PHP, you'd need to run that through html_entity_decode to get it to convert.
I don't think there's an equivalent way to do that from Twig, but you could write a simple plugin that added an htmlentitydecode Twig filter to pull it off.


Change Freeform redirect URL according to checkbox field Is it at all possible to set a different Redirect URL on a FreeForm form if a checkbox is checked? To summarise, I have a FreeForm form which contains a checkbox. I would like the submission redirect URL to differ depending on whether or not the checkbox is checked.

Can anyone shed any light on this and offer some advice?

Thanks

This should be doable. If you have a field in your formatting template with the name formReturnUrl, when checked, it would override the Freeform return URL. You'd likely need to manually hardcode this into your form template code though:

<input type="checkbox" name="formReturnUrl" value="{{ siteUrl }}freeform-demo/bootstrap/my-url" />


Enabling Assets Image Edit Option for Assets in Amazon S3 What do I need to do in order to enable Image Edit option for Assets stored in Amazon S3?

The issue was with Imagik configuration. GD worked fine.

I fully remove Imagik, and reinstalled with it with default settings.

brew remove php71-imagik && brew services restart php71


Read POSTed JSON data from the request body Is there a way with the request service to read POSTed JSON from php://input?

Yes, you can use getRestParams() like so: $input = craft()->request->getRestParams()

A bit confusing naming there, which is why it's changing to getBodyParams() in Yii 2.


Craft Commerce: Soft Delete on Payment Methods? I was just playing around with my payment methods. I deleted them. Then I tried to re-add them with the same names and settings but I couldn't. "Name "Manual" has already been taken."

Apparently they have been soft deleted? How do you reinstate a soft delete?

Commerce soft deletes payment methods instead of hard deletes them because even if a payment method is no longer in use, you still need to be able to have a reference to them for existing orders.

You can "un-delete" the payment method by going into the craft_commerce_paymentmethods table in the database and changing the isArchived column from 1 back to 0.


Page with Matrix field slow to load I am fairly new to Craft CMS but have a good understanding of it. I have a page that has a Matrix field to display staff photos and their roles.

On the initial load of this page, it is slow, it takes nearly 22 seconds. It is only 1meg of data.

Some stats on the initial load:
• DB queries 200
• 22 seconds to load

Once it has been loaded into the cache it is much better:
• DB queries 165
• 1.6 seconds to load

I have tried eager loading the image field and image transform with no speed increase:

{% set teamMembers = entry.teamMembers.with([
        ['blockType:image', {
            withTransforms: ['teamMemberSmall']
        }]
    ]).all()
%}

It's not a huge amount of data so I would have thought this could be much faster. Based on the profiling it looks like it is the asset transform generation that is killing the page. Any tips or tricks I can do to get that initial page load faster? Can the assets be pre-generated?

Server stats:

PHP 7.2
MYSQL 5.5
Memory Limit 256mb

I used to have the same issue then I started using Eager Loading Element. It allows you to speed up your craft cms templates by fetching matrix from the database more efficiently.

You can refer to this link which might help you for further understanding of Eager Loading.


Check to see if category is populated? I want to list all categories that have an entry assigned to them, but hide the ones that are empty.

In EE I could do this show_empty="no"

But I can't see a parameter in the docs for Craft.

Currently I've found that I could use relatedTo but with passing an object with up to 600 entries it dies with caching tags :(

Is there a better way of doing this? This is what I've got at the moment:

{% set blogPosts = craft.entries({section:'blog',limit:null}).find() %}

{% for cat in craft.categories({groupId:2}).relatedTo(blogPosts) %}

{{cat.title}}

{% endfor %}

There is a great tutorial over at Straight Up Craft for handling this (it is however very similar to what you have - it may speed things up a tad though).

  First, we want to grab all of the entry ids from the Section of
  content which we want to display categories for.

  {% set entryIds = craft.entries.section('blog').ids() %}

  Next, we will use the craft.categories tags relatedTo() method to only
  return categories that have a relationship with one of our entry ids.

  {% set categories = craft.categories.relatedTo({ sourceElement:
  entryIds }).groupId(1).find() %}

  Once we have our list of categories that are in use, we can loop
  through those categories and display them in our template:

{% for category in categories %}

{{ category.title }}

{% endfor %}


How do you find more documentation about queries, services, plugins, etc? So I've been having so much trouble finding adequate examples of how to do things when writing a plugin. How do you find more?  (see below for my own answer)

Click on the little triangle! It gives nice examples.


registerCpRoutes gives 404 In my main plugin file I have the following code in my registerCpRoutes fucntion:

public function registerCpRoutes()
{
    return array(
        'campaignreports/subscribers/detail\/(?P<listId>\d+)' => 'campaignreports/subscribers/_detail/'
    );
}

I have a _detail.html template located in /templates/subscribers/_detail.html

For some reason this doesn't seem to work. I keep on getting a "Page not found" error.
As far as I can tell I have followed the docs on dynamic routing
Any ideas on what is going wrong here?

PS: I have uninstalled & reinstalled the plugin

Not sure why you are escaping the / right in front of the regex. Maybe thats the issue?


Filter Entries by Matrix Block I have a matrix field with two block-types ("sound" and "video")
I want to get all entries that have a matrix field with a certain block-type.
At the moment I have:
{% set entries = craft.entries()
        .section(['events', 'sessions'])
        .orderBy('datum desc')
        .matrixField(':notempty:')
        .limit(30)
        .all() %}

how can i get all entries that have a "video"-block in the matrix-field?
I want to paginate the results.
Thanks!

You'll have to query all matrixes in that field with that type first. With these results, you should then be able to query the entries that are relatedTo these results.
You'll end up with
{% set matrixes = craft.matrixBlocks()
    .field('matrixField')
    .type('video')
    .all() %}

{% set entries = craft.entries()
    .section(['events', 'sessions'])
    .orderBy('datum desc')
    .matrixField(':notempty:')
    .relatedTo(matrixes)
    .limit(30)
    .all() %}

Documentation about relations can be found here


Search entries AND within associated assets fields I have a large list of entries. Each entry has a a bunch of fields and a file-field with one or two files. Those files have related field (Author, Date, ..).

I have now implemented a search. All things are working so far. However, the search does not include the asset's fields. Only the asset's title is recognized.

Can I somehow search in asset fields? I tried something like

field1: *query* AND files.author: *query*

but this does not work :(

I have read that I can search all assets that are related to that section, but I would like to include this query in one query than in two queries..

I have now found a workaround using the information @brad-bell provided, that is working, but not exactly what I wanted:

{# Normal search #}
{% set resultsA = craft.entries(search_criteria).ids() %}

{# Assets search #}
{% set assets = craft.assets.customFieldName('*'~query~'*') %}
{% set resultsB = craft.entries.relatedTo({
        targetElement: assets,
        field: 'customFieldName'
    }).ids() | without(resultsA) %}

{# Merge results, paginate #}
{% set results = resultsA | merge(resultsB) %}
{% paginate results.limit(10) as pageInfo, pageEntries %}

How I did it:

Perform a normal search for entries containing the query in one of their fields (specified in search_criteria, not included in the code above) and get the IDs of the found entries.
Search for assets that contain the query in their customField. Since I'm only searching one field, I do not use the search-function, which would be an option when searching multiple fields.
Now I'm getting the entries that are related to the assets. As in step 1, I attain the IDs, ignoring IDs already present in the first set of results, to avoid duplicates (which I found out late are not a problem, since craft.entries - in point 5 - only returns each entry once)
I merge both arrays.
Get an ElementCriteriaObject containing all entries with the IDs collected before.
I paginate them as usual.

If you do not need to paginate, step 5-6 are might be unnecessary. You could simple use find() instead of ids() to get arrays which you then could merge. This however will cause duplicates!

Although this code works, it has a few disadvantages:

The results are ordered by their position in both arrays. resultsA are listed first, followed by resultsB. In my application I can live with that, since queries fetching many results in assets will usually fetch almost no results in entries and vice versa. I tried to sort and order them by the number of occurrences, however, this did not work using only twig functions. With the help of a simple plugin as host for some php array sorting, ordering of the results could be improved.
Performance is not very good, since many queries are necessary.

Idea

One idea in my mind was to build a custom MySQL-query, which JOINS the assets fields (combined to a string if there are multiple ones) to the entry's row. However, I was not able to accomplish that. If anyone knows how to do so: Let me know!

Thanks for your help!


Can't acces JSON data from FeedMe Feed I'm trying to load a JSON feed and parse/display the data.  My code below generates an error - "impossible to access id on a string variable".  Below is some sample JSON data I get back along with code I tried to use to display.  Any help accessing my JSON data would be hugely appreciated.

Code to load / display feed (does not work):

{% set params = {
    url: 'https://jsonURL',
    type: 'json',
    element: '',
    cache: 60,
} %}

{% set feed = craft.feedme.feed(params) %}

{% for node in feed %}
    node: {{ node.id }}
{% endfor %}

JSON feed data:

{
    "id":"546852386",
    "timestamp":"2019-10-17 15:35:47",
    "user_agent":"Mozilla",
    "remote_addr":"1234",
    "payment_status":"",
    "form":"12345",
    "latitude":"123",
    "longitude":"123",
    "data":[
        {
            "field":"83628997","value":"first = aa\nlast = a"
        },
        {
            "field":"83691483",
            "value":"1"
        }
    ],
    "pretty_field_id":"83628997"
}

I think I figured it out ... I guess since I'm only getting one results I can't actually loop through.  Eg: the following works.

{% set feed = craft.feedme.feed(params) %}
id: {{ feed.id }}
form: {{ feed.form }}


Element-API: Access the first url of an asset array I have an asset field in my current project with the handle postImage, containing multiple image files. In my element-api endpoint, I wish to access the url of the first file only.

I tried the following code:

$imgs = $entry->postImage;
$imgUrl = $imgs[0]->getUrl();

The resulting console error message says:

500 (Call to a member function getUrl() on string)

Looping through the array works fine, but I don't want all image urls, just the first one.

It's probably very easy, but that ties a knot my brain. I don't understand where the array is being converted to a string, can anyone hint me to the solution?

Thanks a lot!

you could use array_values() to fetch the first image:

...
      'transformer' => function (Entry $entry) {
        foreach ($entry->images as $image) {
          $images[] = $image->url;
        }
        return [
          'images' =>  array_values($images)[0],
        ];
      },
...

or use reset()

...
      'transformer' => function (Entry $entry) {
        foreach ($entry->images as $image) {
          $images[] = $image->url;
        }
        return [
          'images' =>  reset($images),
        ];
      },
...


Help installing demo site I'm trying to install the Craft demo site on my local dev environment but I'm getting stuck trying to install Composer.

This command from the instructions didn't work.

cd happylager.test
composer install

The I tried this command from the Composer website:

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === '93b54496392c062774670ac18b134c3b3a95e5a5e5c8f1a9f115f203b75bf9a129d5daa8ba6a13e2cc8a1da0806388a8') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"

I tried both as-is and putting it after the path to my directory first like so:

cd /path to directory

Then the above command.

It did seem to install a file named composer.phar but I'm not sure this is it, and moreover I don't have a vendor subfolder.

Am I missing anything? Thanks.

So If you still have everything on your machine, the thing going wrong here is the composer install bit. It looks like you have installed composer locally inside the folder but not globally. You have a file called composer.phar inside you happylager.test folder.

The way you have composer at the moment (locally), you cannot do composer install in your terminal you have to do php composer.phar install from within you happylager.test.

This should sort it for you and you will get the vendor folder from it. Then, simply follow the other steps to installing the demo. I strongly recommend you install composer globally though, it'll be easier for you in the future :)


How to check custom field not empty within params? The following returns entries correctly:

{% paginate craft.entries.section('sectionName').customField(':notempty:').limit(10) as products %}
    {% for product in products %}
        {% include 'incs/_productSnippet' %}
    {% endfor %}
{% endpaginate %}

But the following returns empty:

{% set params = { section: 'sectionName', customField: ':notempty', limit: 10} %}
{% paginate craft.entries(params) as products %}
    {% for product in products %}
        {% include 'incs/_productSnippet' %}
    {% endfor %}
{% endpaginate %}

It's the latter I'm after because the customField I want to check varies. Removing the customField: ':notempty', from params in the second example returns entries, so I'm guessing it's the way I'm using customField within params?

You’re just missing the : at the end of :notempty: in your second example. This will work:

{% set params = { section: 'sectionName', customField: ':notempty:', limit: 10} %}


Plugin-settings form field for chosing a user? I'd like to be able to select a user for a settings field for my plugin.

Is there a settings AttributeType that matches users? And a corresponding forms template for picking a user?

(also interesting would be picking assets/elements from a certain section)

Copying from the widgets settings I made something that sort of works:

Define the setting to be type mixed:

protected function defineSettings()
{
    return array(
                 'jobsemail' => array(AttributeType::Mixed, 'required'=>false),
                 );
}

Then create a settings.html like this:

{% import "_includes/forms" as forms %}

{% set userInput %}
    <div class="select">
        <select id="jobsemail" name="jobsemail">
          <option value="">No one</option>
            {% for user in craft.users.group('Admin') %}
          <option value="{{ user.id }}"{% if user.id == settings.jobsemail %} selected{% endif %}>{{ user.name|t }}</option>
            {% endfor %}
        </select>
    </div>
{% endset %}

{{ forms.field({
    label: "Email recipient"|t,
    instructions: "This person gets emailed when new jobs are added"|t,
    id: 'jobsemail',
}, userInput) }}

This gives you a basic SELECT drop-down list. It's ok here, because the number of admin users is low. It would be less suitable if there were 100s of users.

Is a better solution with a real pop-up element picker would be nice!


How to add users to the search results? I'm trying to display three different sets of data in search results. The first two, News and Services I can easily concatenate by the following:

{% set searchSections =  craft.entries.section(['service', 'newsOpinion']) %}
{% for entry in searchSections.search(query).order('score').limit(52).find()  %}

This way the results display both sections limited and ordered via score no matter what section they are in.

Ideally I want to add a third array to searchSections of users.

{% set allStaff = craft.users.group('staff') %}
{% for user in allStaff.search(query).order('score').limit(52).find() %}

However users aren't a section and merging the three arrays doesn't work. Any ideas how i can do this?

Difficult, if not impossible, to do accurately in Craft 2.4.

In the upcoming Craft 2.5, the actual search score is being returned in the results, so you'd be able to take the two arrays, merge and sort them via their score into one result-set.


Is it possible to define a 'richtext' fieldtype as 'MEDIUMTEXT' in DB? Some articles are very long and getting cut off when saved to the database.

Is it possible to define a 'richtext' fieldtype as 'MEDIUMTEXT', or would I have to write a plugin to replicate the 'richtext' fieldtype with a different field attribute defined in defineContentAttribute? Any other considerations to take into account? Such as search, indexing, redactor or otherwise?

Part 2 of this question would be: what is the simplest way to duplicate the RichTextField in a plugin? Can I just extend 'RichTextFieldType' and redefine getName and defineContentAttribute? I tried the following with no luck.

Update: This creates a 'Rich Text (Medium)' field with the correct DB column type of 'MEDIUMTEXT', but causes the 'Edit Entry' screen in the CP to be blank below the entry title (silent fail?); and if switching to entry type with this field getting a garnish error 'Double-instantiating a transparent text input on an element'.

class LongTextFields_MediumRichTextFieldType extends RichTextFieldType
{
    public function getName()
    {
        return Craft::t('Rich Text (Medium)');
    }
    public function defineContentAttribute()
    {
        return array(AttributeType::String, 'column' => ColumnType::MediumText);
    }
}

Another option might be to just redefine the columntype manually in the database. Is there any chance this value will ever get overwritten? (i.e. upgrades, migrations, etc).

Defining your a plugin with it's own field type that extends RichTextFieldType might work (haven't tested), but your current code is slightly off.

The field type class/file name needs to be PluginHandle_FieldTypeNameFieldType before Craft will even recognize it.

Also, the ColumnType enum uses MediumText, not Mediumtext.

Really, what we should probably do is make this a setting on the field type because it does pop up every so often and there currently isn't a clean answer.


Craft periodically goes down due to plugin migrations Our application seems to be crashing periodically, on a seemingly unknown cadence. Sometimes it goes down once every few days, and sometimes (like today, when I'm at the end of my rope) it goes down 30 times a day or so.

When hitting the site on the frontend, the user gets a message saying that the site is unavailable; the maintenance mode error message. When we visit the admin panel, we are prompted to update two of our plugins, Geo and Embedder. After performing the updates the site comes back online.

In the craft logs before the site goes down, we're hit with a bunch of 404 errors:

Level       error
Category    exception.Craft\HttpException.404
Message     Craft\HttpException in /var/www/vhosts/production/craft/app/controllers/TemplatesController.php:72

these range from requests trying to hit /wp-admin and other random pages

Then it looks like the site goes down, because then we get hit with 503s:

Level       error
Category    exception.Craft\HttpException.503
Message     Craft\HttpException in /var/www/vhosts/production/craft/app/etc/web/WebApp.php:971

When we hit /admin, the logs show the following:

******************************************************************************************************
2018/06/02 20:52:43 [info] [application] [Forced] Preparing to update embedder.
2018/06/02 20:52:43 [info] [application] [Forced] Finished preparing to update embedder.

******************************************************************************************************
2018/06/02 20:52:43 [info] [application] [Forced] Starting to update the database.
2018/06/02 20:52:43 [info] [application] [Forced] The plugin "Embedder" wants to update the database.
2018/06/02 20:52:43 [info] [application] [Forced] Running migrations...
2018/06/02 20:52:43 [info] [application] [Forced] No new migration(s) found for the plugin Embedder. Your system is up-to-date.
2018/06/02 20:52:43 [info] [application] [Forced] Taking the site out of maintenance mode.
2018/06/02 20:52:43 [info] [application] [Forced] The plugin "Embedder" is done updating the database.

******************************************************************************************************
2018/06/02 20:52:43 [info] [application] [Forced] Starting to clean up after the update.
2018/06/02 20:52:43 [info] [application] [Forced] Clearing the update cache.
2018/06/02 20:52:43 [info] [application] [Forced] Flushing update info from cache.
2018/06/02 20:52:43 [info] [application] [Forced] Finished Updater.
2018/06/02 20:52:43 [info] [application] [Forced] Finished cleaning up after the update.

Now I don't think this is related to those two plugins; I think either Craft is getting out of sync somehow, or something is up with our cloud database.

Has anyone run into this issue before? What would be forcing the plugin migrations to initiate again and again, to make updates to the same database?

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.


How to list all User Groups and Users I'm nearly there on this one but could use some help. I want to list all User Groups, with all Users listed under each group. For bonus points, this all needs to be alphabetical (Group, then Users). Something like...

User Group A

User Name A
User Name B
etc...

User Group B

User Name A
User Name B
etc...

Here's what I have so far...

{% set userGroups = craft.userGroups.getAllGroups() %}

{% if userGroups|length %}
    {% for userGroup in userGroups %}
        <h2>{{ userGroup.name }}</h2>
        {# list all users for this group #}
    {% endfor %}
{% endif %}

I just can't figure out how to loop through users for a userGroup.

Something like this should work:

{% set userGroups = craft.userGroups.getAllGroups() %}

{% if userGroups|length %}
    {% for userGroup in userGroups %}

            {{ userGroup.name }}

        {% set users = craft.users.group(userGroup.handle) %}

        {% for user in users %}

                {{ user.username }}

        {% endfor %}

    {% endfor %}
{% endif %}


Show entry content for other available locales We need to part translate a site, and by which i mean only certain sections are available in other locales, and only certain Entries in those pages. In order to display these in the front end we simply want to show :

"This entry is also available in French"

at the base of the entry, and link to a special layout (no nav).

Has anyone achieved this - can the locales be called for each entry ?

Thanks
Dan

I think the best way to do this, is by using craft.entries.id().locale() and checking if any entries are returned (not tested):

{% set thisEntryInDifferentLocales = craft.entries.id(thisEntry.id).locale('fr') %}
{% if thisEntryInDifferentLocales | length %}
    {% for localeEntry in thisEntryInDifferentLocales %}
       This entry is also available in {{ localeEntry.locale }}
    {% endfor %}
{% endif %}


How do I filter entries by month using custom Date/Time field and paginate them? Here is how I am filtering entries by a specific month:

{% set filterId = "July" %}
{% set allEntries = craft.entries.section('messages') %}
{% set filteredEntries = [] %}

{% for msg in allEntries %}

  {% if msg.messageDate | date('F') == filterId | date('F') %}
    {% set filteredEntries = filteredEntries | merge([msg]) %}
  {% endif %}

{% endfor %}

{% set messageList = filteredEntries %}

How can I paginate messageList? Do I need to filter by month a different way for pagination to work?

You won't be able to paginate messageList, because that's just an array... According to the official documentation on the {% paginate %} tag, only an ElementCriteriaModel can be paginated.

To see how to create an ElementCriteriaModel which has already been filtered by month, check out Solution #2 in this thread...

You'll end up with code that looks something like this:

{% set firstDayOfMonth = year ~ "-" ~ month ~ "-01" %}
{% set daysInThisMonth = firstDayOfMonth|date('t') %}
{% set lastDayOfMonth  = year ~ "-" ~ month ~ "-" ~ daysInThisMonth %}

{% set thisMonthsEntries = craft.entries.section('messages').messageDate('and', '>= ' ~ firstDayOfMonth, '<= ' ~ lastDayOfMonth) %}

{% paginate thisMonthsEntries as entriesOnPage %}
    {% for entry in entriesOnPage %}
        {# ... whatever your code does... #}
    {% endfor %}
{% endpaginate %}


"Updating search indexes" message in admin sidebar I'm noticing the following error in my admin sidebar:

If I try to retry it just fails again. I can't see anything obviously failing in my logs. I'm not sure if this is related to the queue, but if I look at my queue info I see a failed job:

$> ./craft queue/info
Jobs
- waiting: 0
- delayed: 0
- reserved: 0
- failed: 1

The Craft docs mention the ability to rebuild the search index manually:

  Craft does its best to keep its search indexes as up-to-date as possible, but there are a couple things that might render portions of them inaccurate. If you suspect that your search indexes don’t have the latest and greatest data, you can have Craft rebuild them with the Rebuild Search Indexes tool in Settings.

But looking at this Github issue:

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

It appears that this option has been removed.

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

Will update the docs you linked to reflect that.

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


Custom Field on Settings page I would like to have a custom field on the general settings page where I can enter the meta description for the website. Can this be achieved somehow?

Another way I could think of is to add such a field to a section, the homepage for example, but this solution wouldn't be elegant.

You can’t change or add fields to the General Settings page, but for site wide available content Craft has this concept of Globals.

See the documentation on it:
https://craftcms.com/docs/globals

It’s also very easy to manage user permissions for Globals, so you can allow certain user groups (besides admins) to change the meta data, somthing that (currently) isn’t possible for everything in Settings.


I want to know if I can interface Craft address details into DPD shipping site New to this and just looking at a few solutions for a small start-up. Would I be able to take address details directly from Craft and interface directly to preferred carrier which is DPD here in UK? Currently my customer is typing address details from existing e-commerce site into DPD !!!

Probably depends on exactly what you're looking to do, but it does look like DPD has some APIs you can integrate with: https://www.dpd.com/nl_en/business_customers/help_en_tools/labelprint_tools/dpd_integration_services

Assuming that's the case, you'd be able to write a Craft/Commerce plugin to pull the data out that you need and interface with their APIs.


Looking at potentially 100,000 users/entries to capture data Looking at a small site build, but potentially capturing Names, Email and Addresses /custom fields, then dumping into a csv.

There's no user activation, but any potential issues with so many entries in the sql database in any one go?

User Registration in Craft seems to fit the bill nicely for us.

Any experience or notes welcome.

We've seen Craft installs with several hundred thousand users/assets/entries running along fine.

You'll just need to be smart with how you're pulling data out on the template side and use caching where appropriate and you should be fine.


CraftCMS with Cloudfront Full Page Delivery I have a fully static website. All images and videos are currently delivered via aws cloudfront.

Now I am thinking of delivering the HTML via cloudfront as well. My concern is that craftCMS routing will always point to the CDN domain.

How do you preview your content without invalidating the cache? I want my clients to immediately see the changes they made without waiting for 30 minutes (cdn cache expiration).

Any ideas?

edit #1:

I am wondering if relative urls for linking between pages has any pit falls.

That's the dream, isn't it? CDN everywhere, no database hits, etc. How "static" is your site? Unlike other CMS, the great thing about Craft is that you can store information everywhere and pull it out anywhere. That gets to be dynamic content problem nightmare unless you're very diligent about knowing what will happen, for example:  "updating this page will also update content on the home page, the blog index, related white papers section, author archives, etc".

Let' say you update the title of one of your main areas that's also part of your navigation: Services becomes Products for example. Now you have to invalidate every single page.

So it can get complex quickly but if you have a very simple site, obviously, the above doesn't apply.

One way to pull this off would be to create a subdomain, like admin.whatever.com. Your admins would login to this URL. As far as Craft is concerned, it'll serve up on whatever domain you need, you just need multiple environment config.php and template trickery.

In your template files, check for the server name.

{% if craft.request.serverName is not "domain.com" %} {% reqireLogin %} {% endif %}

This will prevent non-logged in users from trying to accesses the admin pages, otherwise Craft will serve up your non-CDN on that domain to anyone who hits it (which is not something you want to have happen generally).

Unlike something like WordPress where it actually stores URLs in the database, Craft uses reference tags and builds up the URL on the fly so you generally don't have to worry about relative vs absolute URLs.

The hardest part of this is going to be the cache invalidation. Unlike static files, where you can just upload a new file with a different filename on the CDN to invalidate them, pages are much different. To make matters worse, it can take up to 10-15 minutes for that invalidation to happen on Cloudfront.

I use nginx here for static/microcaching and it works pretty well but the idea is the same. I can share some code I use to invalidate its cache but basically you want to create a plugin that listens on entries.SaveEntry and then tell CloudFront to invalidate the cache after it's saved. Something like:

public function init()
{

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

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

        if ($entry->url && $entry->enabled) {

        $url = $entry->url;

            try {

                 // do CloudFront stuff here
                if (!$response->isSuccessful()) {
                    return;
                }

            } catch (Exception $e) {
                // something happened.
            }

        }
    });
}


What is the best way to create breadcrumbs based on a structure? How do you create breadcrumbs based on a structure?

My structure:

Parent

Child (active)
Other Child

Child

My url:

site.com/parent/child

So my breadcrumb need to be:

home (url) / parent (url) / child

Got it!

{% if craft.request.segments %}

Home

                {% for crumb in entry.getAncestors() %}

{{ crumb.getLink() }}

                {% endfor %}

{{ entry.title }}

{% endif %}


How can I upload separate 1X and 2X images? I want my site to serve 1X and 2X images depending on the browser using something like Picturefill, and I don’t want the 1X version to just be automatically generated using a transform - I want to be able to upload separate 1X and 2X versions, and have them be linked together. How can I go about that?

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 %}


UsersController's actionUploadUserPhoto and actionCropUserPhoto with Element API Can you use the Element API plugin to utilize UsersController's actionUploadUserPhoto and actionCropUserPhoto methods?

Not natively.  The Element API plugin provides a "read only" API to Craft's controller endpoints.  Both actionUploadUserPhoto and actionCropUserPhoto request POST/write requests.

You could fork it and add POST/write functionality to the plugin/API, though.


How does a plugin output JS that can be used within a cache tag? Google Maps for Craft outputs data into script tags to add markers to map with Javascript. Everything works great until a user goes to cache the output of an entries loop. It works upon first page load, but all subsequent page loads do not contain any of the JS at the bottom of the page as it should.

Here is a simple example to duplicate this issue. I am not sure what to do about it. In my mind, there should be a way to output JS that can be cached and output to the page without the query running.

{% set options = {
    id: 'map',
    width: '400px',
    height: '300px',
    clustering: true
} %}

{{ craft.googleMaps.map(options) }}

{% cache %}

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

        {{ craft.googleMaps.data('map', entry.map) }}

        test<br>

    {% endfor %}

{% endcache %}

Within my add-on all the methods that use includeJs behave the same way. But this is just a simple example of what I am doing. I just instantiate an object with some data and include it in the JS.

 craft()->templates->includeJs('new GoogleMaps.MapData('.$id.','.$data->toJson().','.$this->jsonEncode($options).');');

For additional information you can see it here in this support thread on the Github repo.

https://github.com/objectivehtml/Google-Maps-for-Craft/issues/12

That’s a tricky one, because right now the {% cache %} tag is only focussed on the actual HTML that gets output between its tags, but when you include Javascript using TemplatesService::includeJs, etc., that’s actually queuing up the Javascript to be output later on.

So, the trick here will be to make sure any JS that is included within the {% cache %} tag is also output within the {% cache %} tag:

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

        {{ craft.googleMaps.data('map', entry.map) }}

        {# Output any queued-up JS #}
        {{ getFootHtml() }}

    {% endfor %}
{% endcache %}

This isn’t a perfect solution because that tag will also output any Javascript that was already queued up before the {% cache %} tag. If there is any, then it will end up getting output twice on requests where the {% cache %} tag already has cached HTML to return. Might be something we can address in a future update though.


Best practice way to store countries and cities Is there a recommended way for storing countries and cities in craft?
I can see fields and categories as obvious options but its difficult to see the disadvantages/advantages of either at the beginning of a project.

This will depend on what you're actually trying to do, but if you're building this as part of a plugin, I'd store them as relational tables in the database, and display them as dropdown fields. If you provide more specific information about what you're building, I'll see if I can lend a hand.


How to make calls to render a fixed asset I am trying to call an image in my twig template whose identity is known. Here is my code that does not work

{% set asset = craft.assets.kind('image').folderId('9').filename('fitness-strength-strong-male-1.jpg') %}

{% set thumb = {
    mode: 'crop',
    width: 800,
    height: 600,
    quality: 75,
    position: 'center-center'
} %}

 {% if asset %}
    <img alt="No More Posts" class="img-responsive center-block" src="{{ asset.getUrl(thumb) }}" >
 {% endif %}

This is not working at all. My folderId is correct (got it from craft_assetfolders table) and filename is copied and pasted. Not sure what I am doing wrong.

This is more of a suggestion than a real answer (assuming the folderId and filename are correct, what you've got should probably work), but anyway:

I'd strongly advise against hard coding an Asset into a template like this. By creating a Global set with an Assets field, you'll save yourself a lot of (potential) trouble, both short and long term.

Here's how your code could look using a Global set called siteSettings, with an Assets field called noMorePostsImage:

{% set asset = siteSettings.noMorePostsImage.first() %}
{% set thumb = {
    mode: 'crop',
    width: 800,
    height: 600,
    quality: 75,
    position: 'center-center'
} %}
{% if asset %}
    <img alt="No More Posts" class="img-responsive center-block" src="{{ asset.getUrl(thumb) }}" />
{% endif %}

So, the code is (a little bit) simpler than what you currently have, and (more importantly) the chance of something going wrong is much smaller. As a bonus, it'll be much simpler to change the image later on, should the need arise. You'll also avoid future issues if someone e.g. moves or renames the Asset from inside Craft.

If your content editor(s) shouldn't be able to change or remove the image, you can simply exclude the Global set from your content editors' user group permissions (assuming you're not running Craft Personal, of course).


Better way to find a specific asset? I'm currently using a route to get a specific asset for a gallery section of my site. URL is similiar to http://craft.dev/place/place-name/gallery/1 (Where 1 is the number in the gallery.)

I'm currently doing the following in the template

{% extends '_layout' %}

{% set entry = craft.entries.slug(craft.request.getSegment(2)).first() %}

{% set image = entry.images[craft.request.getSegment(4) - 1] %}

{% block content %}

    {{image.getImg('featuredImage')}}

{% endblock %}

It works currently but is there a cleaner way to do it without the - 1?

That’s definitely the way to do it!

I would set the URL segments to their own variables, to clean it up a little bit.

{% set entrySlug = craft.request.getSegment(2) %}
{% set imageOffset = craft.request.getSegment(4) - 1 %}

Also, probably a good idea to include the section param when fetching the entry, in case you have another entry in another section with the same slug.

{% set entry = craft.entries.section('mySection').slug(entrySlug).first() %}

The only issue I can think of is, if the 4th segment is greater than the total number of assets, you’re going to get an error. You can grab the asset using the offset param instead, and check to see if anything is returned:

{% set image = entry.images.offset(imageOffset).first() %}

{% if not image %}
    {% exit 404 %}
{% endif %}


Display the next and previous category The examples I have seen to link to previous and next entry all seem to be for sections. I want to get the previous and next category.

My category handler is called 'media'.

So I might have entries in this category such as :
Time
Life
People

When viewing the entry 'Life', I want to be able to go back to Time (Previous) or to People (Next). Again, these entries are entries in my category.

I tried:

{% set params = craft.entries.section('media').relatedTo(category) %}
{% set prevEntry = entry.getPrev(params) %}
{% set nextEntry = entry.getNext(params) %}
{% if prevEntry %}Previous{% endif %}
{% if nextEntry %}Next{% endif %}

That didn't work, so I also tried:

{% set category = entry.category.first() %}
{% set params = craft.entries.section('media').order('title asc').relatedTo(category) %}
{% set prevEntry = entry.getPrev(params) %}
{% set nextEntry = entry.getNext(params) %}
{% if nextEntry %}
    {% set nextEntryUrl = nextEntry.url %}
{% else %}
    {% set firstEntry = craft.entries.section('media').first() %}
    {% set nextEntryUrl = firstEntry.url %}
{% endif %}
{% if prevEntry %}
    {% set prevEntryUrl = prevEntry.url %}
{% else %}
    {% set lastEntry = craft.entries.section('media').last() %}
    {% set prevEntryUrl = lastEntry.url %}
{% endif %}

But also no good.

Based on your example and description, it's a bit hard to tell whether you are dealing with a category template or an entry template, because in your description you say that the category handle is called 'media', but in the example you are grabbing entries in the section called 'media'.

Assuming you are on a category template (i.e. trying to create a category index page for example), then you should be able to just grab the current category from the 'category' variable (provided by craft), entries related to that category using relatedTo(category), and the next and previous categories from category.nextSibling and category.previousSibling (or category.next and category.previous depending on whether your categories are hierarchical). If so, then the following should work (not tested):

{# category template #}

{% set prevCategory = category.prevSibling %}
{% set nextCategory = category.nextSibling %}
{% set entries = craft.entries('mySection').relatedTo(category) %}

{{ category.title }}

    {% for entry in entries %}

{{ entry.title }}

...

    {% endfor %}

{% if prevCategory %}Previous {% endif %}{% if nextCategory %}Next{% endif %}

If you are dealing with an entry template (i.e. an entry detail page), then you may need to clarify the question a bit.


Log in as different users in backend front end at the same time? Is it possible be logged in with different users in frontend and backend, and if so, how do I do that?

It would be very convenient being able to test logging in/out different users in frontend, without it affecting the logged in admin user in backend.

You can use "incognito mode" in your browser, or you use another browser or computer for this type of front end testing.


How do I show something only for a parent segment and not it's children? How do I display something only for one of the parent Structure sections and not others or this sections children?
I was thinking of using

{% if craft.request.segment(2) == 'modules' and craft.request.lastSegment|length %}''

but that still shows for its children.

The lastSegment will always have length whether it's 2, 3, 4 etc. I am unclear about your Structure setup, but if there is nothing after "modules", "modules" is the last segment and therefore exists.

So maybe something like:

{% if craft.request.getSegment(2) == 'modules' and not craft.request.getSegment(3)|length %}


Use of App::env() compared to getenv() since Craft 3.4.18 I've noticed since Craft 3.4.18 there is a App::env() function from craft\helpers\App::env(). This was created from the discussion here it seems: https://github.com/craftcms/cms/pull/5893
It seems getenv() can be problematic on multithreaded environments, which is why this change was made.
Should getenv() calls be replaced by App::env() in PHP code now, if using Craft 3.4.18 or above given the App::env() function will check $_ENV first then use getenv() as a fallback?

Yes.
It’s not a requirement, but relying on App::env() is the current best practice and we’ve updated the Composer starter project to use it: https://github.com/craftcms/craft/blob/master/config/db.php


Passing Querystring Variable to PHP Code in Plugin I'm pretty new to Craft and PHP, and I am needing to design a page in Craft (powered by a plugin) which will pass a variable in a querystring (or equivalent in Craft) to the PHP code in the plugin.
In my case, it would be a username (e.g. jsmith) to pass to the plugin PHP code, which would query an XML file for a node having 'jsmith' as the username value.
My first question is - in Craft, can I use a querystring like:
?username=jsmith

or would I need to use something more Craft-specific?

My second question is - can Craft (Twig template) pass to the PHP plugin by including the PHP file (service)?

Thanks for your help in this

If you have a URL like this:

mysite.com?username=jsmith

You can retrieve it from your plugin via craft()->request->getQuery('username');

See here: https://craftcms.com/classreference/services/HttpRequestService#getQuery-detail

  My second question is - can Craft (Twig template) pass to the PHP plugin by including the PHP file (service)?

I'm not actually following this question, but we generally try to keep to one question per post.  I'd suggest posting a new one for that with some additional details of exactly what you're trying to do.

Would also suggest giving the official plugin documentation a read-though: https://craftcms.com/docs/plugins/introduction


Web folder content moved up a level - Craft Path settings I use subdomains for staging environments. That meant in Craft 2 I had to move the public_html folder content up a level and change

$craftPath = '../craft';

To:

$craftPath = 'craft';

I'm getting myself in a bit of a mess how to do this for Craft 3. I've moved the contents of 'web' into the root folder for the subdomain.

I think I have to change these settings

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

but it's a bit over my head, so any help to what I change these to would be much appreciated.

My hosting doesn't allow configuring the webserver to point to the /web folder.

Structure:

index.php
css
js
craftcms

config
modules
storage
templates
vendor

To replicate what you did in craft 2, you would change your web/index.php to:

define('CRAFT_BASE_PATH', dirname(__DIR__,1) . '/nameofthefolderwherecraftlives');

The ,1 tells craft to go up 1 level and change /nameofthefolderwherecraftlives to well... The name of the folder where craft lives :)

So for what I show you above, your structure will be:

web

index.php

nameofthefolderwherecraftlives

config
modules
storage
templates
vendor

It's here in the docs.

Hope that helps!


Is Craft's search() case-insensitive? Is Craft's Search case-insensitive?

(And is there a way to toggle case-sensitivity on/off?)

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

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

Update:

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


How can I use another plugin in PHP? I'm running the ElementAPI but would like to take advantage of some functionality provided by another plugin, to return these results in the API. Is this possible? Should all functions available in the main templates be available to the ElementAPI?

To be specific about what I'm trying to achieve--I'm trying to access the Imager plugin to handle optimised transformations of an uploaded image. Here's how the code looks in a regular Twig template

{% set transformedImage = craft.imager.transformImage(image, { width: 200 }) %}
<img src="{{ transformedImage.url }}">

And my attempt to do this inside elementapi.php is:

$sizerOptions = array( 'width' => '202' )
transformedImage = craft()->imager->transformImage( $asset->url, $sizerOptions );

My PHP is not brilliant so I may just be doing something silly here, but wondering if it's my fault, or if I'm attempting to do something impossible!

Your approach is technically correct – the problem is that craft()->imager->transformImage() requires two additional parameters; $transformDefaults and $configOverrides.

You can read more about these parameters and the transformImage method in the plugin's official docs, but it's not super important. The two parameters can actually be null, which means the following should work:

$sizerOptions = array('width' => 202);
$transformedImage = craft()->imager->transformImage($asset, $sizerOptions, null, null);

Note that while Imager does work with URLs, if you do have an AssetFileModel (i.e. $asset) it's actually better to feed that to transformImage() because then Imager will handle automatic cache breaking etc. for you (e.g. if you replace the image in Craft later on) – so my advice is to use transformImage($asset), not transformImage($asset->url), whenever possible.

Finally, in case you're wondering why the below works for templates:

{% set transformedImage = craft.imager.transformImage(image, transform) %}

...when you need the additional two parameters when you do the same thing in PHP, here's a quick explanation of what's going on:

Plugins in Craft are made up of several different components – among them, Services and Variables.

You can think of Services and Variables as two different APIs for a plugin – one is only made available to PHP (Services) and the other is only made available to Twig/templates (Variables).

Craft makes plugin Services available in PHP by instantiating them and adding them to the global craft() object in the format craft()->serviceName. For many plugins, there'll only be a single service, usually named after the plugin itself (e.g. ImagerService, which is mapped to craft()->imager). There can be several though, e.g. Imager_AnotherService, which would be mapped to craft()->imager_another.

Unlike Services, plugins can only have a single Variables class, which is always named after the plugin (e.g. PluginNameVariable) and mapped to craft.pluginName. In Imager's case, this means that the ImagerVariable is mapped to craft.imager in Twig.

Whenever you call craft.imager.transformImage() in a template, you're actually interacting with a Variable class – in this case, ImagerVariable. When you call craft()->imager->transformImage() in PHP, you're interacting with the ImagerService class.

The fact that the ImagerVariable and ImagerService both have a method called transformImage is a common design pattern in Craft, where variable classes are used to "wrap" Services, in order to expose the latter for use in templates. Often (and this is true for Imager, as well), the Variable methods do little more than to call their namesake Service methods. Using the same names for Variable and Service methods isn't a requirement, though – just a "best practice" to ensure consistent plugin APIs for templates and PHP. Imager's author could've opted to call the Variable method transform, doTransform, transformy or basically anything else.

Finally – as I mentioned, Imager's Variable method transformImage basically just wraps the ImagerService->transformImage method – but with one important difference: The Variable method makes the two additional parameters ($transformDefaults and $configOverrides) optional. This is why you don't have to declare them when you use Imager in a template, but you do have to define them when you use it in PHP.

A fun trick is that while Craft doesn't expose Template Variable classes to PHP out of the box, there's nothing preventing you from using them "manually". For example, say you prefer the Imager's Template Variable API over its Service API; here's how you can use the Variable methods wherever you want in your PHP:

Craft::import('plugins.imager.variables.ImagerVariable');
$imager = new ImagerVariable();

$transformedImage = $imager->transformImage($asset, $sizerOptions);


How to check if entry field value is already outputted, and prevent it again? For an event page I have the option to filter on cities and countries. Each event has entry fields in which the city and country, of which the values are outputted in a drop down list on the front end.

As some events happen in the same country and city I have multipe values that are the same. Is there any chance to filter these values in Craft and output it only ones?

{% for entry in craft.entries.section('events') %}
    <option value="{{entry.stad}}" name="{{ entry.stad }}">{{ entry.stad }}</option>
{% endfor %}

Craft has a group filter, that does just that:

{% for stad, events in craft.entries.section('events') | group('stad') %}
    <option value="{{ stad }}">{{ stad }}</option>
{% endfor %}