Building a simple search by multiple categories Is it possible to build the following/is it the right way in Craft. Been through the docs and searched but stuck.

I just need to build a form on one page with a dropdown select for 2 categories;

Location
Type

That then takes the user to the results page and returns entries where the location and type match.

Can someone be so kind as to provide a sample to get me going please?

Building the form is pretty straightforward, you get the categories from your "locations" and "types" category groups using craft.categories
and loop them to build your select options. I choose to pass the category's slug as the value to submit and /results as the URL to submit to.

<form action="{{ url('results') }}" method="get">

    Location
    <select name="location">
        <option value="">all locations</option>
        {% set categories = craft.categories.group('locations') %}
        {% for category in categories %}
            <option value="{{ category.slug }}">{{ category.title }}</option>
        {% endfor %}
    </select>

    Type
    <select name="type">
        <option value="">all types</option>
        {% set categories = craft.categories.group('types') %}
        {% for category in categories %}
            <option value="{{ category.slug }}">{{ category.title }}</option>
        {% endfor %}
    </select>

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

</form>

Getting the entries that are related to categories from both, one or non of your category groups is a little bit more tricky.
In case a category in both select options is selected, you need to use the following syntax for your relatedTo parameter
(see Craft docs: "The relatedTo Param - Passing Multiple Relation Criteria"):

{% set cocktails = craft.entries.section('cocktails').relatedTo('and',
    { sourceElement: currentUser, field: 'favoriteCocktails' },
    { targetElement: gin, field: 'ingredients' }
) %}

I suggest to compose the value for the relatedTo parameter starting with an array ['and'] and then build upon this array,
conditionally adding array elements (relation conditions) using the merge filter.

{# Get the search data #}
{% set locationParam = craft.request.getParam('location') %}
{% set typeParam = craft.request.getParam('type') %}

{# Compose the relation param #}
{% set relationParam = ['and'] %}

{% if locationParam %}
    {% set location = craft.categories.group('locations').slug(locationParam).first() %}
    {% set relationParam = relationParam|merge([{ targetElement: location }]) %}
{% endif %}

{% if typeParam %}
    {% set type = craft.categories.group('types').slug(typeParam).first() %}
    {% set relationParam = relationParam|merge([{ targetElement: type }]) %}
{% endif %}

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

{# Find and list matching entries #}
{% set entries = craft.entries.relatedTo(relationParam) %}

{% if entries|length %}

        {% for entry in entries %}

{{ entry.title }}

        {% endfor %}

{% else %}
    No entries found.
{% endif %}


Can anything be done to suppress or limit the clickable area of the checkbox in a Matrix block header? You know, the one that gangs blocks together but never really gets explained in the docs.

I hate that thing. I hate it because double-clicking (or single clicking) anywhere in a Matrix block header toggles the check. And wouldn't one rather collapse/expand a block by double-clicking than by pulling down that menu?

It can be hidden with CSS (with consequences) but I am wondering if there is something I am missing.

I would love to restrict its behavior to just the far-left checkbox/label area. I think it's a UI mistake to make the entire header the active checkbox area.

Can anything be done to suppress or limit the clickable area of the checkbox in a Matrix block header? (or Neo)

Not really an answer, but have you considered posting a feature request on the feedback site?

http://feedback.craftcms.com


Check if there is a discount and, is yes, how much I would like to do two things in my Craft commerce templates:

In my product template:

Check if there are any discounts available to a specific product.

I have a way to output discounts but need to be able to check if there are any at all because the pricing table would look entirely different for either one of the two cases.

In my shopping cart template:

I would like to check (1) if there are any discounts applied to a line item in the shopping cart and, if there are, (2) I would like to display the discount amount for that line item.

This way, I can avoid showing a zero discount like this:
"Your discount: $0.00"

Thank you for your help.

Something like this?

  {% if item.discount %}

    Your discount is {{ item.discount|commerceCurrency( currency ) }}

  {% endif %}


Eager loading relations in Plugins Element Type I am creating an ecommerce plugin in Craft, and trying to take advantage of the ElementType. My goal is to list the orders, and also the items ordered in a single column. Is it possible to eager load Element Type's relations for the ElementIndex view?

I have two records: OrderRecord and ItemRecord, with relations defined like this:

// OrderRecord (the ElementType)
    public function defineRelations(){
      return array(
                'element' => array(static::BELONGS_TO, 'ElementRecord', 'id', 'required' => true, 'onDelete' => static::CASCADE),
                'items'   => array(static::HAS_MANY, 'Shopping_ItemRecord', 'orderId', 'onDelete' => static::CASCADE))
    }

// ItemRecord
public function defineRelations(){
  return array(
    'order' => array(static::BELONGS_TO, 'Shopping_OrderRecord', 'required' => true, 'onDelete' => static::CASCADE)
  )
}

Loading the records from a service using OrderRecord::model()->with('items')->find() works really well, but i am struggling with translating this to the ElementType (if it's even possible, i don't know). I tried to using the OrderElementType::modifyElementsQuery() function to add the item columns, but there are a few problems:

The query is not allowing me to specify a different order-by, resulting in MySQL ambigous column error. The query is only containing "order by ´id´" without any alias name, which makes this query fail: select order.customerName, items.*
Joining in the items table, and grouping by anything else than the default ´elements´.´id´ results in duplicate rows in the view. This is my biggest concern about this question, how can i translate several rows from the result to a single OrderModel?

My current solution to this is to query the items from the OrderModel::populateModel($values), but this feels very slow and inefficient, i would like to avoid calling 50 extra queries every time the getMoreElements() is called

Thanks

Ok, so i managed to solve my problem without actually fetching any extra records, but instead using mysql group_concat function for the fields i need to display. Posting this here for anyone else that might need it.

In OrderElementType:

public function modifyElementsQuery(DbCommand $query, ElementCriteriaModel $criteria){

    $query
      ->addSelect('group_concat(items.productName separator \';\') as productnames')
      ->join('orders orders', 'orders.id = elements.id')
      ->leftJoin('items items', 'orders.id = items.orderId'
      ->group('elements.id');
}

public function populateElementModel($row){
  $model = OrderModel::populateModel($row);
  $products = explode(';', $row['productnames']);
  foreach($products as $product){
    $item = new ItemModel();
    $item->productName = $product;
    if(!$model->items){
      $model->setAttribute('items', array());
    }
    $model->setAttribute('items', array_merge($model->items, array($item)));

  }
  return $model;
}


PHP error when trying to access dates in Sprout Reports Basic Sprout Report here, settings page:
{{ forms.dateTimeField({
  label: "Start Date"|t,
  instructions: "The start date of the date range you wish to display in your report."|t,
  id: 'datetimeStartDate',
  name: 'datetimeStartDate',
  value: settings.datetimeStartDate is defined ? settings.datetimeStartDate : now|date_modify("-30 days")
}) }}

{{ forms.dateTimeField({
  label: "End Date"|t,
  instructions: "The end date of the date range you wish to display in your report."|t,
  id: 'datetimeEndDate',
  name: 'datetimeEndDate',
  value: (settings.datetimeEndDate is defined ? settings.datetimeEndDate : now)
}) }}

Results page:
{% set purchases = craft.entries()
  .section('purchases')
  .limit(null)
%}

{% if settings.datetimeStartDate and settings.datetimeEndDate %}
  {% set purchases = purchases.postDate('and, >= ' ~ settings.datetimeStartDate.date ~ ', <= ' ~ settings.datetimeEndDate.date)
%}
{% endif %}

I am getting the following PHP error:

PHP Notice – yii\base\ErrorException Undefined property:
DateTime::$date

I have copied the datetime fields directly from the example docs, and tested the results template code with hardcoded dates, which works fine, but passing dates this way does not work.

You can't access date this way, you'd need to use the date (docs) or datetime (docs) or even atom (docs) filters.
In the case of your report, since you have multiple conditions, you would need to pass those as an array and use the atom filter.
Try:
{% set purchases = purchases
    .postDate([
        'and',
        '>=' ~ settings.datetimeStartDate|atom,
        '<= ' ~ settings.datetimeEndDate|atom
    ]) %}

Alternatively, you can use before() (docs) and after() (docs) and pass date objects directly:
{% set purchases = purchases
    .after(settings.datetimeStartDate)
    .before(settings.datetimeEndDate) %}


Charge: Update subscription card details I am attempting to create a form where the user can update their subscription card details (with Stripe Elements).

From looking at the Charge plugin's source code, I believe the endpoint I need is charge/updateSubscription.

As with checkout I am creating an opts hidden input in my twig template like so:

{{
  craft.charge.setPaymentOptions({
    planAmount: currentSubscription.planAmount,
    planInterval: currentSubscription.planInterval,
    planIntervalCount: currentSubscription.planIntervalCount
  })
}}

And then making a POST request with Javascript to the endpoint:

getStripeToken(cardToken => {
  post({
    params: {
      action: 'charge/updateSubscription',
      opts,
      cardToken,
      subscriptionId
    },
    then: response => console.log(response)
    url: '/'
  })
})

Quite simply, this doesn't work. I receive a {success: true} response, but the Stripe card has not been updated.

Does anybody what I'm doing wrong, or even if this is possible?

In the end I worked out the card is related to a customer, not a subscription.

I couldn't see any public endpoint to update a customer's card, so I added this method in charge/controllers/ChargeController.php (not ideal to update the plugin directly I know):

public function actionUpdateCard()
{
  $this->requirePostRequest();
  $customer = craft()->charge_customer->find();
  $cardToken = craft()->request->getRequiredPost('cardToken');

  if ($customer->addCard($cardToken)) {
    $this->returnJson(['success' => true]);
  } else {
    $this->returnJson(['success' => false]);
  }
}

and then can make requests to the charge/updateCard endpoint:

getStripeToken(cardToken => {
  post({
    params: {
      action: 'charge/updateCard',
      cardToken
    },
    then: ({ success }) => console.log(`Card updated: ${success}`)
    url: '/'
  })
})


Relating entries to assets within an ElementAction I'm following the Element Actions example from the official Craft docs.

I've defined an Artist entry type, and have defined an entries field on my Assets to relate an Artist to each Asset. To avoid assigning Artists one-by-one, I'm attempting to create a Element Action so that I can select multiple Assets in the Asset Index and relate them to an Artist entry in bulk.

I'm almost there. I can select an Artist (entry) from a dropdown I've created on the Asset Index page in the CP, but I'm struggling to save the relationship in the performAction function within my plugin. I assume I should be using the relations service saveRelations() method to accomplish this?

I'm new to Craft and not sure where I'm going wrong. I'm sure the fact that I'm doing this within an ElementAction is irrelevant, it's just that I'm doing something wrong while trying to save the relation. Here's the relevant part of the code as it currently stands:

public function performAction(ElementCriteriaModel $criteria)
{
    // Get the selected artist
    $artistId = $this->getParams()->artist;
    $artist = craft()->entries->getEntryById($artistId);

    // Make sure it's a valid one
    if (!$artist)
    {
        $this->setMessage(Craft::t('The selected artist could not be found.'));
        return false;
    }

    // Assign the artist to the selected elements
    $assets = $criteria->find();

    foreach ($assets as $asset)
    {
        $artistFieldModel = craft()->fields->getFieldByHandle('artist');
        craft()->relations->saveRelations($artistFieldModel, $asset, $artistId);
    }

    // Success!
    $this->setMessage(Craft::t('Artist successfully assigned.'));
    return true;
}

Any pointers gratefully appreciated.

So it seems what I was doing wrong was passing in a single $artistId rather than an array. With the change shown below it works as expected:

foreach ($assets as $asset)
{
    $artistFieldModel = craft()->fields->getFieldByHandle('artist');
    craft()->relations->saveRelations($artistFieldModel, $asset, [$artistId]);
}


Is it safe to delete unused matrix field tables from the DB? During design/dev I created a bunch of matrix fields that I have since decided not to use. I have deleted the fields, however, I notice that the matrix tables are still in the database. Is it safe to delete these manually, or is there some other cleanup that needs to happen as well (i.e. references within another table, etc.)?

Update: The problem is caused when changing the fieldtype from a matrix field to another field type, rather than deleting the field altogether, and creating a new one. Even if the field is subsequently deleted, the matrix tables will still remain, which results in orphaned data in the DB.

That shouldn't be the case... Those tables should have been deleted automatically when you deleted the fields.

Did you actually delete the fields themselves? Or did you simply remove them from your section's field layout? Make sure the actual fields were deleted within Settings > Fields

If you're positive those fields have been properly deleted...

Try updating to the latest version of Craft (v2.2.2587), which was released today. It includes this bug fix:

  Retroactively fixed a bug where some Matrix block rows would get left behind in the database when an element was deleted that had a Matrix field.

If that doesn't resolve the problem for you, I'd recommend submitting a bug report to Pixel & Tonic. Submit the message via your Dashboard, so you can include a copy of your database and log files.


Adding new structure items to top of structure Is there a way to add new items in a structure to the top of the list? Now I have to drag it from the bottom to the top.

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

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


How can I display category title inside another category I would like to display a list of category.
I can display the information inside a category like slug or title.

However, I dont know how to display a category field inside a category.

    {% for category in craft.categories.group('handle') %}
       <p> {{category.title}} </p>
       <p> {{category.title}} </p>

    {% endfor %}

If I get you right you have a category select field inside a category. If you want to grab any field values from a category you can do it the same way as with entries. Code works almost the same.

{% for category in craft.categories.group('handle') %}
    <p> {{category.title}} </p>
    <p> {{category.title}} </p>

    {# You can access any field like you normally do inside your category #}
    {{ category.categoryField }}

    {#
       If you want to access another loop-able
       field inside your category you can just make another loop.
       Like you're looping over entries
    #}
    {% for block in category.categoryFieldName %}
        {{ block.fieldName }}
    {% endfor %}
{% endfor %}


How do I print the name of the Section on an index page I have an index page for articles in a section.  Call the section "dogs."

How do I template to output the name of the section?  This is not an entry, but an index page.


Installation Error "1046 No database selected" Summary

I'm getting the following error when attempting to install a new Craft site locally:

CDbCommand failed to execute the SQL statement: SQLSTATE[3D000]: Invalid catalog name: 1046 No database selected. The SQL statement executed was: SHOW TABLES LIKE 'craft_%'

Having just downloaded the ZIP, I assume the version of Craft in question is the latest at time of writing (2.1.2563).

Point of failure

After some digging, the error appears to be caused by line 59 in craft/app/etc/behaviors/AppBehavior.php, specifically the call to craft()->db->tableExists():

$this->_isInstalled = (craft()->isConsole() || craft()->db->tableExists('info', false));

If that is indeed the case, it means that the preceding craft()->getComponent('db') and craft()->getIsDbConnectionValid() checks are passing, which leaves me completely baffled as to what is causing the error.

Environment info

The site is (not) running on a local Vagrant VM, which is happily hosting another Craft site with no problems. It's perhaps worth noting that I didn't install the other site from scratch on this server.

The basic server specs are as follows:

Ubuntu 12.04 LTS (64-bit)
Apache 2.2.22
PHP 5.4.30

The database definitely exists, and I can connect to it using Sequel Pro.

Has anybody else run into this?

While it may be an unsatisfying answer, for the sake of completion, this question was resolved by completely destroying and rebuilding the exact same VM.

Short discussion on Twitter about it here:

https://twitter.com/monooso/status/487831027327696896

I have a warm affection for the on/off technique.  I've even seen it fix elevators!


Posting an entry without using a form? I'd like to create a history section so logged in users can see which pages they have visited.

Is there a way to post an entry without using a form? So the user does not have to click to say he has visited a page, instead as soon as they visit the page it is logged into a history section (the user and the page slug)

I've thought about doing it with javascript but it seems a little messy. Is there a native neat way to do this? Or a simple way to achieve it with a plugin?

Thanks in advance :)

If you're looking for an "audit trail" of pages a user has visited, then a plugin will be the way to go.

You'd want to track a user by something like their PHP session ID.  And for every request grab that session ID and the URI and save that in a your plugin's dedicated audit table in the database (no need to use entries for this).

When the user goes to their history page, you'll query your audit table and grab any rows with a matching PHP session ID and display them however you want.


How do I build a link from variables? I'm building an entry type's menu, automatically populated with several sections. A route for dynamic menu had to be also created.

Code

{% set section = craft.sections.getSectionByHandle('sectionHandle') %}
{% set entryTypes = section.getEntryTypes() %}

{% for entryType in entryTypes %}

            {{ entryType.name|ucfirst }}

{% endfor %}

Output

craft.dev/sectionHandle/types/entryType.handle

When I access the link, It gets crazy.

Output

craft.dev/sectionHandle/types/sectionHandle/types/entryType.handle

I was trying everything I know, but Whatever I add in front of {{url('types/'~entryType.handle) }}, it gets duplicated.

Since you are building a custom URL, you shouldn't be using url() here, since it automatically appends your values to the siteUrl. Try one of these instead:

-or-


Postmaster plugin: user activation link Trying to get the Postmaster plugin working for user activation emails, instead of the default Craft setup (had issue with Mandrill setup, Use SMTP authentication throws an error).

It doesn't seem that Postmaster disables the default Craft email setup, is there a way to do this within Craft?
Assuming (1), what is the correct {{ link }} variable as currently I'm seeing:

Template Error

Variable "link" does not exist

/Users/.../site/craft/templates/postmaster/user/activation.txt(5)

Hey {{user.friendlyName}},

Thanks for creating an account with the Postmaster {{siteName}}! To  activate your account, click the following link:

{{link}}

If you weren't expecting this email, just ignore it.

It doesn't seem there is currently a way to do this.

In Craft 2.x, it isn't possible for plugins to provide their own email providers that the entire Craft installation can use.  They can provide their own that they can use for themselves, but it won't affect things like when Craft sends an activation email.

That's changed in the upcoming Craft 3, though.  There is an example Mandrill plugin here on how to pull that off.


Craft 3 Upload To Bluehost - Index.php outside root issue I'm having issues uploading my craft3 site to Bluehost.

I've uploaded all the files, ran composer install and it does actually work. However when I go to my domain it shows the raw files/folders and I have to go in to my 'public_html' folder to access the site.

I must note I changed the 'web' folder to 'public_html'.

Because the index.php file is inside the public_html folder my server can't find an index file and therefore shows the raw files.

That's my understanding.

What's the best approach for this?

Thanks

Without getting too much into it, i feel you need to look at a symbolic link for public_html to the web folder (if you have linux server):

https://www.shellhacks.com/symlink-create-symbolic-link-linux/

Or change .htaccess file:

https://www.expression-web-tutorials.com/bluehost-main-domain-sub-folder.html


How are people organizing their global sets? I've found it a little challenging to use global sets effectively, so I'm wondering how others are doing it.

The fact that a global has to be in a set has been a little tricky to deal with at the beginning a of a build, as knowing what those sets might be is hard when there aren't any globals yet.

This leaves me using sets like "Misc", "Content", and "Settings", which doesn't end up being all that helpful.

The arbitrary nature of these assignments also present a problem when using those globals, because you have to call them with their set name {{ settings.analyticsId }}.

Just thinking out loud, and wondering how others are dealing!

Before I create any fields I try to plan them on paper. This helps me to create my first logical groups. It doesn't prevent changes later on, but at least reduces them a little.

Also all my global sets have prefix: global__settings, global__misc...

Now if I have to create a new set and move some fields, I can do a "Search & Replace" on all templates, and thanks to the prefix I don't have to worry about replacing the wrong variables.


How can I get a field's value from a global based on a url segment? I have a rich text field with a handle of myTextField that I have included in a global set called firstGlobalSet.

What If I created another global set called secondGlobalSet and included the same field myTextField.

How could I get the correct field from the correct global set based on url segment?

For example, mysite.com/first or mysite.com/second

You will need to access a few things.

The url segment you need (for example the last segment)
The global set name
The field handle name

You can use getLastSegment to access the last url segment.

Using the global set names above let's say I have a url like this:

mysite.com/first

{% set segment = craft.request.getLastSegment() %}  // first

I know I've got a global set called firstGlobalSet, and now I've got first. We just need to put them together. You can use Craft's
getSetByHandle method to access the global set via its handle.

{% set global = craft.globals.getSetByHandle(segment ~ 'GlobalSet') %}
{{ global }} // firstGlobalSet

Now that we've got the correct global set, we can get to the field we need. In this case it's myTextField.

{{ global.myTextField }}


Show content based on chosen city Just have a question on the way way to approach this: I have entire sections of a website that are per city and the number of cities might grow. I plan to create a city category and add the cities to it, then those cities appear when people add content. Then in the front-end, get those categories into a list and show them so a user can select them. Once selected it would write it to a cookie or localStorage.

Can I organise my content via url like /newyork/ and it would pick up the URL and fetch that data? Or when I visit the site and I have localStorage set, it would redirect me to /mychosencity/ ?

Just trying for the fastest, most efficient way both in terms of redirecting, but also implementing per city content on a whole site as well as in the templates.

Yes, you can totally do this with categories, but then you have to assign a city category to each entry manually. Another idea would be to use a structure section for all of your entries, with top level entries being entries for the cities and child entries for the stories (you can make use of different entry types).

Your cities index page to promt the user for their preferred city would list the categories or the top level entries of your structure. Use a conditional in this page's template that retrieves a cookie and does the redirect in case. To set a cookie you'd need to make a custom plugin or make use of Lewis Jenkins' "LJ-Cookies plugin".

For your per-city stories index page you would make your new-york/ template list the city specific stories by adding the category relation / the city parent entry as a criteria to the ElementCriteriaModel.

If you choose to use categories, see here how to set up a category template (tick "Categories in this group have their own URLs"). Additionally you probably want to make your categories field required (so that you have to select a city) and set the limit to 1 (max. allowed cities) in the field settings.

For the structure solution you may want to read through this article in the docs, to learn how to give entry types individual templates.


Search results with partial match to query I have entry titles that contain dashes (i.e. ABC-123). When I search for 'ABC', 'ABC-123', 'ABC 123', '123' etc the entry is shown in the results (I have fuzzy search enabled). However, when I search for 'ABC123' or anything with the dash omitted from the query the entry does not appear in the results. The same goes for misspellings (i.e. 'ABB-123').

Is there a way for search to return a result that is only a partial match to the query to take into account slight differences between the query and a page title?

Please note that I have the following fuzzy search config settings:

'defaultSearchTermOptions' => array(
    'subLeft' => true,
    'subRight' => true,
),

And I have the following search query template code:

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

Is there a way for search to return a result that is only a partial match to the query to take into account slight differences between the query and a page title?

Not natively.

When you put a title of "ABC-123" into a title in Craft, it will normalize it down to " abc 123 " when putting it into the craft_searchindex table (lowercasing all letter and removing punctuation).  And Craft does a similar thing for searches (lowercases them and removes punctuation).

With subLeft and subRight enabled, searching for ABC turns it into a MySQL fulltext search with wildcards on the left and right... i.e. LIKE '%abc%' so it will match what's in the search_index table.

Likewise ABC-123 gets converted to %abc 123%, which will match, ABC 123 also gets converted to %abc 123%, which will match and 123 into %123% which will match.

ABC123 would get converted to %abc123% which wouldn't match (nor would ABB-123.

MySQL does have a SOUNDEX() method, which might do what you're looking for, but it does have enough drawbacks that Craft wouldn't use it natively.

i.e. it won't work against full text indexes, inconsistent results in non-English languages and inconsistent results with multi-byte characters (even if they are UTF-8).

Some other search services might offer more robust solutions (Algolia, Apache Lucere, etc.) that you could wrap with a plugin for searches on the front-end of a Craft site, but you should add a thumbs-up comment to this Github issue if you'd like the ability for plugins to swap out the core search provider that Craft uses wholesale (including for the Control Panel).


Unable to set error message in onBeforeDeleteUser This is related to How to overrule Craft error messages with custom setError()? but I don't have enough rep to comment on it.

I have a plugin that needs to check if a user is ok to be deleted before doing so. Stopping the delete with $event->performAction = false; works fine, but I am unable to overwrite the Craft message with my own to tell them why.

The following code demonstrates the problem:

craft()->on('users.onBeforeDeleteUser', function(Event $event){
    craft()->userSession->setError("I don't want to delete " . $event->params['user']->username);
    $event->performAction = false;
});

If deleting from the edit user page the "Couldn't delete the user" message is shown. I can change setError() to setNotice() and it will be displayed alongside the Craft error as a potential workaround, but I'm reporting an error so would like to display it as such. (There is the other workaround of setting the error on a field of the user entry, but in my case the error has nothing to do with a field on the page so this would be misleading.)

If deleting from the users listing page setError() shows nothing, just the Craft notice "Deleted Users" is shown. This also cannot be overridden with setNotice().

Is there a way of overriding the Craft error message or showing my own error message alongside it?

I can't think of a clean way to do this.

craft()->userSession->setError() is just a wrapper for craft()->userSession->setFlash() that uses a key of error and saves the message to user session and is good for one request.  Multiple calls to it just overwrite the same key causing the last one in to win.

You could maybe use setFlash() directly, passing in your own key, then add some JS for displaying the additional flash message similar to how Craft does it.


Create users without providing e-mail I have a client that has a need for adding users without knowing their e-mail beforehand. Their wish is that when the user login for the first time, they are prompted to enter their e-mail, which also needs to be verified as normally by sending a activate link.

Is this possible to do?

Perhaps something hooked into the users.onBeforeSaveUser event?

I think a custom plugin is going to be the best way to do this.

If the client is adding users from the control panel, they'll either have to put in a dummy email address (username+someUniqueId@domain.com), or you can create a front-end "user management" form for them that fills that in behind the scenes.

Regardless, you'll want to be sure "verify email address" is not enabled for the user at this point.

Then, assuming you'll be providing your own front-end login form for these users, with username/password fields (password not required), you'll want to point the form to your plugin's controller with it's own actionLogin method (very similar to Craft's UsersController->actionLogin), but check to see if password is null and if the username is valid and if the email is in the format of the unique email address that was previous assigned.

If so, prompt for their actual email, then send Craft's activation email and let it go through Craft's usual workflow for setting a password on the user account.


How do I list category name? Forgive the simplicity of this question but I am in the early stages of my first Craft implementation.

My simple question is: how do I display a category name in a template. This is the code I am using:

{% for entry in craft.entries.find({section: 'blog', limit: '3'}) %}

{{ entry.blogCategory }}

        {{ entry.title }}

{% endfor %}

The error I am getting says "Object of class Craft\ElementCriteriaModel could not be converted to string"

Any help is appreciated.

An ElementCriteriaModel is "used to fetch elements with a given set of parameters." {{ entry.blogCategory }} hasn't yet fetched your category element.

You need:

{{ entry.blogCategory.first }}

if you are positive there is exactly one of them, or more generally:

{% for c in entry.blogCategory %}

{{ c }}

{% endfor %}


Using Yii CDbCriteria to query a table in a plugin First question I guess is "should I be using CDbCriteria at all, or am I overcomplicating things"?

Secondly if I'm ok using it, how do I achieve the following SQL query:

SELECT * FROM myTable
WHERE cottage=3
AND (fromDate BETWEEN '2015-01-01' AND '2015-01-11'
OR toDate BETWEEN '2015-01-01' AND '2015-01-11');

So far I've got this:

$criteria = new \CDbCriteria();
$criteria->addCondition('cottage=' . $booking->cottage);
$criteria->addBetweenCondition('fromDate', $booking->fromDate, $booking->toDate);
$criteria->addBetweenCondition('toDate', $booking->fromDate, $booking->toDate, 'OR');
$previousBookings = BookingEngine_BookingsRecord::model()->findAll($criteria);

Which nearly gets me there, the only issue is when I dump the $criteria->condition, the brackets are in the wrong place. So I get this:

((cottage=3) AND (fromDate BETWEEN :ycp2 AND :ycp3)) OR (toDate BETWEEN :ycp4 AND :ycp5)

The cottage and fromDate are bracketed together, whereas I want the fromDate and toDate bracketed together instead.

Other than manually writing the SQL, is there a more straightforward way of doing this, I feel I'm really overdoing a seemingly easy query!

UPDATE: I did rearrange the addCondition and addBetweenCondition calls as such:

$criteria = new \CDbCriteria();
$criteria->addBetweenCondition('fromDate', $booking->fromDate, $booking->toDate);
$criteria->addBetweenCondition('toDate', $booking->fromDate, $booking->toDate, 'OR');
$criteria->addCondition('cottage=' . $booking->cottage);
$previousBookings = BookingEngine_BookingsRecord::model()->findAll($criteria);

and that did in fact solve the problem. However it does feel like it's working by accident rather than by design. I think Jørgen's answer below  is a bit more straightforward, so I went with that instead.

Try this (untested)

$criteria = 'cottage = :cottage and ((fromdate between :d1 and :d2) or(toDate between :d1 and :d2))';
$params = array('cottage' => $booking->cottage, 'd1' => $booking->fromDate, 'd2' => $booking->toDate);
$previousBookings = BookingEngine_BookingsRecord::model()->findAll($criteria, $params);


Updating Entry field with GraphQL mutation I'm trying out the GraphQL mutations and would like to issue an update of an Entry, triggered from a webhook.
However, documentation on mutations seems sparse, and I find GraphQL highly confusing. Most examples talk about creating new entries, not update current ones, and how you actually call graphQL relies on implementation, it's hard to figure out how to deal with this in Craft.
I found https://github.com/craftcms/cms/issues/4835, which shows an example of creating an entry. Documentation talks about creating drafts, and publishing drafts, but no examples are shown, just a bunch of words thrown around.
First it says:

To save a draft for an entry, use the entry type-specific mutation which will have the name in the form of save___Draft

But then followed by:

To create a draft use the createDraft mutation., which requires the id of the entry for which to create the draft as an argument and returns the resulting id of the draft as the result.

For publishing a draft, you should use the publishDraft mutation, which requires the id of the draft to publish as an argument and returns the id of the entry it belongs to as the result.

None of these things makes sense to me...
Anyone have any comprehensible examples they can give?

To edit an entry via a GraphQL mutation you will need to pass the id of the entry you want to edit (similar to front end entry form).
This example assumes a news Section, an article Entry Type and will update the entry title.
Mutation
mutation MyMutation($id: ID = "", $title: String = "") {
  save_news_article_Entry(id: $id, title: $title) {
    id
    title
  }
}

Query variables
{
  "id": "12345",
  "title": "My title update"
}


Remove duplicated entries from SuperTable related entries Anyone able to assist me with removing duplicates in this example?
So I have a related entries (cables) setup in a SuperTable. Some of these entries are duplicated across different rows. So a cable might be related to the first row in the SuperTable and also row3 and row4.

I want to be able to run through all these cables in any SuperTable row and output the entries just once not duplicated.
So as an example a basic SuperTable setup like this;

{% for row in entry.tests %}
    {% for cable in row.cables %}
        {{ cable.title }}<br />
    {% endfor %}
{% endfor %}

would output this;
BS 7211
BS EN 50525
BS 6724
BS 8573
BS 7835
BS 7629-1
BS 8436
BS 5467
BS 6724
BS 7846
BS 6622
BS 7835

I want to essentially loop through and only display the related entry once. As you can see from the example some entries are duplicated (e.g BS 6724)

The simplest way is to create a "filtered" array, containing the unique cables, and then loop through that.

For example:

{# Build the "filtered" array of cables #}
{% set filteredCables = [] %}

{% for row in entry.tests %}
    {% for cable in row.cables %}
        {% if cable.title not in filteredCables %}
            {% set filteredCables = filteredCables|merge([cable.title]) %}
        {% endif %}
    {% endfor %}
{% endfor %}

{# Output the unique cables #}
{% for cable in filteredCables %}
    {{ cable }}<br />
{% endfor %}


Filter Sprout Form entries throwing error Based on this very helpful question I'm trying to filter the display of Sprout Form entries based on the value of a form field.

For example, my form handle is 'reportHazardDeficiency' and my field name is 'company'. My template has craft.sproutForms.entries.formHandle( 'reportHazardDeficiency' ).company( 4 ) and I get

Database Exception – yii\db\Exception Unknown column 'reportHazardDeficiency.field_company' in 'where clause'

I'm running craft3 and Sprout Form trial version 3.0.0-beta.16.

Seems to be working after upgrading to 3.0.0-beta.21. Thanks @Ben!


How to add a non-breaking space to a rich text field? Seems like a basic question but I can’t figure out a way to do this out of the box, or reference to it in the Redactor docs. ‘&nbsp;’ always gets stripped out.

What about using CSS white-space: nowrap; instead of &nbsp; characters? I guess that's semantically more correct and this also allows you to prevent your text to break at any other character (great for phone numbers etc.).

CSS:

.nobr {
  white-space: nowrap;
}

Markup:

my phone number is +1 800-275-8777

To add this easily to your Redactor fields markup, have a look at the inline format API or the formattingAdd config setting (I actually had mixed experiences with that setting).

If you'd like to be able to add this with the click of a button, I also just added this to my Redactor Inline Styles plugin, which is a collection of (optional) buttons to apply inline styles to your Redactor texts (Quotes, Code, etc.).


Is it possible to include category slugs in the entry URL format? Is it possible to include category or tag slug in the entry URL format?
Would you please let me know the tags that make it, if possible?

Assuming you want the first category that's selected in the field, you'd set your "Entry URL Format" setting to:

{categoryFieldHandle.first().slug}

You can access any of your custom fields by their handle in a similar way.


SuperSort `rsortAs` error with `postDate` In Craft CMS Twig template I am trying to sort Entries by post date using SuperSort.

An old template on Craft CMS 3.0.17.1 PRO is using:

{% set products = products | supersort('rsortAs', '{ postDate }') %}

And this works as expected.

But after updating to Craft CMS 3.4.17.1 PRO this is throwing an error:

PHP Recoverable Error – yii\base\ErrorException
Object of class DateTime could not be converted to string

I tried updating to:

{% set products = products | supersort('rsortAs', '{ entry.postDate }') %}

But the sorting does not work as expected, ie. nothing is sorted by date.

I saw this Using Supersort with date field but that is not helpful as I am using the latest plugin version.

I'm missing something or doing something wrong?!

Figured it out, needed to format the postDate object accordingly:

{% set products = products | supersort('rsortAs', '{ postDate | date("U") }') %}


When I want to add some features to my Craft site, do I need to modify the files in the craft/app folder? I am new to Craft CMS, now I run a demo site of Happy Lager, wanna add a web crawler to fetch some data to my db. I should develop a plugin to complete this feature, but if I need to change the craft/app folder? or how my services in plugin called by my site? call from the craft/app? please help me,thank you!

Short answer... no!!! You don't ever want to make changes to the craft/app folder. Any changes you make in the app folder will be overwritten when you update Craft.

If you need any custom behavior, the correct way to do it is to write a custom plugin. Your plugin will be safe outside of the Craft core, and will survive any Craft updates intact.

Read up on the complete documentation for creating a Craft plugin. You can also download the Business Logic template to see what some basic components look like. Or even better, spin up a custom plugin using the fantastic Plugin Factory!


Translating static text in JavaScript files I've got some static text that is dynamically being displayed on the frontend with JavaScript.

Now considering the site has 3 locales, how do I best translate those static texts?

I know I could put the JavaScript code in my twig files and use the translate filter, but that is what I'm trying to avoid as I like to keep the HTML & JavaScript separated.

Is there a way to pass on certain messages to a script?

From this answer, I learned there's such a thing as Craft.t but I can't seem to access it from the frontend. Can it be included?

EDIT - To clarify what I'm looking for, it's something in the likes off this Wordpress concept, where you can pass some variables from the server to a javascript script. It would allow me to make some global fields to store the translations in, and make those translations editable from the backend.  But I'm guessing that's not possible?

For now I'm going with this solution:

<script>

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

</script>

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

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


Craft 3 Author Photo Trying to display the author photo of the entry (it's there for sure).  The Craft 2 way I used entry.author.photoUrl but that is not working so I tried entry.author.photo.url and that does not show anything and no error or warnings.

Is what I am doing correct?

{{ entry.getAuthor().getPhoto().getUrl() }}

Here is the function. Of course if the author has no photo you'll receive nothing (but an exception). Furthermore this function returns the URL not a HTML tag.


Craft commerce 3 - Module - Lineitem - Get usergroup I have the following code working. The only thing i have to do is to check which usergroup is the customer in. Is there a simple way to check what usergroup is the customer in? This is my first custom module.
Event::on(
LineItems::class,
LineItems::EVENT_POPULATE_LINE_ITEM,
function(LineItemEvent $event) {

    // @var LineItem $lineItem
    $lineItem = $event->lineItem;

    // @var bool $isNew
    $isNew = $event->isNew;

    $purchasable = $lineItem->getPurchasable();
    $variant = $purchasable->getProduct();

    // IF GUEST USER  > NORMAL PRICE
    $lineItem->salePrice = $lineItem->getSalePrice();
    $lineItem->price = $lineItem->getPrice();

    // IF USER IS IN DEALER USERGROUP > DEALER PRICE
    $lineItem->salePrice = $variant->dealerPrice;
    $lineItem->price = $variant->dealerPrice;

}

);

Remembering a) that not all customers are users and b) that a user can be in one, or more, groups.....then something like this can be used to check if a user is in a particular group:
            $order = $lineItem->getOrder();
            $user = Craft::$app->users->getUserByUsernameOrEmail($order->email);
            if ($user){
                foreach ($user->getGroups() as $group) {
                    if ($group->id == someParticularValue){
                        //do stuff
                    }
                }
            }


Customer details revealed at base order URL If anyone visits http://site.com/commerce/customer/order they see the last order made even if they are not logged in and not related to that order in any way.

The customer can see their order info if they use http://site.com/commerce/customer/order?randomcustomerorderstringforthatspecificorder. Stripping the ? and the random string after it shows the last order.

I am using the standard template to display order information. They are redirected to this page after they complete a transaction. Relevant code is:

{% extends '_layout' %}
{% set number = craft.request.param('number') %}
{% set order = craft.commerce.orders.number(number).first() %}
{% if not order %}
    {% redirect 'commerce/customer' %}
{% endif %}

So it does not seem to be redirecting to commerce/customer.

Any help would be great.

As a rule in Commerce, when retrieving orders on client side templates, you should limit the retrieved orders to orders for the current customer only, using the customer parameter:

{% set number = craft.request.param('number') %}
{% set order = craft.commerce.orders.number(number).customer(craft.commerce.customer).first() %}
{% if not order %}
    {% redirect 'login' %}  {# or wherever #}
{% endif %}

(...if the included example templates aren't doing that, you should let Luke know.  I haven't looked at them in ages and don't have them to hand here...)

(One slightly random side thing I have noted with time is that you should really limit loading of the order complete page to a single time, i.e. only specifically at the actual order completion - if you don't, you tend to get issues with re-submissions of orders to your analytics and so forth.  E.g. if the customer completes an order, goes somewhere on the site, then comes back to the complete page using the back button - it can create issues - so I remove the number parameter from the url using some JS and make sure I check for a number in the url in the cart/complete template:

{# Show empty cart if they somehow get back here without a number.... #}
{% set number = craft.request.param('number') %}
{% if not number %}
    {% redirect 'cart' %}
{% endif %}

And the JS would be something like:

if(window.location.pathname == "cart/complete"){
    var cleanedUrl = utilities.removeURLParameter(window.location.href, "number");
    window.history.pushState('',document.title,cleanedUrl);
}


SVOD and Social capabilities I represent a leading online music tuition platform. We are considering using Craft to develop our new platform. We have a couple of questions about the capabilities of the platform.

1 - Can we build an SVOD and TVOD platform on Craft? The video would be pulled from our CDN and displayed via JW player.

2 - Can we build a social side to our site, where members can share content to a centralized social dashboard.

Any help or advice would be greatly received.

I built a website very similar to what you're describing using ExpressionEngine years ago. It's definitely doable in Craft, and it'd be much easier than most other platforms I can think of.

However, as Brad noted in his reply, it will take some development effort.


Filtering by entries which have unpublished draft versions in the admin I have a client who wants to use an author (draft) -> editor (publish) workflow.

It appears that authors can update existing entries which will create a new draft of the entry. As an editor, I can then visit the edit page for that entry and select the new draft from the "revisions" drop-down.

This is great if I know that a new draft is waiting to be reviewed, but I couldn't find a way to discover which entries have new drafts.

Is there a way to view which posts have new drafts from the entries index? Otherwise what is the normal practice for editor-type users to know which entries have pending changes?

Thanks in advance!

Craft definitely doesn't give you these filtering tools when viewing a list of entries, but the building blocks exist within the framework to allow you to build your own solution. The most straightforward way I can think of would be to create a plugin with its own CP section and show the outstanding drafts there.

You can get a list of all drafts with this little bit of PHP:

EntryDraftRecord::model()->findAll();

If you expose the list of drafts using a Template Variable, you could then display links to each of them by doing this:

{% set drafts = craft.myPlugin.getAllDrafts() %}

{% for draft in drafts %}
    {% set draftEntry = craft.entries.getEntryById(draft.entryId)|first %}

      {{ draftEntry.title }}

{% endfor %}


Problems with channel and locales So I'm setting up a multi-lingual site for the first time, and I'm having some problems with the urls.

I followed the guide, step by step. I've set up the siteUrl in general.php:

'DEV' => array(
    'devMode' => true,
    'siteUrl' => array(
        'no' => 'http://teknologi.dev/no/',
        'en' => 'http://teknologi.dev/en/',
        'es' => 'http://teknologi.dev/es/'
    ),
),

And I guess that works, since I get a message in General settings that the siteUrl has been defined elsewhere.

Then I have a section called "Videos", which I've set up like this:

And when I list out all the entries, the URL to one entry looks right, but I'm getting a 404. If I however change the Entry URL Format to include the locale letters, ex: no/videoer/{slug}, it works. But that makes the URLs write out the locales twice, so a URL might look like: http://teknologi.dev/no/no/videoer/orkanger, which of course gives a 404.

So is there some step I've missed?

Edit: I also have this structure in my www folder:

- .htaccess
- index.php // I needed this one for admin to work?
- no/
  - .htaccess
  - index.php
- en/
  - .htaccess
  - index.php
- es/
  - .htaccess
  - index.php

And in each of the localized index files I have changed the craftPath and the CRAFT_LOCALE

$craftPath = '../../craft';
define('CRAFT_LOCALE', 'no');

While the root index.php points craftPath to ../craft.

Edit 2: I tried deleting the root index.php, and while /no/ still worked, every subpage (ex: /no/videoer/) gave this error message:

The requested URL /index.php was not found on this server.

Do I need to do anything in my .htaccess for locales?

Okay, so I found the answer. And the reason it wasn't working is because I've been using another .htaccess (a hybrid of h5bp and Craft) than the default that comes with the Craft download. And this .htaccess included a RewriteBase, which was set to /. So when one tried to access /no/{slug} the RewriteBase would send it up one folder, basically. So I had to go into each of the locales .htaccess and set their RewriteBase to /no and so on.

I'm just gonna leave it here, and I'm pretty sure I'm gonna find this post again the next time I'm making a multi-lingual site and don't understand why all of my links are broken...


How to validate entry in Craft 3 An entry could be validated by the following code in craft 2:

craft()->content->validateContent($entry);

How could be the same done in Craft 3 ?

Every model has a validate() function

// set the scenario to live
$entry->setScenario(Element::SCENARIO_LIVE);

// validate the model
$entry->validate();

// get the errors,
$errors = $entry->getErrors();


Plugin license key is lost every time I update Craft CMS I have licensed the Verbb Navigation plugin, but every time I update Craft I get a notice that the license needs attention. The key field on the Plugins page is empty after the update. Is this a bug, or is there another way to store the key so it will be saved after an update?

@Dalton I would say that's indeed the issue (using the project.yaml file), at least at first glance.

Every time you're pushing the project.yaml file to your server, it'll overwrite your server's project.yaml file. Because the plugin isn't licensed locally, you're basically removing the license each deploy.

Can you register the license locally, then push your project.yaml file? You'll notice locally, as soon as you enter a license key, the file will change to store this license key. Things should stay in sync from then on.


If only one Matrix block show this, for more then one block show that I have a Matrix field which contains a bunch of blocks. If only one matrix field is present in the entry I need it to show a message. If more then one matrix field show an other message.

Below is my current code.

{% for block in entry.modelIds.limit(1) %}
    {% if block.modelId|length == 1 %}
        I am link - {{block.modelId}}

    {% else %}
        Not a Link - {{block.modelId}}

    {% endif %}
{% endfor %}

Any help would be appreciated. I have tried a few different approaches and am just stumped.

Thanks!

Edit: adding image of fields.

Thanks to Brad for asking me a question above, it made me realize I was checking for matrix fields and not the matrix block. My code is now working that I am checking for the correct element on the page.

Revised code:

{% if entry.modelIds|length == 1 %}
     I am link - {{block.modelId}}

{% else %}
     Not a Link - {{block.modelId}}

{% endif %}

Thanks Brad for the help!


FreeForm and Vue - Hidden Forms in Modal - Manually refresh the Craft CRSF token and Freeform JS Honeypot field Anyone using FreeForm and Vue together?
I have a form that is hidden away in a modal (that is then shown using Vue) via a click of a button. Vue is only used to hide the form and show the form. the form code is all in the page/template.

However, I am having issues with the form being marked as spam and the following error on FreeForm:

  Form honeypot is invalid

FreeForm support suggested that as it is Vue is used - I need to manually refresh the Craft CRSF token and Freeform JS Honeypot field.

I have no idea how to do this? Or where to start. If anyone has done similar or can help point me in the right direction?

Not sure if it's a good call or not but you could have an endpoint that just has the {{ craft.app.request.csrfToken }} outputting on it. Poll(GET) that using ajax (axios or whatever you're using in your Vue app) and update your Vue model's csrf value with the response body?

Same for the honeypot value I guess although I'm not that familiar with freeform I take it there'll be a twig variable available for this.

I'm sure there's a nicer way to do this but this seems like it should work?


Writing and debugging Craft plugins I think my question is simple but may fall outside of the scope of this forum. What is best practices when writing and debugging Craft plugins? Obviously, one way to do so is to create a account on a server, write the code, upload and install it and then trigger the code using twig in a web page. Uggg...

Is there a good (hopefully free, open source) way to write and debug plug in code for Craft, perhaps locally?

I'm not really sure what this has to do with Craft because it's the same process with every single PHP file... You download xampp/wampp/lampp or whatever you want, install it, open it, activate your apache and MySQL, copy your project into your htdocs folder, create your database at localhost/phpmyadmin and start to create your plugin.

Anyway when you use a good IDE it makes absolutely no difference whether you create it locally or not since a good IDE will upload/download/compare your files on the server automatically. You don't have to upload all your files with programs like Filezilla or something like that


How to create a custom query inside a plugin in Craft? Can you give an example of returning entries from a section in JSON format using a custom query?

Easy enough:

$query = craft()->elements->getCriteria(ElementType::Entry);
$query->section = 'mySection';
$results = $query->find();

You can obviously refine the query before calling find():

$query->limit   = null;
$query->myCustomField = 'value';


Creating an active page within a channel I need some advise about the best way to achieve this.

My site is set up with a Channel called 'Product' for example.

I then have entries within this section

Product A
Product B
Product C

Only one of these products will be active at once.

All links on the site for 'Product' will need to link to the active product page (A, B or C).

The way I'm thinking of doing this is having a lightswitch on the Product pages to state which is the current (active) one.

I can't get my head around how this might work at the moment so any advise would be much appreciated.

I would create a single template that is displayed when you visit /product and set entry to be the first entry in the Product channel that is live.

{% set entry = craft.entries.section('products').status('live').first() %}

All you need to do then is disabled all product entries apart from the product you want to display.

UPDATE: To avoid duplicate content or different content on the /product page you could redirect to the current product entry page /products/product-a using

{% redirect entry.url %}


Clear template cache from the CLI? I was looking for a way to clear the “template caches” and “compiled templates” from the CLI, as I want to automatically do this after every auto-deploy of the site I've created.

For this I was looking into the craft binary and its cache/list command. However, when running ./craft cache/list it only returns me cache (yii\caching\FileCache).

This felt kind of strange to me, as I was expecting a list similar to the one to be seen in the admin at the URL /admin/utilities/clear-caches:

So hereby I'm wondering if it's possible to clear any of these caches show above from the CLI. Or is the cache/clear command for something else that I'm not aware of?

Craft-Scripts will do this for you: https://github.com/nystudio107/craft-scripts#clear_cachessh

You can see what it does via the source: https://github.com/nystudio107/craft-scripts/blob/master/scripts/clear_caches.sh

As for cache/clear this clear's Yii2's cache... which Craft CMS uses for almost nothing. Template Caches are always in the db, compiled templates are always cached on disk as files, and so on.


Open Entry in a Modal Unsure how to go about doing this. I'm looking to open a related entry in a modal on the same page. In an area, I have a list of houses. On click, I would like the user to open a modal and load the corresponding entry inside it.
Is there an easier way to do this other than AJAX loading it in?

Ajax is probably the easiest way when using something like Fancybox:
<a data-fancybox data-type="ajax" data-src="yoursite.com/houses/house-slug" href="javascript:;">
    House page
</a>

If your house page has content you want to hide when viewed in the modal you can detect whether or not Ajax was used to request the page:
{% if not craft.app.request.isAjax %}
    Your header code
{% endif }

You could also just include the house content on the page, but hidden and use fancybox to reveal it. This is possibly more accessible.


Creating a multi-dimensional Photo Gallery on Craft CMS I'm currently working with a client who has several hundred photos in a gallery. The gallery consists of albums within albums. The link to their current gallery is here: http://www.fmquizzing.net/gallery2/main.php

I'm working on an entire site update and would like to update their photo gallery to integrate directly with Craft if possible. They currently have the photos in folders on their server pulled in dynamically with a PHP script.

Is there a good way to go about creating a gallery like this with Craft, or is it going to be just as good to attempt updating the styles and script on what they already have going? Trying to think both about short term and long term development and maintainability costs.

Ah yes, gallery2. Used that quite extensively a few years ago. Have a client with an old gallery2 project as well, we might be doing something with it, so we're probably in the same boat.

I can tell you the last time I looked into the gallery project, they were shutting it down. I have no idea where the project stands now, the original authors wanted someone to take it over if possible. The website is still active but when a project is in limbo, it's never a good sign.

Integrating it with Craft is going to be an exercise in futility and it's going to be just as easy to get the original photos working inside Craft "natively". Craft can really do everything Gallery can do... and better because now you can do things  like relate photos back to actual content entries and more.

I took a quick glance at a lot of the site's galleries and it looks like they're not really doing anything special, hardly using any of the gallery features (like tags, etc).

Gallery stores all of its photos in a folder called g2_data. You could grab that folder,  throw it up in a Craft asset source, have Craft index that folder, and everything will be neatly organized by folder ready to roll. Make some Entries that correspond to albums and sub albums and then go to town adding them to each entry/album. Telling Craft about which photos live in which album is going to be the most time consuming but since Gallery 2 stores them hierarchically, at least you have a visual reference vs something simply stored in a flat database structure.

As far as maintainability, Craft is the easiest CMS I've ever had the privilege of using. A lot of my clients figure out most of the control panel before we even have the training session. I remember Gallery2 being very finicky about clearing caches, generating thumbnails, etc. All of this will be handled mostly automatically by Craft.


Extending UserController I'm trying to extend the Craft UserController class, in order to add some extra validation to the actionSaveUser action, before the rest of the code in that function executes.

I've got no problem hitting my controller and even calling the parent::actionSaveUser which seems to be working, except for getting the validation error messages.

function actionSaveUser()
{
    parent::actionSaveUser();
    $this->renderTemplate('profile/index.html');
}

For brevity, I've not included any of the validation just yet. The template being rendered does display errors if routed to the Craft controller action, but not through mine.

The main reason for doing this is because uploading of a non-image for the profile image (e.g. uploading a php file) causes a php error, not a value in the returned errors array.

Any idea why the errors are disappearing when routing through my controller first?

Thank you in advance

Update

Looking through the UserController::actionSaveUser action, I can see

craft()->urlManager->setRouteVariables(array(
    'account' => $user
));

Looking through the urlManager documentation; I can see that _routeVariables is being updated but can't see a way of accessing this array to get the account value.

Am I looking in the wrong place?

Update The Second

Ok, even sending the form directly to users/saveUser isn't yielding any errors (account object isn't defined). But, if all fields are filled in, it correctly saves

Any suggestions?

While not a direct answer to your question, as of the next (post 2.4.2702) Craft release, Craft will now return a validation error on the UserModel if a non-image is uploaded for the user's profile photo.


Craft for Author Agency website? I'm a complete noob in the Craft world but love to give it a whirl for my latest project - just wondering if it can do what I want it to, and to maybe get some starting points from you guys in the know!

I'm building an Author agency website. In addition to their simple static info pages they will need to administer their 250+ clients (Authors,Public Speakers or both) and the 600+ Books by their clients. These will obviously need to be linked (through Entries as I understand it so far). i.e they want a single Author profile page (headshot, bio etc) which also displays a list that author's books, in turn linking to each book's profile page (synopsis, jacket, purchase link etc).

Now clearly I'll need either Client or Pro, as I imagine I will need to achieve this through Channels? Am I on the right track? Is there anything you think I'm missing (plugins?) Or maybe I pissing up the wrong tree?

Thanks in advance.

Don't be alarmed if this post gets flagged for being off-topic. Typically questions regarding whether "craft is appropriate for x" are considered too broad and opinion based. But I'll try and give you some suggestions anyway, which may give you a head start.

The short answer is yes, craft can do all those things. The only point to maybe consider is when you say "purchase", unless you are just linking to amazon or something. As I'm sure you're aware, E-commerce is not something to take lightly and I would make sure you research your options here, and have a plan. E-commerce solutions for craft are limited at the moment, but keep an eye on the plugin page.

You will likely want to have Craft Pro, so that you can have multiple user accounts.

Here is one approach to the basic CMS design, without really knowing anything about your requirements.

Create a single for your homepage.
Create a 'structure' (call it "pages" for example, or whatever you like) to contain all of your static pages and index/landing pages. This would include for example pages like "About us", "Company", "Services", "Authors" index page, "Books" index page, and anything else that you would consider as part of your main nav. 'Entries' within this structure would be defined with unique 'Entry Types' for each unique page layout that you need. Within each 'Entry Type' fields can be defined independently from other 'Entry Types'. In the 'pages/_entry.html' template you can determine which template code to display by checking the entry.type property. The advantage of using a structure here (as apposed to channels and singles) is that you can use it to generate dynamic navigation. See example below.
Create a channel for Authors (called 'authors' or whatever). You can also create users for this if you ever want to allow clients to log-in for whatever reason. (Note: I would use a channel regardless because it allows for multiple tabs in the edit page, and link it to users via a users field. But that's just me). Another tip: Might also check out a plugin called Introvert to display reverse related books from the books channel.
Create a channel for Books (called 'books' or 'products' or whatever), with a 'related users' or 'related entries' field for 'authors' (depending on how you dealt with authors above).
Create a category group for your books subject taxonomies (I'm just guessing at this point), but you get the idea.
Add salt and pepper to taste and serve.

Now for some code examples (and useful concepts regardless of your design).

In your '_layout.html' master template, to generate nav (copied from the docs):

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

    {% nav entry in entries %}

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

                    {% children %}

            {% endifchildren %}

    {% endnav %}

In your 'pages/_entry.html' template, to determine the entry type and retrieve related entries:

{% switch entry.type %}
    {% case 'about' %}
        {{ entry.title }}
        ...
    {% case 'authors' %}
        {{ entry.title }}
        ...

            {% set authors = craft.entries.section('authors') %}
            {% for author in authors %}

{{ author.firstName }} {{ author.lastName }}

            {% endfor %}

    {% case 'books' %}
        {# repeat code above but for books, likely with some category break-down based on the categories field #}
    {% case default %}
        {# display default template #}
{% endswitch %}

Note: You can also use 'includes' in the switch statement, for better template organization, or use this technique to eliminate the need for the 'switch' statement altogether.

In your 'authors/_entry.html' template, to get related books.

{{ entry.title }}

   {{ entry.bio }}
   ...

Books

    {% set books = craft.entries.section('books').relatedTo(entry) %}
    {% for book in books %}

            {{ book.title }}

    {% endfor %}

In your 'books/_entry.html' template, to get authors from the 'authors' entries field.

{{ entry.title }}

....

Authors

    {% for author in entry.authors %}

{{ author.title }}

    {% endfor %}


How to host a huge website on Craft (10k pages, over a dozen languages, 2GB database) We have what appears to be a very large website. We have a strong content strategy which has led us to develop a huge number of pages (over 10k) for our website, as well as building out a significant amount of internationalized pages (over a dozen). We're currently on Craft 2 and working on migrating to Craft 3. As part of that, I figured we'd re-evaluate our current hosting strategy. However, all the hosts I've spoken with have agreed that our situation is unique relative to their other customers.

Here's our 2GB database breakdown (with removal of smaller sections):

+--------------------------------------+-----------+
| Table                                | Size (MB) |
+--------------------------------------+-----------+
| searchindex                          |    868.14 |
| content                              |    728.73 |
| entryversions                        |    215.70 |
| elements_i18n                        |    194.59 |
| matrixcontent_comparisonpagetablerow |     10.72 |
| structureelements                    |     10.52 |
| elements                             |      6.97 |
| entrydrafts                          |      5.58 |
...
+--------------------------------------+-----------+

We currently host on Digital Ocean through Forge. We have a 4vCPU CPU optimized server with 8GB of ram.

What we find is that things like assets are slow, navigating the admin is slow, etc etc. Without fastcgi caching, the entire website would be very slow.

Should we just throw more CPUs at it? What's the ideal solution to really improve performance for such a big website? I'd prefer not to have to get super complex with our hosting strategy (ie break out database, have a read-only database, use a caching layer in front, etc), but if that's what's necessary I'd consider it.

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

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

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

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

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


Super Table -> Matrix data loss I updated to the newest Craft Version 3.1.1. Since then I have the following problem. I lost all the data from Matrix Filed stored in a Super Table Field after changing Field Setup (Matrix - Asset props.) again.

Setting:
Craft CMS: 3.1.1,
Super Table: 2.0.14

1)
I created a Super Table Field which stores a simple Text Field and a Matrix-Field with one Block which stores a simple Text and an Asset.

2)
I added the Field to a Single Entry.

3)
I created all Content with the Super Table Field in the Entry

4)
jumped back to Super Table Field Settings and changed something in the Matrix Asset properties

5) after Saving i lost all the Data in the Matrix Field, which i stored in the entry

Really bad, because the Super Table field i created in the entry was complex.

Does anyone else have the same problem? - What did I Wrong?

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

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


How do i put google analytics code into a Global field? can anyone tell me step by step what to do to put google analytics code into a global field? I have read the earlier answer but i am new to craft and i don't know where to start.

You should just be able to put it in a text field and then output it in an includeJs statement. So, add a new global set (called 'googleAnalytics' or whatever); create a text field (called 'text' or whatever); and add the new field to your global set field layout.

In your template you should be able to access it by the globalSet handle.

{% includeJs googleAnalytics.text %}

Not tested, but I don't see any reason it shouldn't work. If the includeJs statement doesn't like that for some reason you can try the following instead.

{% set GACode %}
    {{ googleAnalytics.text }}
{% endset %}
{% includeJs GACode %}


filtering entries by category I've got my news entries paginated and I have a featured entry on the first page so I'm wondering what the best approach would be to filter by category. Here is what my template looks like:

{% extends "_layout" %}
{% set title = "News" %}

{% paginate craft.entries.section('news').featured('not 1').limit(6) as pageInfo, pageEntries %}
{% set segment = craft.request.segment(2) %}
{% set pageCats = craft.categories('newsCategories').slug('segment') %}
 {% block content %}

Company News

    {% if pageInfo.currentPage == 1 %}
    {% for featuredEntry in craft.entries.section('news').featured('1') %}

                {% for image in featuredEntry.featuredImage %}

                {% endfor %}

{{ featuredEntry.title }}

                {{ featuredEntry.body.getPage(1) }}
                Continue reading

    {% endfor %}
    {% endif %}
    {% for regularEntry in pageEntries %}

{{ regularEntry.title }}

                {{ regularEntry.body|hacksaw(words='25', allow='
', append='...') }}
                Continue reading

    {% endfor %}

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

{% endblock %}

{% nav category in craft.categories.group('news') %}

{{ category.title }}

{% endnav %}

You don't actually need to look at the URL segments, because Craft automatically populates your template with a category variable whenever it matches the current URL to a category's URL. All you need to do, is to make sure that your category URLs point to the correct template, and to account for that template being rendered both with a category variable and without (i.e. for the default news index listing).

First, you'll need to make sure that the URL format for your category group is correct – you should probably use something like news/{slug} or perhaps news/categories/{slug}. Also, set the "Category template" to your news index template, e.g. news or whatever template path you're actually using for the news index.

Then, you can filter your entries like the following, using the relatedTo parameter:

{% set category = category ?? null %}
{% paginate craft.entries.section('news').featured('not 1').relatedTo(category).limit(6) as pageInfo, pageEntries %}

...

One gotcha to note is that whenever you pass a NULL value to the relatedTo() parameter (which will happen whenever the category variable is empty), Craft will ignore the parameter and return all entries – which works in this case, as the same template should also double as your news index.


More extensive documentation for defining models for plugins I'm trying to get a better understanding of how to define new models in plugins, but the documentation at http://buildwithcraft.com/docs/plugins/models doesn't get me very far.

For example, there is:

protected function defineAttributes()
{
    return array(
        'name' => AttributeType::String,
        'type' => array(AttributeType::Enum, 'values' => "alcohol,mixer,other"),
    );
}`

I've seen other plugins define attributes with an array element of 'required' => true, but the only example I see here is 'values'. Is there somewhere I can see a list of the available options when defining attributes? Or is it a better practice to define the attributes simply and then define validation rules in the rules() method?

I know the docs say to check out the CModel documentation, but it doesn't even have defineAttributes. Does Craft itself have more in depth documentation on this topic?

Have a look at Stephen Lewis' archived blog article about validation. Even better, buy the book.


Send email with dedicated SMTP settings from a Craft 2 plugin I have looked a lot for this but cannot find any dedicated solution. Basically I want to do this: How to send email from Craft 3 custom plugin? … but for a Craft 2 plugin.

A how-to for the global email settings would be already helpful, but ideally we would like to use not those SMTP settings in the global email settings but dedicated ones for another email address. Can this be done?

Thanks!

edit August 8th: no ideas? Any help is welcome!

So basically I solved it like this, but couldn’t apply other SMTP settings than the global ones. But we did a workaround with the replyTo-address, so practically we are fine. If someone knows how to apply other SMTP-settings, feel free to answer. Thanks!

namespace Craft;
$email = new EmailModel();
$emailSettings = craft()->email->getSettings();

$email->toEmail   = $_REQUEST['email'];
$email->replyTo = 'test@test.com';
$email->subject = "Subject";
$message = "...";

$email->body = $message;

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


Error on Craft 3 install When attempting to install Craft 3 in OSX El Cap, I'm getting the following errors:

  Script @php craft setup/welcome handling the post-create-project-cmd event returned with error code 255
  /Craft3/vendor/craftcms/cms/bootstrap/bootstrap.php on line 104

  Parse error: parse error in PATH/vendor/craftcms/cms/bootstrap/bootstrap.php on line 104
  Script @php craft setup/welcome handling the post-create-project-cmd event returned with error code 255

I used the --ignore-platform-reqs flag as I am using PHP7 on MAMP.

When I attempt to load index.php in the browser I'm seeing this seemingly related issue in the trace:

  in PATH/web/index.php at line 21 – yii\base\Application::run() 15161718192021    (new Dotenv\Dotenv(CRAFT_BASE_PATH))->load();}

  // Load and run Craft
  define('CRAFT_ENVIRONMENT', getenv('ENVIRONMENT') ?: 'production');
  $app = require CRAFT_VENDOR_PATH.'/craftcms/cms/bootstrap/web.php';
  $app->run();

I've substituted "PATH" in all errors in lieu of the actual path.

Any advice on resolving this would be much appreciated.

In order to install under MAMP with PHP7 we added the MAMP PHP7 path with the following command:

  export PATH="/Applications/MAMP/bin/php/php7.0.15/bin:$PATH"

After achieving a successful Craft 3 install we ran the setup in the CLI and we also created a fresh DB and a new MAMP host following the sequence recommended in the installation docs.


Migrate WordPress Site into Craft CMS. How deal with 404's? I migrate my WordPress site into Craft CMS. So far so good.
But the URLs for most of the Blog Entries are complete new. What's the best way to handle that? My site is good linked on Google and there are a lot of backlinks. It would be nice to have a solution where I can see which pages the Users call and if it a 404. Afterwards I can create rewrite rules for this sites.

Finest way was a Plugin that combine this two features.
Maybe anyone knows one.

David,

I like using Reroute. It's a Craft plugin that lets you create 301s and 302s to any of your entry pages within Craft.


Paginate Grouped Entries I am trying to paginate grouped entries as follows...

{% set searchParam = craft.request.getParam('q') %}

{% set groups = craft.entries({
    search: searchParam
})|group('section') %}

{% for entries in groups %}
    {% paginate entries.limit(10) as pageEntries %}

    {% endpaginate %}
{% endfor %}

However it is throwing this error on the paginate line: Array to string conversion

How else can I achieve this functionality?

That error is occurring at entries.limit(10), because at that point entries is already an array of fetched entries, rather than an ElementCriteriaModel. (The entries will get fetched as soon as the ElementCriteriaModel is passed to your |group filter.)

The only way to grab just 10 entries per section (per page) will be to loop through each of your sections, and create a new ElementCriteriaModel for each one.

{% set sections = {
    'news': 'News',
    'events': 'Events',
    // ...
} %}

{% for section, sectionName in sections %}

    {% set entries = craft.entries.section(section).limit(10) %}
    {% paginate entries as pageInfo, pageEntries %}

    {% if pageEntries|length %}

{{ sectionName }}

        {% for entry in pageEntries %}
            {{ entry.title }}
        {% endfor %}
    {% endif %}

{% endfor %}

Note that Craft does not support multiple independently paginated lists of entries on a single webpage. So if you use the built-in {% paginate %} tag like this, when it takes you to page 2, all of the sections’ {% paginate %} tags will start showing page 2 content. And you’ll need to keep track of which section actually has the most pages, before building out your pagination nav.

// ...

{% set primaryPageInfo = null %}

{% for section, sectionName in sections %}

    {% set entries = craft.entries.section(section).limit(10) %}
    {% paginate entries as pageInfo, pageEntries %}

    // ...

    {# Does this section have the most entries (so far)? #}
    {% if not primaryPageInfo or pageInfo.totalPages > primaryPageInfo.totalPages %}
        {% set primaryPageInfo = pageInfo %}
    {% endif %}

{% endfor %}

{# Build out the pagination nav using the biggest section's pageInfo #}
First Page
{% if primaryPageInfo.prevUrl %}Previous Page{% endif %}
{% if primaryPageInfo.nextUrl %}Next Page{% endif %}
Last Page


Product Type Collections & Tags I'm pretty new to Craft and Craft Commerce and right now I'm struggling with the following: in the navigation I want a list item for every product type. This works with the following code:

{% for productType in craft.commerce.productTypes %}
    <li>{{ productType.name }}</li>
{% endfor %}

But how can I now link this product type to an collection template and show only products of this type?

And the second question is: If at least one product has the tag "new" I want a list item for this in the menu as well. I created a tag field for this. But how can I now check if there are products with this tag and can I link this to an collection template as well?

Thanks for your help!

Well as always with Craft there are many ways to skin this particular cat.

A simple approach would be to have a catalogue template (either just one for all product types or separate ones for each product type if you want to vary the format significantly).

Assuming just one template for your various catalogues, this could live in your  templates folder at e.g. _site/product-catalogue.html

You could set up a route in Settings->Routes, such that

*/catalogue pointed to  /_site/product-catalogue

this template would then load whenever someone went to e.g.

yoursite.com/monitors/catalogue

In there you could query for all products of that type and display them:

{% set segment_1 = craft.request.getSegment(1) %}
{% set products = craft.commerce.products.type(segment_1).find() %}

...and proceed from there any way you like, really, in terms of display.

In terms of building you nav:

{% for productType in craft.commerce.productTypes %}

{{ productType.name }}

{% endfor %}

(Another approach would be to add all the products to a category, and then use category fields and a category template to display your product list).

I haven't used tags much, and I am not sure I'm 100% on what you're asking (do you want to highlight sections with new products, or create an extra element in your nav for these?)....but in essense you'd probably have to search for products in that category and look for a tag of New.  Here's some sketch code:

{% for productType in craft.commerce.productTypes %}
   results = search for entries with this type that have the tag New
   if the length of results > 0

*** NEW *** {{ productType.name }}

   else

{{ productType.name }}

   endif
{% endfor %}

Craft docs on doing the search are here: https://craftcms.com/docs/searching


Complex custom SQL query with multiple relationships (Craft DB) For the Sprout Reports plugin I need to write a custom SQL query to get some Craft data. (We use this plugin so our client can easily generate CSV exports at any time from the CP).

As there are multiple relations with both Entries and Users, the query becomes quite tricky.. Any help in the right direction would be awesome!

-

This is the case:

We have subscriptions, which have subscription data and a relationship to a course (Entry) and a school (User). The course has a relationship to a sportsclub (User). We need a single SQL query that pulls all this data from the Craft database.

-

We have the following tables:

craft_sections

id|name
--|-------------
 1|subscriptions
 2|courses

craft_entries

 id|sectionId
---|---------
 50|        1       (subscriptions)
 51|        1       (subscriptions)
 52|        1       (subscriptions)
100|        2       (courses)
102|        2       (courses)
104|        2       (courses)

craft_content

id|elementId|name      |gender|city      |course_name     |school_name|club_name
--|---------|----------|------|----------|----------------|-----------|-----------
 1|       50|John Doe  |Male  |New York  |                |           |
 2|       51|Lisa Smith|Female|New Jersey|                |           |
 3|       52|Brad Bell |Male  |Washington|                |           |
 4|      100|          |      |          |Basketballcourse|           |
 5|      101|          |      |          |                |School 1   |
 6|      102|          |      |          |Volleybalcourse |           |
 7|      103|          |      |          |                |School 2   |
 8|      104|          |      |          |Swimmingcourse  |           |
 9|      105|          |      |          |                |School 3   |
10|      150|          |      |          |                |           |Sportsclub 1
11|      151|          |      |          |                |           |Sportsclub 2
12|      152|          |      |          |                |           |Sportsclub 3

craft_content elementId = craft_entries id and craft_elements id

craft_relations

id|sourceId|targetId
--|--------|--------
 1|      50|     100       (subscription -> course)
 2|      50|     101       (subscription -> school)
 3|      51|     102       (subscription -> course)
 4|      51|     103       (subscription -> school)
 5|      52|     104       (subscription -> course)
 6|      52|     105       (subscription -> school)
 7|     100|     150       (course -> sportsclub)
 8|     102|     151       (course -> sportsclub)
 9|     104|     152       (course -> sportsclub)

sourceId and targetId relate to the craft_elements table, where you can get the type of the element. The Ids also relate to the elemendId in the craft_content table.

craft_elements

id |type
---|-----
 50|Entry       (subscription)
 51|Entry       (subscription)
 52|Entry       (subscription)
100|Entry       (course)
101|User        (school)
102|Entry       (course)
103|User        (school)
104|Entry       (course)
105|User        (school)
150|User        (sportsclub)
151|User        (sportsclub)
152|User        (sportsclub)

craft_users

id|username
--|--------
 1|school_1
 2|school_2
 3|school_3
 4|sportsclub_1
 5|sportsclub_2
 6|sportsclub_3

craft_usergroups

id|name
--|-----------
 1|Schools
 2|Sportsclubs

craft_usergroups_users

id|groupId|userId
--|-------|------
 1|      1|     1
 2|      1|     2
 3|      1|     3
 4|      2|     4
 5|      2|     5
 6|      2|     6

-

The desired result from the query:

id|name      |gender|city      |course_name     |school_name|club_name
--|----------|------|----------|----------------|-----------|------------
 1|John Doe  |Male  |New York  |Basketballcourse|School 1   |Sportsclub 1
 2|Lisa Smith|Female|New Jersey|Volleybalcourse |School 2   |Sportsclub 2
 3|Brad Bell |Male  |Washington|Swimmingcourse  |School 3   |Sportclubs 3

I'll be happy to see the SQL answer if anybody posts it but I expect this is a very complex query to write manually for anyone without advanced SQL knowledge.

While this isn't an answer that solves the immediate question, I think a fair answer is that this type of query is complex enough that it probably makes sense to build a custom solution (as it sounds like you did) or wait until Sprout Reports (or another alternative exists) that makes it easier to extend the plugin to run more programmatic or memory-intensive queries for use cases like the one you describe.


Rename assets to lowercase As there is no native config to control the naming of assets I am trying to write a small plugin to do this.
Here is what I have;

    craft()->on('assets.saveAsset', function (Event $event) {
        if ($event->params['isNewAsset']) {

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

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

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

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

However, this currently results in a duplication of the extension like so;
model-rendering-image.jpg.jpg
special-services.jpg.jpg

If I remove this part of the code
'.'.$asset->getExtension()) then the asset isn't renamed at all.

Can't seem to get past this hurdle.

Anyone able to shed some light?

Also is there a reason that assets are not renamed to lowercase by default or why this isn't rolled in as a config option?

Just tested your code and it worked as you'd expect if you leave off the extra getExtension() call (the filename property already includes the extension).

$filename = strtolower($asset->filename);

If it's not saving for you with that, you've got some other error happening elsewhere.


Using the Group filter with Squarebit Charge plugin Has anyone had success using the Group filter with Squarebit Charge?

I tried a few different approaches, in each case getting array errors. Here is code:

{% set allCharges = craft.charge.charges.limit(3)|group('cardName') %}

{% for cardName, details in allCharges %}

{{ cardName }}

{% for details in allCharges %}
    {{ details.dateCreated }}...and more fields
{% endfor %}

{% endfor %}

This throws an error message "Key "dateCreated" for array with keys "0" does not exist."

If I dump(details) I see an array that looks like all the fields you would expect, including "dateCreated"

Any help would be appreciated!

I got this to work with the following:

{% set allCharges = craft.charge.charges.limit(5) %}
{% set charges = allCharges|group("dateCreated|date('F')") %}

{% for month, details in charges %}
    <div>
        {{ month }}

        {% for detail in details %}
            <p>{{detail.id}}{{detail.customerName}}</p>
        {% endfor %}
    </div>
{% endfor %}

Two things to note: the group filter was applied to the results of the Charges query, rather than applying it to the query itself; the second issue is that the Charge model contains sub-models,which will require an inner loop.


How to create a query to group alternate language pages? I'm trying to create a sitemap for a site with multiple locales.  An example of the format is described here, but as a quick summary: I need to output locales of related translated pages aside one another.

<url>
  <loc>http://www.example.com/english/</loc>
  <xhtml:link
     rel="alternate"
     hreflang="de"
     href="http://www.example.com/deutsch/"
     />
  <xhtml:link
     rel="alternate"
     hreflang="de-ch"
     href="http://www.example.com/schweiz-deutsch/"
     />
  <xhtml:link
     rel="alternate"
     hreflang="en"
     href="http://www.example.com/english/"
     />
</url>

To output a list of all entries like this I believe I need to query: All entries, from all locales, grouped by elementId.

I've tried to do this using $criteria->find() but I seem to run into two problems.

First, there appears to be no way to query all locales.  The best way I've found is to loop through all the locales.  I'm wondering if I'm overlooking something.  Right now I have:

foreach (craft()->i18n->getSiteLocales() as $locale)
{
  ...
}

A potential problem with doing it this way is that I won't be able to group the results of all locales by elementId during the query.

Second, once I have all the entries, I need to make sure they are grouped by elementId.  This does not happen by default.  The entry for each locale just gets the next available ID when it's created.  It seems the way to do this would be to use $criteria->order = 'elementId'; however, it doesn't appear Craft supports ordering a result set by elementId.

The ideal query would look something like this:

$criteria            = craft()->elements->getCriteria(ElementType::Entry);
$criteria->limit     = null;
$criteria->status    = 'live';
$criteria->sectionId = $sectionId;

// Problem #1: I want to return all locales like you can return all entries using null
$criteria->locale    = null;

// Problem #2: I want to group my results by Element ID
$criteria->order     = 'elementId';

$entries = $criteria->find();

Any ideas on what the best approach would be here?  Is there any crafty way of doing this or will I have to resort to using a custom query?

This query cannot be created in the "ideal" way described in the question using craft()->elements->getCriteria. It required several steps to build the results needed. The final solution was a bit specific to our needs. Here is some pseudocode that represents a solution:

$urls = array();

// Fetch all enabled locales
foreach (craft()->i18n->getSiteLocales() as $locale)
{
    // Confirm there are elements in a specific locale and get them
    ...
    $criteria->locale = $locale->id;
    $elements = $criteria->find();

    foreach ($elements as $element)
    {
        // Add each location indexed by its id
        $urls[$element->id][] = array(...);
    }
}

// Process what we created above and adjust it to fit our needs
$urls = $this->processUrlsIntoTheRightFormat($urls);