Element API access param in transformer Each of my entries has multiple categories (e.g. series, disciplines, and stages). I can get a list of elements related to a single category but I'd also like to get the category information as well (title, summary etc). Ideally, I'd like to pass the $slug to the transformer so I can grab the category from there, is that possible?

Here's my current code for an endpoint from elementapi.php

'api/series/<slug:{slug}>.json' => function($slug) {
  // get category by slug
  $series = craft()->elements->getCriteria(ElementType::Category);
  $series->group = 'series';
  $series->slug = $slug;
  $series->first();

  return [
    'elementType' => ElementType::Entry,
    'criteria' => [
      'section' => ['lessons'],
      'relatedTo' => ['targetElement' => $series]
    ],
    'transformer' => function(EntryModel $entry) {
      return structureEntry($entry);
    }
  ];
},

/*-------------------------------------------*/

function structureEntry($entry) {
  return [
    'id' => (int)$entry->id,
    'title' => $entry->title,
    'slug' => $entry->slug,
    'summary' => $entry->summary ? $entry->summary : null,
    'featuredImage' => $entry->featuredImage->first() ? getImageSizes($entry->featuredImage->first()) : null,
    'body' => $entry->body ? (string)$entry->body : null,
    'series' => $entry->series ? getCategoryData($entry->series) : null,
    'stage' => $entry->stage ? getCategoryData($entry->stage) : null,
    'disciplines' => $entry->discipline ? getCategoryData($entry->discipline) : null
  ];
}

function getCategoryData($categories) {
  $cats = array();

  for($i = 0; $i < count($categories); $i++) {
    $cats[$i] = [
      'id' => (int)$categories[$i]->id,
      'title' => $categories[$i]->title,
      'slug' => $categories[$i]->slug,
      'summary' => $categories[$i]->summary
    ];
  }

  return $cats;
}

Ideally, I'd like to do something like this:

'api/series/<slug:{slug}>.json' => function($slug) {
  // get category by slug
  $series = craft()->elements->getCriteria(ElementType::Category);
  $series->group = 'series';
  $series->slug = $slug;
  $series->first();

  return [
    'elementType' => ElementType::Entry,
    'criteria' => [
      'section' => ['lessons'],
      'relatedTo' => ['targetElement' => $series]
    ],
    'transformer' => function(EntryModel $entry) {

      $category = craft()->elements->getCriteria(ElementType::Category);
      $category->group = 'series';
      $category->slug = $slug;
      $category->first();

      return array_merge(structureEntry($entry), structureCategory($category));
    }
  ];
},

Any help would be appreciated, thanks!

I managed to get access to the slug in the transformer function by using use. I'm not sure if it's the correct way but it works for now.

'api/series/<slug:{slug}>.json' => function($slug) {
  // get category by slug
  $category = craft()->elements->getCriteria(ElementType::Category);
  $category->group = 'series';
  $category->slug = $slug;
  $category->first();

  return [
    'elementType' => ElementType::Entry,
    'criteria' => [
      'section' => ['lessons'],
      'relatedTo' => ['targetElement' => $series]
    ],
    'transformer' => function(EntryModel $entry) use ($category) {

      $firstCategory = $category->first();

      $cat = [
        'id' => $firstCategory->id,
        'slug' => $firstCategory->slug,
        'title' => $firstCategory->title
      ];

      return array_merge(structureEntry($entry), structureCategory($cat));
    }
  ];
}


How to count ad impressions We're adding advertising to our Craft site. The ads come from our business members and are displayed randomly with article pages, based on tags and categories. All that is working fine.

The question comes up, how to report impression counts of the ads back to the advertisers? I'm newish to Craft; I don't know if it is possible to write back to a field of an asset (displayCount = displayCount + 1 kind of thing).

Any ideas or suggestions would be appreciated.

Since it sounds like you're rolling-your-own, and can afford a relatively simple implementation, I'd recommend checking out the seq(…) Twig function that Craft provides.

{% do seq("ad-impressions-#{ad.uid}") %}

Then, if you have a dashboard of some kind for advertisers/partners, you could display those tallies by iterating over their “owned” advertisements:

{% for ad in ads %}
    {{ ad.title }} views: {{ seq("ad-impressions-#{ad.uid}", null, false) }}
{% endfor %}

Here, the third argument tells the function to read the value, but not increment it.

  Of course, this is extremely crude. It assumes you only need to count the number of times an ad is rendered into a page, and makes no guarantees about how many times it’s actually seen. It also won't increment if the page is cached.

Overall, I'd recommend outputting the ad with some kind of identifying information, and firing a custom Google Analytics event… or—time permitting—write a custom controller to ping via AJAX when an ad is actually displayed in a browser. Keep in mind that somewhere in here, you're apt to be able to deliver a better product with an existing plugin!


Don't allow multiple users with same the password I am working on a user registration page with AJAX.
I noticed that users are able to create accounts which have the same passwords. How do I disable this?

If users want to create an account with the same username I do get an error message, why does that not happen for passwords?

Thanks!

This is not a common practice out of the box, and not even desirable as you may also imply that other users have the same password creating the possibility for this new user to just try different emails with that password.

What you could do is run via a plugin the user password against a list of weak passwords, and return a message if the password entered is easy to break.

If 2 or more users have the same password and their password is good, there's no reason for letting one of them know about the existence of the others. The same thought does not apply to emails or usernames though, since they are the unique ids within the system.


Freeform - limit who can view 'results' page I've got a form that redirects to a results page on submission. Results page currently lives at /form/results/[submission.id]/success/

The results page shows the user's answers, and a bunch of other results.

Is there a 'best' way to make it so that this results page is only accessible for the current user/session? I don't want to have it be available for any random joe to just try IDs and see someone else's results.

The short answer is that freeform doesn't do it.

The longer answer is that you can cheat with a cookie.

I used a cookie. Used this plugin: https://github.com/nystudio107/cookies

In Freeform's admin, I created a hidden field called "cookie validator" and added it to my form.

On the page that my form lives on /form/, I added a cookie that sets a value of a large random number.

{% set randomNumber = random(9999999999) %}
{{ setCookie('formcookie', randomNumber, now | date_modify("+1 hour").timestamp ) }}

{{ form.render }}

{% set cookievalueJS %}
  $(document).ready(function() {
    $('#form-input-cookievalidator').val("{{ randomNumber }}");
 });
{% endset %}
{% includeJs cookievalueJS %}

This creates a random number first. Then sets a cookie with that number as a value. And then sets the input field to have that same number.

Then, on my form results page /form/results/

Instead of using an 'isSuccess' check, I check for the cookie & field value...

{% set submissionId = segment2 %}
{% set form = craft.freeform.form('myForm') %}
{% set submission = craft.freeform.submissions({
    id: submissionId,
    form: formHandle,
}).first() %}

{% if myCookie  ==  submission.cookievalidator %}
  {# render all the submission data here #}
{% else %}
  {# show the "nothing to show here" page #}
{% endif %}

NOTE: I'm going to move this to an all https site eventually, and will probably have to swap the cookie to be a securecookie. But that's pretty straightforward with the cookie plugin.


Modify/add to price based on custom field? Is there a way to modify a variant's price based on a custom field in the product?

To clarify, Let's say I have a matrix field with a block that has a text input with the handle name and a numeric input field with the handle price. This is then outputs as a radio button select list in the template like "Original" and "Name". When the "Name" radio button is selected, the price is picked up from the field price in that matrix block. The user could then add to cart with the modified price.

Any way to do this without plugins, or is there a plugin available for this logic? I'm not PHP savvy, so any light that can be shed on this is much appreciated. Ideally there's a way to do this within the template.

You could simply use variants to handle this couldn't you?  A non-name and named variant, each with a different price.

There's no other built in way to do what you want without PHP, I think.  The PHP would not be too complex though, if you fancy adventuring into Craft plugins, which are super-useful with Commerce in general, opening up all sorts of extra possibilities.


Commerce categories issue I am trying to develop an email commerce site that is easy for customers to navigate. The way that I would like to do it is so that I have a range of different parent categories and that when a customer clicks in this it opens a page where the different child categories are displayed with image tiles. When a customer clicks onto this tile it will then bring up the products in that child category.

Is this possible at all and if so what is the best way to go about making it operate in this way?

Many thanks for any help in advance

This is absolutely possible with Craft & Commerce.

First, you would set up your categories group - say, Product categories.  You can add custom fields to these categories, for example an image field for an image that represents the category.

Then, you'd enter your category data - categories are inherently hierarchical (well, taxonomical really) - so it's easy to set up Parent -> Child structures.

Next, you would add a categories field as a custom field to your products when setting them up in Commerce.

Then, when you enter your products you can choose which category (or categories) the product should be in.

Finally, you would set up templates to actually display all this: probably one template to display the parent categories list, another to display which user chosen sub-category is required, and then finally templates for your product grid and most likely another for your actual product pages.

It sounds like a bit of a process spelled out like that, but if you step through setting up the fields and entering some data, and then start with very simple templates to just list out the things at each stage, you will find it is quite easy to set all this up - the only complexity really comes from the design angle -> i.e. making it look and work nicely!

Good luck with it!


Displaying entries from a specific custom date year I've a list of entries, all with custom dates.
Is there a way to show entries from a specific year, just using the custom date rather than the posted date?

Any help is much appreciated!

I ended up using this code.

{% set upcoming = craft.entries.section('section').order('customDate')%}

{% for entry in upcoming %}
    {% if entry.customDate =='2018-10-12' %}
        {{entry.title}}
    {% endif %}
{% endfor %}

Works for now anyway.


Output raw html from if statement and combining strings? I have the following code:

If imageWidth is specified as 120, it should output:

However it is outputting this:

I've tried using |raw but that doesn't work.

Any ideas?

Thanks

{# set test variable, to make your code work #}
{% set block = {imageWidth: 300} %}

{# the real output #}
<img{{ block.imageWidth|length ? (' width="' ~ block.imageWidth~ 'px"')|raw }} />

Works for me


Twig in External jQuery I'm a little bit new to Craft, but it's already my favorite CMS, even after 8 years or so in Wordpress.

Here's what I need to do. I have integrated a preloader into my site, using preload.js, and I need to know if there is a way to utilize Twig within my JavaScript files.

Essentially, preload.js gets all of the assets to preload from a load Manifest, which is created with JSON. I got this working properly as an inline script, simply pulling the sources of all my assets, based on this question. What I need to know is, is there a way to use these Twig tags inside of an external JavaScript file? I know that there is in liquid, but I'd like to get this working here as well.

Thanks.

Just put your javascript file in the templates folder. E.g. place a file called external.js in the folder craft/templates/includes/. Then include it like this <script src="/includes/external.js" type="text/javascript"></script>

I don't know if this is an official way to do it, but it works.


MySql 5.7 error - field doesn't have a default value We've just switched server for one of our sites and I am now encountering a MySql error on one of our plugins. The MySql version on the new server is 5.7 and throws an error as a field has no default value.

Do we now need to adjust our db model and records to add Null when we define the attributes to any fields that don't have a default value set?

Strange thing is when I look at the database table some fields have been set up with 'Allow Null' set and others haven't and these fields are exactly the same type for example in both model and record file I have these 2 fields one has been set to Allow Null the other hasn't??

'profession' =>  array(AttributeType::Name, 'maxLength' => 255, 'required' => false),
'city'       =>  array(AttributeType::Name, 'maxLength' => 255, 'required' => false),

Any ideas or suggestions?

Running latest craft 2.6.3016 on php 7.1

Cheers

The STRICT_TRANS_TABLES mode was added to the default SQL mode in MySQL 5.7.5 and is likely causing the error to be thrown:
https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html

You can either disable STRICT_TRANS_TABLES mode in your database (there are plenty of articles explaining how), or add default values to your fields (which I would recommend).


Change the size of a users profile photo? I have a website where I am pulling a list of staff members from the Craft users. You can add individual fields to the users element, but it seems the image for the photo is incredibly small is size and lacking in quality.

Is there a way to change the size of the profile photo? Hopefully I can just apply an image transform on the user profile photo. Adding another field for a photograph seems redundant.

I found the answer on the Craft website under the UserModel section:

getPhotoUrl( size )
Returns a URL to the user’s photo at a given size in pixels (defaults to 100). You can also pass in "original" if you want to get a non-resized photo back.

Although this does answer my question, I feel the behavior between handling this "asset" compared to an actual native asset is a little cumbersome, especially considering if I wanted to apply an image transformation on the original file.


Craft 3 CP performance I'm wondering what kind of performance I should expect from Craft 3's Control Panel.

I've created a (clever) structure, where I have matrix field which contains a superTable field.

Matrix

Row (block type)

Column (superTable)

Style (dropdown)
Image (an asset)
Text (redactor)

The idea being that I can add rows, and inside the rows I can add a number of columns and fill the column with an image and/or text. From this I create a bootstrap grid.

Problem is that editing entries get really slow if and when the entry has larger amount of rows and columns. On the worst page I have 24 rows and loading the page makes 362 db queries and takes well over 10 seconds to load all redactor fields. This is way too slow to be usable.

Then I started again from an empty page, which has fields for:

title
categories
hero image
ingress/description
and a button to add rows

An empty page creates 116 db queries. Every time I add a new row it adds 9 db queries. Every new column adds 3 db queries. So 10 new rows would create at least 90 new db queries, which is beginning to be problematic.

So is this the amount of db queries that I should expect, ie. is this normal? Is there something fundamentally wrong in the way I created the fields for the page using matrix and a superTable? What can I do to improve the performance?

(Running Craft 3.0.10.2 on Windows/IIS and MariaDB)

Is this a problem with only the dashboard, or the front-end also? Although this is a bad answer, waiting a few seconds to load the dashboard shouldn't be a huge deal. You will only need to access it a few times while editing content. On the other hand, there are ways to improve the front-end performance such as Eager Loading.

You can approach this conceptually by creating a simpler data model. In my opinion, super table inside of a matrix is a sign that you are doing something wrong. There is a reason that matrix in matrix is not supported, probably because of this performance issues like this.

You can also extend the dashboard or something to implement eager loading or cut down on db queries but I don't think it is worth the effort. Maybe you can mention something to Pixel and Tonic and they will improve this in a later version of craft.


White pages on Frontend I'm quite new to Craft. I was working on templates, then I logged in to create a new section and now any frontend route is returning a blank page.
500 Internal Server Error.

I restarted, Nginx, reboot Ubuntu server, etc.

Control Panel is working fine, I haven't touched any configuration file that I'm aware of.

Any idea what I did wrong?

Error with Twig templates.

In case anyone is interested, I was using extends in a template that was include by a index template. Generating a sort of bad recursion that emptied memory ( PHP Error ).


Is a migration needed if defineContentAttribute is changed from false to an AttributeType My plugin's FieldType was initially setup with defineContentAttribte set to false.  I and switching it to AttributeType::Mixed. Does a migration need to be written to account for this change? If so how would this be written since it is the specific input name that is added to the content table?

Does a migration need to be written to account for this change?

Yes.

  how would this be written since it is the specific input name that is added to the content table?

Just thinking out loud:

Select all fields from the database that have your field type.
Determine if they are in a Matrix context (craft_matrixHandleContent) a global context (craft_content).
For each grab their handles and build the column name.
Alter table to add the column to the appropriate table.


Navigation with AJAX I haven't used AJAX a lot, but what I want to do is the following:

I have a top navigation that outputs entries from a structure which link to various singles that display my data.
I want my navigation to stay and not reload when going to another page. How would I implement AJAX combined with Craft for that?

I'm not sure this is a really a Craft-specific question, but here's a basic strategy:

Build your nav and pages to work without any Ajax calls. Make sure your nav is output consistently (e.g. in <nav class="primary-nav") as well as the content of the page (e.g. in <div class="main">).
Now implement your JavaScript. You want to (a) intercept navigation link clicks to stop a full page reload, (b) Ajax in the new content, (c) move the active class to the clicked navigation link, and (d) change the URL to the new page address. Make sure to use History.js to smooth out any difference in browser implementation of HTML5's history API (including pushState).

Here's a demo (and code) I cooked up with static HTML. It's based on Andrew Fricke's post titled Rolling your own PJAX Implementation with History.js


After updating, getting "Could not resolve the subpath" error After updating to 2.6.2973, saving any entry fails, resulting in an Internal Server Error: "Could not resolve the subpath '{slug}'".

I've read the similar errors on here which trace back to Matrix Asset objects and dynamically-named folders, though I'm not using any dynamically-named folders, and I can't tell where it's pulling {slug} from, and/or what's causes the issue. I've gone through and double-checked and resaved both asset directory and field configurations.

The log again points in the direction of the Matrix Asset, and refers to the folder id "1" -- a Local Source which has both the System Path and URL completely hardcoded. The top of the trace looks like so:

#0 /[directory-path]/craft/app/fieldtypes/AssetsFieldType.php(707): Craft\AssetsFieldType->_resolveSourcePathToFolderId('1', '{slug}', true)
#1 /[directory-path]/craft/app/fieldtypes/AssetsFieldType.php(327): Craft\AssetsFieldType->_determineUploadFolderId(Object(Craft\Model))
#2 /[directory-path]/craft/app/services/ElementsService.php(1618): Craft\AssetsFieldType->onAfterElementSave()
#3 /[directory-path]/craft/app/services/MatrixService.php(778): Craft\ElementsService->saveElement(Object(Craft\MatrixBlockModel), false)
#4 /[directory-path]/craft/app/services/MatrixService.php(882): Craft\MatrixService->saveBlock(Object(Craft\MatrixBlockModel), false)
#5 /[directory-path]/craft/app/fieldtypes/MatrixFieldType.php(533): Craft\MatrixService->saveField(Object(Craft\MatrixFieldType))

This error stalls all the client's content entry, so I hoping for any additional insights or tips. Thanks so much.

If you're setting an dynamic upload folder location for an Assets field inside of a Matrix field, you need to preface things like {slug} with {owner.slug}.

See the note about dynamic subfolders on an Assets field inside of Matrix here: https://craftcms.com/docs/assets-fields#dynamic-subfolder-paths


Correct timezone for AttributeType::DateTime in CP I've written a plugin that stores records in it's own table. I can see that the dateCreated and dateUpdated fields are stored in UTC.

When I want to display them in a CP template, I'm using populateModel and my model contains 'dateCreated' => AttributeType::DateTime.

If I output this with {{ entry.dateCreated|dateTime }} then I'm still getting UTC time and not BST (the Timezone in Settings).

If I use {{ entry.dateCreated|date('d M Y H:i', 'Europe/London') }} then it's correct.

Is there any way to get the date with the correct timezone set automatically?

It's a bit confusing at the moment (should be cleaner in the upcoming Craft 3), but for now, if you use {{ entry.dateCreated|date }}, it should take the timezone into account and display the correct time.


Display categories which only contain entries I'm grabbing a list of categories and displaying their entry count.
How can I only display categories which have entires? So I'm not getting any with 0 in them, which is occurring as I have a few entries not yet published with new categories.

{% nav category in craft.categories.group('insights') %}
{# Get the count of entries related to `category` #}
{% set entryCount = craft.entries.relatedTo(category).total() %}

        {{ category.title }} ({{ entryCount }})

{% endnav %}

A simple but effective solution would be to just wrap the output in a conditional.

{% if entryCount %}
    <li>...</li>
{% endif %}


Rename asset file upon upload? Is there any way to rename files upon there upload to an assets field?

I know I can hit the options of the file and rename manually, but was wondering if there was a way to do this automatically? i.e. renamed based on the entry ID.

Craft has the ability to dynamically add subfolder paths to Assets when you are creating the Asset field in the control panel.

Tags like {slug} and {author.username} are some of the available options for creating the directories.

I know it has been brought up before and they have acknowledged the possibility. So who knows, maybe we will see it in 2.2?

For now, if organization is a concern I recommend using subfolders to keep it clean.


Grouping related fields together Is there a mechanism for grouping related fields in an entry besides:

a) putting them in a tab - which I generally reserve to group fields at a higher order (e.g content/data/meta)
b) putting related fields inside a matrix block with a limit of 1, which feels like I'm adding a level of complexity to my content model.

I have various modules in a page, so i've taken to labelling them with a common prefix for each module (as in 'Homepage Hero - Background Image', 'Homepage Hero - Subheading'), but all of the fields visually gel together in the UI in a somewhat indistinguishable list.

I suppose changing my use of tabs would serve my purpose, but could look quite unruly on an entry with many elements.

You could put them in a supertable which supports nested matrix etc.
All the info on supertable here: https://github.com/engram-design/SuperTable


Custom URL based on Categories I am very new to this CMS and I was able to set it up, import some content from csv files.

I have set up templates and right now if someone clicks on the article, the URL is www.example.com/articles/{slug} of the article. This is all fine if I wasn't migrating from another system and we have a ton of articles and the URL was based on SEO requirements.

I have set up a channel type and one of the fields is Category type. I have 2 more category type fields but I don't use them to create the URL.

Here is the screenshot of what it looks like

A lot of content from olden days doesn't have the second category (so would just belong to Analog/ Mixed Signal ICs) but the newer content (from last 3 odd years most likely has it). So when the Url is display I want the URL to be either www.example.com/Analog_Mixed_Signal_ICs/Title
or
www.example.com/Analog_Mixed_Signal_ICs/Amplifiers/Title

I am not sure if this simple or complex but I would appreciate if someone can tell me how to achieve this.

I wouldn't normally set up a site like this — but given your setup, the following should work.

In the category settings, make sure that your category has 'Entries in this section have their own URLs' checked.
Set your category url format to:

top-level: {slug}
nested categories: {parent.uri}/{slug}

Set your article entry url format in the channel settings to {category.last.uri}/{slug} (where 'category' is the handle of your category field.)

Note the use of last. Categories will be returned as an Element Criteria Model which behaves much like an array (even if there is only one defined). The use of last will return the last category element, which should be the uri pattern that you're looking for.

Of course, if you have other routes in the CMS you will have to be careful about routing conflicts.

As a side note, you might want to consider using a 'structure' instead of 'categories'. I commonly use a single structure that represents all of the top level pages in a site, using Entry Types to distinguish the various field requirements and page layouts. You can then include the appropriate template layout automatically based on 'entry.type'. Likewise, you can use this structure to easily generate your site nav, and be fairly confident you won't run into any routing conflicts. The only reason I mention this is that you seem to already be heading in this direction with your current setup.

Edit: I might also add that you will want to make your category field required, otherwise there will be no route to the article in question.


Search for href parameter in rich text field I'm trying to find using craft search "bitly" urls in body rich-text field in articles. It's for generation of list of popular articles.
So if query is a link (like "http://bit.ly/1eZFQMY") search doesn't find anything.

Tried "fuzzy" search and all methods listed on craft search page.

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

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

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


Craft 3: how can I set dynamic Base URL in sites setting? Sites localized versions are setup using Base URL like this:

— http://{baseUrl}/en/
— http://{baseUrl}/fr/

But {baseUrl} variables are not transformed using craft.app.sites.getAllSites().

{% set sites = craft.app.sites.getAllSites() %}
{% for site in sites %}
    {{ site.baseUrl }}
    // → outputs http://{baseUrl}/locale/ instead of http://mywebsite.com/en/
{% endfor %}

Whereas baseUrl are set from general.php:

'aliases' => array(
    'basePath' => '/mywebsite.com/htdocs/',
    'baseUrl'  => 'http://www.mywebsite.com/'
),

So as of Craft CMS 3 RC7, they added a new alias() Twig function.

So what you can do is something like this in your general.php:

'aliases' => [
    '@basePath' => getenv('CRAFTENV_BASE_PATH'),
    '@baseUrl' => getenv('CRAFTENV_BASE_URL'),
],

(or whatever/however you want to set them). These aliases can be used in sites’ Base URL settings, volumes’ Base URL settings, and Local volumes’ File System Path settings in the AdminCP.

And then in your templates, you can do something like:

{{ alias('@baseUrl') }}
{{ alias('@baseUrl/assets/img/' }}

To resolve the alias there. I changed Craft 3 Multi-Environment to leverage aliases in this way (rather than having them in the .custom config), and it's documented in detail in the Asset Volumes and Aliases.

You do not need to be using Craft 3 Multi-Environment to utilize them in the same way, this is just a live example that's handy to point to.


Return Matrix Field block number Just wondering if there's a way to return the matrix block number during the loop?

For example:

{% for block in entry.myMatrixField %}
  {% if block.type == "quote" %}

{{ block.quote }}

  {% endif %}
{% endfor %}

Might return something like this:

Curabitur aliquet quam id dui posuere blandit.

Curabitur aliquet quam id dui posuere blandit.

Curabitur aliquet quam id dui posuere blandit.

Thanks, Mark

Yes that's possible, all Twig loops have a loop variable:

  loop.index - The current iteration of the loop. (1 indexed)
  loop.index0 - The current iteration of the loop. (0 indexed)

Example:

{% for block in entry.myMatrixField %}
  {% if block.type == "quote" %}

{{ block.quote }}

  {% endif %}
{% endfor %}


XAMPP Windows 10 - Could not find your craft/ folder error I'm new to Craft CMS and would like to getting started, I searched for several hours now but I was not able to find an answer.

I downloaded and copied craft to my htdocs folder, created a database and changed the db access but when I open my page I get

Could not find your craft/ folder. Please ensure that $craftPath is set correctly in C:\xampp\htdocs\craft\public\index.php

I think I have to change the permission of that folder but I have no idea how to do this. Could you help me?

I didn't change any path, so it is correct and points to the right file but there is only one directory visible in C:\xampp\htdocs\craft\ in my browser

Edit:
my Files looks like this
htdocs
-craft
--craft
---app
---config
---plugins
---storage
---templates
---.htaccess
---web.config
--public
---index.php

I believe the problem is that you've got craft within htdocs, so your web server is trying to run craft from the root, instead of where it should be, /public

To illustrate, this is where htdocs should be.

-craft

--craft
---app
---config
---plugins
---storage
---templates
---.htaccess
---web.config

--public <- htdocs
---index.php

I suggest, to test, that you change the httpd.conf to make apache run from the public folder rather than the pre-made htdocs folder xampp has given you. Go into the xampp config, click on httpd.conf and change the following lines:

DocumentRoot "your\path\to\htdocs\craft\public"

and

<Directory "your\path\to\htdocs\craft\public">

Restart your server, and you should be golden. On windows, you shouldn't have any permission issues with folders.

As an example, here is what my lines look like:

DocumentRoot "D:\Documents\work\bud\public"
<Directory "D:\Documents\work\bud\public">

I'd avoid just dumping the code in the pre-made htdocs folder provided and just route your httpd.conf to wherever your codebase is.


Many entry fields, only one db request? Craft 101: I have entries with many different fields, so I'm doing something like this:

{% set var = craft.entries.section('foo').slug('bar').first() %}

{% if var %}
  {{ var.field1 }}
  {{ var.field2 }}
  {{ var.field3 }}
  etc...
{% endif %}

Does Craft fetch the entry only once or every time the variable is called? I'm guessing only once but I'm not too sure, and some entries have 50+ fields.

The statement is only executed once.

You are essentially creating an elementCriteriaModel, returning the first element using the .first() parameter (which in this case is an Entry Model), and storing it in a variable; which you then can use to access your field values.

If you want to further increase performance you can wrap the whole block in a cache tag, which will speed up subsequent requests.


Simplify Twig/JS loop code Can any help simplify this js/twig code? The code links to some tabs that show floorplans of the property being sold. The specified aria-controls refers to a supertable field called floorLevel that has the loop.index included, so for example if I put [aria-controls='{{ row.floorLevel }}{{ loop.index }}'] it would output those names. I got it working so that when the user clicks on the tab it also changes the separate information about the measurements, but I couldn’t find of a less manual way of doing it, but I’m sure there must be an easier way?

{% includejs %}
{% for row in entry.floorplans.limit(1) %}
$( "[aria-controls='groundFloor1']" ).on( "click", function() {
  $( "#dimsTarget1" ).addClass( "is-active" );
  $( "#dimsTarget2" ).removeClass( "is-active" );
  $( "#dimsTarget3" ).removeClass( "is-active" );
  $( "#dimsTarget4" ).removeClass( "is-active" );
  $( "#dimsTarget5" ).removeClass( "is-active" );
});
{% endfor %}
{% for row in entry.floorplans.limit(1) %}
$( "[aria-controls='firstFloor2']" ).on( "click", function() {
  $( "#dimsTarget2" ).addClass( "is-active" );
  $( "#dimsTarget1" ).removeClass( "is-active" );
  $( "#dimsTarget3" ).removeClass( "is-active" );
  $( "#dimsTarget4" ).removeClass( "is-active" );
  $( "#dimsTarget5" ).removeClass( "is-active" );
});
{% endfor %}
{% for row in entry.floorplans.limit(1) %}
$( "[aria-controls='secondFloor3']" ).on( "click", function() {
  $( "#dimsTarget3" ).addClass( "is-active" );
  $( "#dimsTarget1" ).removeClass( "is-active" );
  $( "#dimsTarget2" ).removeClass( "is-active" );
  $( "#dimsTarget4" ).removeClass( "is-active" );
  $( "#dimsTarget5" ).removeClass( "is-active" );
});
{% endfor %}
{% for row in entry.floorplans.limit(1) %}
$( "[aria-controls='thirdFloor4']" ).on( "click", function() {
  $( "#dimsTarget4" ).addClass( "is-active" );
  $( "#dimsTarget1" ).removeClass( "is-active" );
  $( "#dimsTarget2" ).removeClass( "is-active" );
  $( "#dimsTarget3" ).removeClass( "is-active" );
  $( "#dimsTarget5" ).removeClass( "is-active" );
});
{% endfor %}
{% for row in entry.floorplans.limit(1) %}
$( "[aria-controls='basement5']" ).on( "click", function() {
  $( "#dimsTarget5" ).addClass( "is-active" );
  $( "#dimsTarget1" ).removeClass( "is-active" );
  $( "#dimsTarget2" ).removeClass( "is-active" );
  $( "#dimsTarget3" ).removeClass( "is-active" );
  $( "#dimsTarget4" ).removeClass( "is-active" );
});
{% endfor %}
{% endincludejs %}

You can select elements by class and give your html elements custom data attributes.

When this is your clickable html element with the corresponding div

<button data-id="dimsTarget4" class="myButton">

Your jquery could be

$('.myButton').click(function(){
    var containerId = $(this).data('id');
    $('.myContainer').removeClass( "is-active" );
    $('#'+containerId).addClass( "is-active" );
})

And that's basically it. You'll remove the class from all your divs and add it to the one specified in your data-id attribute.

You won't need any twig elements in your JavaScript (which is much better) and define everything in your twig template. That way your Javascript will behave independently. When you change your html you won't need to change your Javascript that much and you can reuse the code

Note: I just used the button as an example. You can insert whatever class name or html element you like. Since you didn't mention the structure of your html I decided to use a button


Focal point: more control? I originally had this setting in twig for gallery thumbnails:

{% set square150 = {
    mode: 'crop',
    width: 150,
    height: 150,
    quality: 75
    position: 'center-center'
} %}

<img width="{{asset.getWidth(square150)}}" height="{{asset.getHeight(square150)}}">

I noticed focal point doesn't apply, so I removed the position property as described on https://docs.craftcms.com/v3/image-transforms.html

So now it's

{% set square150 = {
    mode: 'crop',
    width: 150,
    height: 150,
    quality: 75
} %}

and the focal point works (I'm writing this out here because it took me some time to find out).

But it seems to me that the cropping is kind of generous, the area of the thumbnail is quite large. It does contain the focal point, true. But the focal point isn't always in the center of the image, as I'd have expected.

I'm sure the current behaviour is fine for many use cases.

In mine, what I'd expect is that for the focal cropping, the extract of the image is zoomed in so far that the focal point is in the center.

So something like...

{% set square150 = {
    mode: 'crop',
    width: 150,
    height: 150,
    quality: 75
    position: 'focal-point-center-center'
} %}

Is that possible and did I interpret the behaviour correctly?

There's no way of doing that natively.

When you're cropping an image with Craft, it zooms in as little as possible.  So, if you have an image that's 800x600 and you crop a square at 500x500, Craft won't zoom in at all.

When cropping is finished, the next task is to get the focal point as close to the center of the final image without crossing out of bounds.

Consider if Craft tried to put the focal point in the center no matter what. If the focal point was 100 pixels away from an edge and you wanted a square of 300x300, that would result in 1.5x zoom which would be a less desired outcome for many people.


How to localise page url in a multilingual site, how can i place multilingual links to content.

i.e. in the footer i would place a Imprint but in anohter language the slug might be /de/germanImprint...is there an easy helper to always get the right url from the english slug?

This is how to "translate" a slug:

{% set enSlug = 'work' %}

{# Get the ID of an entry with that english slug #}
{% set enId = craft.entries.slug(enSlug).locale('en').first().id %}

{# Use the entry ID to get the german slug #}
{% set deSlug = craft.entries.id(enId).locale('de').first().slug %}


Include a template that sets variables (global template variables) I'm essentially looking for a way to have a template that runs through a bunch of sets that I might use throughout my templates.

The problem is, if I include in a template with an extends, it dies up with:

  A template that extends another one cannot have a body.

{% include '/_resources/variables.twig' %}
{% extends '/_layouts/default.twig' %}

Some research indicates that maybe this isn't easily done with Twig parsing alone:
https://stackoverflow.com/questions/20410194/use-twig-custom-set-variables-from-an-include
https://groups.google.com/forum/#!topic/twig-users/QKdpWAxLdjE

So, what would be the best way to achieve this? My initial thought would be a plugin that you gave the path of a template, which preloaded things into variables.

I realize some variables (strings) could be done via macros. But, for example, I have a set usStates = {...} that is a big hash of state codes and names.

There are actually two issues with this approach. The first, and the direct reason you’re getting that Twig error, is that templates that extend another template can only output things within {% block %} tags. Any HTML that gets output outside of those tags (either directly or via {{ output tags }}) will result in that Twig error.

The {% include %} tag is in the same boat. Its only purpose (as far as the parent template is concerned) is to output the results of a child template. So like {{ output tags }}, you can’t place it outside of {% block %} tags. If you really want to include a template within these nested templates, you will need to move it to within your {% block %}.

Even if you did that, though, you’d then run into the second issue: Any variables that are set/modified within an included template will not bubble back up to the parent template. For example, if you had these two templates:

parent template:

{% include "_inc" %}
{{ foo }}

child template (_inc.html):

{% set foo = 'bar' %}

That foo variable would actually be discarded as soon as Twig was finished rendering _inc.html; nothing that happens in there will have any effect on the parent template. (As I said, the only purpose of the {% include %} tag as far as the parent template is concerned is to output the rendering result of the included template.)

However, it’s still probably possible to achieve what you want when you consider the order in which these templates are going to be processed:

Everything besides the {% block %} tags in the requested template (the one with the {% extends %} tag)
The layout template (_layouts/default.twig), including its {% block %} tags
The requested template’s {% block %} tags

Knowing that, you can probably just set your variables you’re trying to set from within _layouts/default.twig, and they will be available within the requested template’s {% block %} tags.

requested template:

{% extends '_layouts/default.twig' %}

{% block content  %}
    {{ foo }}
{% endblock %}

layout template (_layouts/default.twig):

{# Set the variables you were trying to set in _resources/variables.twig #}
{% set foo = 'bar' %}

{% block content %}
{% endblock %}


"Subtemplates" for entry using routing? Suppose I have a section for Products, that uses the template at products/_entry and is set up to have the URL format of 'products/{slug}'.

Our existing page structure shows a Product page when you go to the URL (such as example.com/products/cool_product, but we also have a sub-page for "Product Details" which we would get to (using the previous example) by going to example.com/products/cool_product/details.

Is something like this possible with Craft routes? I've tried adding a route in craft/config/routes.php that looks like:

return array(
    'products/<slug>/details' => 'products/_details'
);

however that doesn't do what I'd expect, which is load the product entry using that slug and display the template (which would in turn display the relevant data from that product entry)

Do I need to have something in my _layout.html that catches such a request somehow? I'm a bit confused I guess. I suppose I can handle the request a bit more manually in the template by parsing the request and loading the product that way. I guess I'm hoping there is something a little more elegant (read: I'm lazy )

You might check out the routing docs on accessing subpatterns in your templates.

Here is the example given in the docs (which provides the variables 'year' and 'month' to the template that correspond to the matched uri segments — which would match `news/2015/02'):

'news/(?P<year>\d{4})/(?P<month>\d{2})' => 'news/_archive',

So I would presume you could do the same using your products (I'm terrible with regular expression though, so please check the match syntax).

'products/(?P<slug>[^/]+)/details' => 'products/_details',

Fyi, the variable is defined using (?P<name>...), where '...' is the pattern to match. So in this case the variable 'slug' (or whatever you defined it as in your regex pattern) should now be available as a variable in your template, which you can use to retrieve the entry.

{% set entry = craft.entries.section('mySectionHandle').slug(slug).first() %}
{% if entry %}
    {{ entry.title }}
    ...
{% endif %}

When you create the link to that page you would naturally want to include the slug:

View details

Untested.


How to display success message using the Contact Form plugin Kind of feel silly having to ask this but I cannot for the life of me get a success message to display after the redirect when the Contact Form submits.

I just am not sure how to call it in the template view.

I have tried various things like this:

{% set success = craft.config.get('successFlashMessage', 'contactform') %}

{% if success %}

{{ success }}

{% endif %}

But just cannot seem to grab it.

I did look at the documentation on Github and was not able to find it.

You can see in the code for the plugin on GitHub that it sets a 'notice':

craft()->userSession->setNotice($settings->successFlashMessage);

As the official documentation mentions, this can later be grabbed with the following code:

{% set message = craft.session.getFlash('notice') %}

Then used as a normal message thereafter.

{{ message }}


Is it possible to replace uploaded assets? I have a site that uses several PDF forms that update from time to time. Instead of adding a new asset, I would rather replace the existing one.

I couldn't see how to do that from within the Craft admin. I suppose it's possible to do via FTP, but I'd really like it to be able to be done by the client.

Am I missing something, or is this not possible at this time?

Thanks

This actually is possible if you navigate to the folder or sub folder where you are trying to add the asset and then upload a file with the exact same file name.

Craft will ask you if you want to replace the existing file or upload another version with an appended name (for example "my-file-1.txt")


How to check for new entries periodically from the front-end? I would like to check periodically (every 5 seconds for example) whether there are new entries in a channel. If yes, I would like to present a refresh button on the website (with the number of the new entries).

So, I probably need a javascript which executes every 5 seconds a database query for the id of the latest entry and compares that to the last entry shown on the current page.

But I guess that javascript is not able to execute a database query, so I probably need a plugin for this.

Are my assumptions more or less correct? Where could I find a paid developper for such a plugin?

Thank you very much for your support.

This is actually a pretty simple task.

Create a template that your JS will reach out to returning the total number of entries. First create a template folder called "ajax" with an index.html file inside. Within that file put (replacing blogs with the name of your channel):

{{ craft.entries.section("blogs") | length }}

Inside your javascript, add this:

    var numberOfEntries = false;

    setInterval(function(){

    $.ajax({
      url: '/ajax',
      type: 'GET',
    })
    .success(function(data) {

      updatedNumberOfEntries = Number(data);

      if(updatedNumberOfEntries != numberOfEntries){

        // something was updated -- do whatever you want
        numberOfEntries = updatedNumberOfEntries;

      }
    });

    }, 5000);

You'll obviously need to make some revision to suit whatever you're trying to do but essentially just dump out the number of articles in a template, and use jquery's ajax method to get that value and see if it has changed.


How to write a segment that is not two other segments How can I write:

is segment 3, and is not itemA and is not itemB?
both itemA and itemB are segment 3 as well.

{% if craft.app.request.getSegment(3) and craft.request.getSegment(3) !== 'itemA' and craft.request.getSegment(3) !== 'itemB' %}

To clarify, I want to target a category that is segment 3, but I want to omit two other categories that are on the same segment(level):

Topics Category

Subcategory
Subcategory

itemA(omit)
itemB(omit)
itemC(yes)
itemD(yes)

In code, I want to achieve this:

{% if craft.request.getSegment(2) == 'Subcategory' %}
   // do something
{% elseif craft.app.request.getSegment(3) and craft.request.getSegment(3) !== 'itemA' and craft.request.getSegment(3) !== 'itemB' %}
   // do other stuff
{% else %}
   // do a generic thing
{% endif %}

I personally try to avoid inlining too many conditionals because I feel like it leaves room for logical loopholes. I also think using variables for segments keeps things easier to read.

{% set seg2 = craft.request.getSegment(2) %}
{% set seg3 = craft.request.getSegment(3) %}

So maybe something like this? The keyword in is Twig's way of checking in_array()

{% set badItems = ['itemA', 'itemB'] %}

{% if seg2 == 'Subcategory' %}
    // do top priority thing
{% elseif seg3 != '' and seg3 not in badItems %}
    // do secondary thing
{% else %}
    // do overall default thing
{% endif %}

However, if you know the finite list of acceptable items beforehand, I think this is more concise.  Since segment 3 could be blank if it's not there, maybe try checking if it is something instead of if it's not something.

{% set goodItems = ['itemC', 'itemD'] %}

{% if seg2 == 'Subcategory' %}
    // do top priority thing
{% elseif seg3 in goodItems %}
    // do secondary thing
{% else %}
    // do overall default thing
{% endif %}


404 when opening a localized page I get a 404 page when I try to open an Italian page. Homepage www.domain.com/it/ works, but when I proceed to www.domain.com/it/assistenza-e-supporto it gives me a 404.

English version works. Any idea where I should look to fix this?

I've followed the steps as desribed here:
https://craftcms.com/docs/localization-guide

Config looks like this:

return array(
    'cpTrigger' => 'admin',
    'omitScriptNameInUrls' => true,
    'devMode' => true,
    'siteUrl' => array(
        'en_US' => 'http://local.crafttraining.craft.dev/',
        'es' => 'http://local.crafttraining.craft.dev/es/',
        'it' => 'http://local.crafttraining.craft.dev/it/',
    ),
);

Update:
After a day of trying and searching I found out that once I remove the omitScriptNameInUrls from the general.php it works fine, but I would like to have nice url's.

.htaccess looks like this:

<IfModule mod_rewrite.c>
RewriteEngine On

# Send would-be 404 requests to Craft
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]
RewriteRule (.+) index.php?p=$1 [QSA,L]
</IfModule>

What am I doing wrong. Thanks for helping me out with this.

Found it (at last). The thing was that the . before .htaccess was removed when copying the files to the /it/ folder on OSx


Filtering by lightswitch fields Bit of an unusual one and sure must be missing something but know if we have a defined lightswitch field we want to filter against it can quite easily be done so like this:
{{ craft.products().myField(1) }}

However, if I have several lightswitch fields and a front-end filtering form I don't especially want to explicitly do this against all of them, eg {{ craft.products().myField(1).anotherField(9) }}. Was wondering then if it is possible to build out some kind of dynamic search or filter but unless doing something crazy looks like the Craft search parameter won't filter against lightswitch fields, eg the following won't work:
{{ craft.products().search('myField:1') }}

I think I have found a workaround using the where() parameter but feels a bit … inelegant … as essentially specifying my query now against DB values rather than against Craft elements/properties:
{{ craft.products().where('field_myField=1') }}

Any thoughts on improving? Is there a way to do this in native Craft/twig without having to query against specific database values?
Cheers,
Cole
PS above are examples working with Craft Commerce Products. Not entirely sure if this is an issue limited to products as opposed to - say - entries but as these are both essentially elements had assumed not.

Searching against lightswitch should work. Make sure Use this field’s values as search keywords is checked in Settings → Fields → your field then run ./craft resave/entries --update-search-index to (re)index your values.


Using {% cache globally %} inside {% cache %} I am currently building a website that consist almost entirely of blocks.

There are quite a few pages that use the same blocks, but sometimes with slightly different content and not always in the same order.

I have built a matrix field to construct each page out of these blocks and most of these blocks have their own template.

Basically I do this:

{% for block in matrix %}

  {% if block.type == 'type1' %}
    {% include 'type1.twig' %}

  {% elseif block.type == 'type2' %}
    {% include 'type2.twig' %}

  {% endif %}
{% endfor %}

Some of these blocks however, also have for loops in them accessing matrix fields.

I was wondering if it is possible to use {% cache %} tags around my for loop that loops through all the basic blocks, and then within my block templates another {% cache %} tag but with the globally parameter.

So in short, can I safely use cache tags inside other cache tags?

So in short, can I safely use cache tags inside other cache tags?

You can nest {% cache %} tags and in the majority of cases it's probably safe.

Some additional reading:

What effect does nesting cache tags have?

Prevent craftcms caching CMS page with dynamic template


Moving site to new server - admin area not working I am trying to move a Craft site to a new server but am having difficulties.

I have backed up the whole site and database an replicated it on a new server.

3 pages work fine, one page only loads the header, and the admin page lets me login but the dashboard is blank but there are no console errors in chrome.

I have changed my host files on my mac to point the domain to the new server so I'm not sure if this might cause issues?

Or is there something else I am missing?

I'd start with debugging the control panel. If you enable devMode, and load the dashboard, you might see any error message that display on the screen that would give you a clue what's going on.

If it's not there, then some error message is probably being logged in your craft/storage/runtime/logs files that would help.  Open that files and do a search for [error] and look for any suspicious messages.


Composer Error Updating Craft CMS 3 from RC13 to 14/15 PHP 7.0.28 / MySQL 5.6.38 / Craft Pro 3.0.0-RC13

While trying to update I get this error:

Error: An error occurred

Output: Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable set of packages.

Problem 1
- The requested package codeception/codeception could not be found in any version, there may be a typo in the package name.
Problem 2
- The requested package codeception/mockery-module could not be found in any version, there may be a typo in the package name.
Problem 3
- The requested package codeception/specify could not be found in any version, there may be a typo in the package name.
Problem 4
- The requested package codeception/verify could not be found in any version, there may be a typo in the package name.

Potential causes:
- A typo in the package name
- The package is not available in a stable-enough version according to your minimum-stability setting
see for more details.
- It's a private package and you forgot to add a custom repository to find it

Read for further common problems.
Running update with --no-dev does not mean require-dev is ignored, it just means the packages will not be installed. If dev requirements are blocking the update you have to resolve those problems.

My composer.json file:

{
  "name": "craftcms/cms",
  "description": "Craft CMS",
  "version": "3.0.0-RC13",
  "keywords": [
    "cms",
    "craftcms",
    "yii2"
  ],
  "homepage": "https://craftcms.com",
  "license": "proprietary",
  "support": {
    "email": "support@craftcms.com",
    "issues": "https://github.com/craftcms/cms/issues?state=open",
    "forum": "https://craftcms.stackexchange.com/",
    "source": "https://github.com/craftcms/cms",
    "docs": "https://github.com/craftcms/docs",
    "rss": "https://github.com/craftcms/cms/releases.atom"
  },
  "require": {
    "php": ">=7.0.0",
    "ext-curl": "*",
    "ext-dom": "*",
    "ext-json": "*",
    "ext-mbstring": "*",
    "ext-openssl": "*",
    "ext-pcre": "*",
    "ext-pdo": "*",
    "ext-zip": "*",
    "composer/composer": "~1.5.2",
    "craftcms/oauth2-craftid": "~1.0.0",
    "craftcms/plugin-installer": "~1.5.0",
    "craftcms/server-check": "~1.1.0",
    "creocoder/yii2-nested-sets": "~0.9.0",
    "danielstjules/stringy": "~3.1.0",
    "elvanto/litemoji": "^1.3.1",
    "enshrined/svg-sanitize": "~0.8.2",
    "guzzlehttp/guzzle": "~6.3.0",
    "league/flysystem": "~1.0.35",
    "league/oauth2-client": "~2.2.1",
    "mikehaertl/php-shellcommand": "~1.2.5",
    "pixelandtonic/imagine": "~0.7.1.2",
    "seld/cli-prompt": "~1.0.3",
    "twig/twig": "~2.4.4",
    "yiisoft/yii2": "~2.0.14.2",
    "yiisoft/yii2-debug": "~2.0.10",
    "yiisoft/yii2-swiftmailer": "~2.1.0",
    "yiisoft/yii2-queue": "~2.0.1",
    "zendframework/zend-feed": "~2.8.0",
    "craftcms/cms": "3.0.0-RC15",
    "bugsnag/bugsnag": "v3.9.0",
    "craftcms/redactor": "1.0.1",
    "dolphiq/redirect": "1.0.15",
    "nystudio107/craft-cookies": "1.1.9",
    "superbig/craft3-bugsnag": "2.0.0",
    "superbig/craft3-templateselect": "2.0.0",
    "topshelfcraft/supersort": "3.0.1"
  },
  "require-dev": {
    "codeception/codeception": "~2.3.3",
    "codeception/mockery-module": "~0.2.2",
    "codeception/specify": "~0.4.6",
    "codeception/verify": "~0.3.3"
  },
  "provide": {
    "bower-asset/bootstrap": "3.3.* | 3.2.* | 3.1.*",
    "bower-asset/jquery": "3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable",
    "bower-asset/inputmask": "~3.2.2 | ~3.3.5",
    "bower-asset/punycode": "1.3.*",
    "bower-asset/yii2-pjax": "~2.0.1"
  },
  "suggest": {
    "ext-imagick": "Adds support for more image processing formats and options.",
    "ext-iconv": "Adds support for more character encodings than PHP’s built-in mb_convert_encoding() function, which Craft will take advantage of when converting strings to UTF-8.",
    "ext-intl": "Adds rich internationalization support."
  },
  "autoload": {
    "psr-4": {
      "craft\\": "src/"
    }
  }
}

Fixed this on several installations by changing the PHP and Yii versions to match what the system was running. It seemed to get out of sync now and then so had to keep on top of it at first on all of the Craft 3 installations. Once it's handled it doesn't pose a problem in the future.


Comprehensive logging of user actions with Craft Pro? I am considering a purchase of Craft Pro in place of a new ExpressionEngine build for a client. One of the client's requirements is that there be a comprehensive set of logs like Audit Pro of what each user is doing (logging on, deleting entries, changing settings) and when. Is that data logged in Craft Pro, or is there a plugin that would accomplish that functionality?

I don't know of a plugin that exists expressly for this purpose, but you could combine LumberJack (logging plugin) with Craft's numerous events to make this happen with your own plugin. You can log from within said plugin or even in your Craft templates.

Take a look at the event reference and see if there's enough there to satisfy your client's needs. Creating your plugin should be pretty straightforward.

It may also be worth noting that Craft's logs are available from the control panel at /admin/utils/logs. These are developer-centric errors and warnings though, not a record of specific user actions.


How fixed are the ICC profile in core app? Will ICC profiles here always be a core part of Craft app?
/craft/app/vendor/pixelandtonic/imagine/lib/Imagine/resources/Adobe/CMYK

Not sure I'm following 100%, but they're part of the Imagine library so as long as Craft is using that library, they will be included in Craft.


How to check if on a channel/category index? In the previous question I asked for a way to detect the 404 page from a plugin. Brandon gave me a good starting point with this answer. However, I wondered what method I could use to also detect wether the user is on any category/channel index page?

That would require some sort of convention on your end which identifies what makes up a category/channel index page, as channels and categories don’t actually have an “index URL”.

For example you could decide that all sections’ index pages should have a URI that matches the section’s handle (not necessarily a good idea though, in the event that you want a URI that includes dashes). In that case you could do something like:

{% set segments = craft.request.getSegments() %}
{% if segments|length == 1 %}
    {% set section = craft.sections.getSectionByHandle(segments[0]) %}
    {% if section %}
        We’re on a section index!
    {% endif %}
{% endif %}

There is no corresponding function for getting a category group by its handle at this time, however.

A better approach might be to just leave it up to the templates to define whether they are supposed to be an index template. So in news/index.html, the template that you want to treat as the News index template, for example, you could put this:

{% set isIndex = true %}

Any layout templates that the index template extends will then have access to that isIndex variable.


Sprout Forms - Notification Based on Checkbox Value I'm using Sprout Forms 3.8.0.2 and Craft CMS 3.4.5. My client wants the email notification to go to different email addresses based on whether or not a form checkbox is checked. My plan is to create a new notification for each checkbox value, with the checkbox logic in a custom rule. I've read through the documentation, but I can't figure out how to write the code that checks whether a checkbox is checked. I think it's something like
{ checkBoxFieldHandle == 'value' } or { checkBoxFieldHandle.valueBeingChecked.selected } but neither of those are sending any notifications after a test message. Any advice on how to do this? Thank you!

You're on the right track.

The first thing to note is that the Send Rule field does support shorthand syntax like in your question, however, if you are using compound logic, you will want to use the full object syntax for that logic.

So, instead of (with no reference to object. and single curly braces):

{ checkBoxFieldHandle == 'value' }

You'll want to use the full object syntax to get the expression to evaluate:

{{ object.checkBoxFieldHandle == 'value' }}

The next thing to note is that the checkbox field is a multi-select input, meaning more than one value can be selected. This could be present additional logic challenges for what you are trying to do but assuming you have a checkboxes field with a single checkbox or an opt-in field the logic is more predictable.

Checkboxes are submitted as arrays, so you'll need to make sure you are targeting the correct node in the array. In the case of a single checkbox, we know the first checkbox will be index 0 in the array. Once we have the target checkbox, we can see if it's selected by checking the selected attribute:

{{ object.checkboxFieldHandle.getOptions()[0].selected == true }}

And we can update the same statement to check for false if we want to only send if the checkbox is unchecked:

{{ object.checkboxFieldHandle.getOptions()[0].selected == false }}


Get categories for current page/entry For templating, I need to be able to see what the categories of the current entry is. I'm aware of how to get all categories in craft via

{% set categories = craft.categories %}

however I haven't come across a way to simple get the categories that are set for the entry. Is there a simple way of doing this?

You can access the categories through the category field itself.

{% for category in entry.categoryFieldHandle %}
    {{ category.title }}
{% endfor %}


Only show items related to the lowest category level I have a category group (CG).
I have a channel of entries with a matrix field (MF).
Every block in that matrix field has a category field linked to the CG.

I want to list all the MF blocks in an ordered list grouped by their category.
So for example:

Category A

MF block 1
MF block 2
Category AB

MF block 3

I'm looping over all categories within CG (with a recursive macro) and for each category I show a MF block that has that category related.
The problem is that when a block is related to Category AB, it is also related to its parent Category A, so the block is shown in Category A as well as in Category AB.

I want it to be only shown in the lowest level category, being AB in this case.

It gets even trickier because I cannot limit the amount of categories selected to just 1, because than Craft automatically selects only the top parent. So now (even if I don't need it) I have to take care of the possibility that the matrix block has multiple categories selected (and their children).

I was thinking about grouping the matrix blocks by their category with the groupBy filter plugin but I haven't found the time yet to try this out. And I'm afraid I might loose the hierarchy of the CG.

I could use a section for the categories (where you can limit it to a single item and it'll select the correct child) but than the client has a hard time to see what the parent category is in the CP. So that's a downer.

Why I need this:

The client needs to be able to upload a ton of files related to an entry or add links related to an entry. That's why I created a matrix with 3 block types: external link, internal link and file.
The file block has a table field where they can upload an asset and select a locale. Because all files can have multiple translations. But the locales these files can be translated in do not match the locales that the site is available in. So that's why I can't just use a translatable asset field. That also why I can't use a front-end asset browser (because of the links and the translated files and because I have no control over the created folder structure).

I could live without them being able to add links if that would make it simpler. Alternative solutions are more than welcome!

This is a truly tricky one. Let's restate the problem:

  For each category in a tree list of categories: We want to display content from an element if the element is related to the category but not related to any of the category's children.

Off the top of my head, I can't think of a really performant way to do this... So, hopefully there aren't too many categories in your setup, and caching is key.

First we need to generate a recursive structure of categories:

{% set categories = craft.categories.group(...) %}

{% nav category in categories %}

    {% include '_elementsForThisCategory' with {category: category} only %}

    {% ifchildren %}
        {% children %}
    {% endifchildren %}

{% endnav %}

(You could easily use a macro in place of that include. These days I prefer includes over macros for anything other than the very simplest use cases.)

Next (in the included template/macro), we need to create a list of elements that are related to the present category but not related to any of its children:

{# Query entries that are related to this category's children. #}

{% set relatedToChildCats = craft.entries.relatedTo({
    targetElement: category.getChildren()
    field: 'yourMatrixField.yourCategoriesField'
}) %}

{# Query entries that are related to this category,
   and exclude the entries that are related to this category's children. #}

{% set theBuckStopsHere = craft.entries.relatedTo({
    targetElement: category
    field: 'yourMatrixField.yourCategoriesField'
}).id('not', relatedToChildCats.ids) %}

{# Display the content however you want. #}

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

→ You probably noticed that my example uses Entry elements, and your stated use case deals with MatrixBlock elements. I wanted to give the example using purely out-of-the-box-friendly code, and unfortunately Craft 2 doesn't provide a template method for querying Matrix blocks... But luckily, our good friend Low wrote a nice plugin (Low Blocks), which adds a handy craft.lowBlocks template variable.


How do I print the options in a dropdown field? I have a dropdown field with X options.  I want to print each option as a button.

I tried...

    {% for option in entry.isotope.options %}

{{ option }}

    {% endfor %}

isotope = dropdownFieldHandle

But I get the error Variable "entry" does not work'.

There's not an "elegant" way to do this but you can access the dropdown field by its handle using getFieldByHandle. Something like:

{% set dropdownField = craft.fields.getFieldbyHandle('isotope') %}

  {% for option in dropdownField.settings.options %}

{{ option.value }}

  {% endfor %}

If you need the label instead, just use {{ option.label }}

You can also grab a dropdown's options from any entry you know has the field already attached, such as the first entry from your news section for example:

{% set entry = craft.entries.section('news').limit(1)[0] %}

{% for option in  entry.isotope.options %}

{{ option.value }}

{% endfor %}

Note: similar to this question.


Craft with the PHP Built-in server? With PHP 5.4+ we get a built-in webserver, http://php.net/manual/en/features.commandline.webserver.php

Has anyone had luck setting this up with Craft? It seems like it could be pretty straightforward, but I am not sure how to wire up a mysql database.

In particular I am hoping to run this with Gulp/BrowserSync so that I can just fire up a livereload instance of Craft quick and easily.

On a very basic pass-through I just did, it seems to kind of work - except it just has 404 pages and a "Craft can’t connect to the database" error.

Here is my gulpfile.js for reference:

gulp.task('php', function() {
    php.server({ base: 'public', port: 8010, keepalive: true});
});

gulp.task('serve', ['php'], function() {
    browserSync.init({
        notify: false,
        reloadOnRestart: true,
        open: false,
        proxy: '127.0.0.1:8010'
    });
    gulp.watch('*.js').on('change', reload);
    gulp.watch("*.html").on('change', reload);
    gulp.watch("*.php").on('change', reload);
});

gulp.task('default', ['serve']);

Edit: I connected to mysql without much problem (installed using Homebrew, and connecting with 127.0.0.1), but now I am getting:

  Your server doesn’t meet the following requirements to run Craft:

  Mcrypt is required.

Brad Bell mentions this about Craft:

  Being a self-hosted PHP web application is a hard life. Your parents try to raise you correctly and equip you with the tools necessary to successfully go out into the world and live on some stranger's unknown, unfriendly and oftentimes hostile server environment so you can serve up web pages, but things are stacked against you.

It's a great read.

I hate to be that guy, but any reason why you don't want to run something more common like MAMP? I haven't used PHP's built in server but there might be little things here and there that you'll pull your hair out over as to why your installation is functioning weirdly and it ends up being a little "quirk" with the PHP web server performing oddly with Yii or something else.

Unless you're just fooling around, it's ideal to run the same software locally as you do on a "live" web server. Some people go so far as to clone the environment they're in (like Vagrant or some other virtual machine), but MAMP works well.

I've used Home Brew and I've even compiled PHP/MySQL/Apache manually on a Mac. It's a great exercise in dependency management, using the command line, and seeing what other packages all go into PHP—there's a ton!—but that's really where it ends. The web server stack is just a tool and MAMP gives me all of that in a simple download that you can easily move/remove. If you have more than one computer, you're going to have to repeat those home brew commands on every Mac you want to test on; MAMP is 3 clicks and I have the stack.


Craft CP showing plugin updates, but already updated This morning there were new updates for Craft CMS, Contact Form and Simplemap on a Craft Pro site I host. I updated everything through the Craft CP. After the update, the CP still shows available plugin updates. When I check composer.json everything is already updated.

I tried running ./craft update all through SSH, deleted caches, checked the OPcache settings with my hosting provider and checked the logs. Can’t find any reason why the CP shows plugin updates while everything is already updated.

I also contacted Craft support, and they suggested putting the question here. I hope anyone does have an idea what’s going on.

The server environment:

PHP 7.0.33
MySQL 5.5.5
Craft Pro 3.1.21.1
Yii 2.0.17

My composer file:

{
  "name": "craftcms/craft",
  "description": "Craft CMS",
  "keywords": [
    "craft",
    "cms",
    "craftcms",
    "project"
  ],
  "license": "MIT",
  "homepage": "https://craftcms.com/",
  "type": "project",
  "support": {
    "email": "support@craftcms.com",
    "issues": "https://github.com/craftcms/cms/issues",
    "forum": "https://craftcms.stackexchange.com/",
    "source": "https://github.com/craftcms/cms",
    "docs": "https://craftcms.com/docs",
    "rss": "https://craftcms.com/changelog.rss"
  },
  "require": {
    "craftcms/cms": "3.1.21.1",
    "vlucas/phpdotenv": "^2.4.0",
    "craftcms/redactor": "2.3.2",
    "rias/craft-position-fieldtype": "1.0.14",
    "craftcms/contact-form": "2.2.4",
    "ether/seo": "3.5.4",
    "ether/simplemap": "3.4.10",
    "nystudio107/craft-typogrify": "1.1.17",
    "matt-west/craft-recaptcha": "1.3.0"
  },
  "autoload": {
    "psr-4": {
      "modules\\": "modules/"
    }
  },
  "config": {
    "optimize-autoloader": true,
    "platform": {
      "php": "7.0"
    }
  },
  "scripts": {
    "post-root-package-install": [
      "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
    ],
    "post-create-project-cmd": [
      "@composer dump-autoload -o",
      "@php craft setup/welcome"
    ]
  }
}

There was something wrong inside the vendor folder. Couldn't find what. What I did to solve it (thanks to Craft support):

Rename vendor folder to vendor-old
Ran composer clearcache to delete all content from Composer's cache directories
Ran composer install to install all depencies in composer.json
Deleted vendor-old folder


How to round the decimal value which we store in the admin panel? Is it possible to round the decimal value we store in the admin panel . Can anyone Explain me with an example

Twig offers various filters. So to round the decimal value, we can use a round filter.
The round filter rounds a number to a given precision:
{{ 42.55|round }}
{# outputs 43 #}

{{ 42.55|round(1, 'floor') }}
{# outputs 42.5 #}

The round filter takes two optional arguments; the first one specifies the precision (default is 0) and the second the rounding method (default is common)

common rounds either up or down (rounds the value up to precision
decimal places away from zero, when it is half way there – making 1.5
into 2 and -1.5 into -2).
ceil always rounds up.
floor always rounds down.

For more filter in Craft CMS. You can check below link.
https://craftcms.com/docs/3.x/dev/filters.html


Uploading PDFs with Imagick extension enabled seems to rasterize and compress the PDFs Uploading PDFs to Craft3 with Imagick extension enabled seems to rasterize and compress the PDFs.

Also, if I manually swap out the files after upload, it works fine until I have to edit something in an article with a pdf uploaded. Then the behavior is repeated when I press save.

Any idea on where to disable this behavior?

Got the same problem with Craft3 (3.0.0-beta.19). Had to change the imageDriver to GD.

Add 'imageDriver' => 'gd', to config/general.php and replace/reupload the files in Craft.


Feed Me in Templates - can't pull in I'm using Feedme to display content in my temmplates from a podcast RSS feed - not importing entries, just displaying.

Everything is working fine except that I can't display the <itunes:summary> node.

When I use this code

{# podcaast #}
{% set params = {
    url: 'https://website101podcast.com/feed.rss',
    type: 'rss',
    element: 'item',
    cache: 60,
} %}

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

{% for node in feed|reverse %}
  {% if loop.index <= 1 %}

{{ node.title }}

{{ itunes:summary }}

    Listen Now
  {% endif %}
{% endfor %}

I get the following template errors:

  Unexpected token "punctuation" of value ":" ("end of print statement" expected).

Is it possible to call in the itunes field?

You'll not be able to use the dot notation here, and instead use the array notation.

Try: {{ node['itunes:summary'] }}


'png_compression_level should be an integer from 0 to 9' upon uploading image First time we see this: client tried to upload a specific PNG file (that a first sight looks ok) and Craft CMS returned the error 'png_compression_level should be an integer from 0 to 9'

This turned out to be a bug and the fix will be in the next release (current version is 3.5.15.1).


Set logging path/file to use php://stderr I'm rethinking our Craft environment/workflow.  My idea is to accommodate disposable and/or multiple container (or server) environments.  As a result I want to use log aggregation apps like papertrail, logstash, etc to consolidate and investigate logging across multiple servers.  They recommend logging to php://stderr.  Is this possible?  What approach would you take to override the apps log route?

Pretty sure you'd need to write a plugin that has a class that extends Yii's CLogRoute and override the processLogs method with your own logic.  Something like this:

class StdErrRoute extends \CLogRoute
{
    public function processLogs($logs)
    {
        $strErr = fopen("php://stderr", "w");

        foreach($logs as $log)
        {
            fwrite($strErr, $log[0]);
        }

        fclose($strErr);
    }

}

Your plugin's init() method would register the route via craft()->log->addRoute().


Entries save but site doesn't update Hey there and thanks in advance. We just moved our site to production as a beta site. The only thing that is different between this site and our local/staging site is the config file. The allowUpdates and allowAdminChanges is set to false. Databases are separate and all sites are running.

We I update entries on prod, they save but my site does not update. When I do the same change on local/dev the changes render on my dev site.

Am I missing something? Does allowUpdates and allowAdminChanges affect whether or not content will be updated on the site? Thought it might be a cache issue but why would it work on dev and not prod?

Any thoughts on this would be greatly appreciated.

Thank you,

Does allowUpdates and allowAdminChanges affect whether or not content will be updated on the site?

Nope.

  Thought it might be a cache issue but why would it work on dev and not prod?

Caching is my first thought. Is production behind a CDN, Varnish or some other caching solution that dev is not?

Maybe the enableTemplateCaching config setting is set to false for non-production environments?


Form Plugin for Craft CMS I'm looking for a plugin like ContactForm from P&T but with more options like validation for custom fields or the possibility to build a own mail template for the mail at his self.

I want to handle all with the same plugin if this is possible.

You can find most plugins for Craft here: https://straightupcraft.com/craft-plugins

There's a few different form plugins to choose from, not sure if all of them will have what you're looking for.

I've used Sprout Forms a few times and you should be able to do both of what you're asking for.


PHP error upon installation I keep getting this error when I go to install Craft: "Declaration of Craft\UrlManager::parseUrl() should be compatible with that of CUrlManager::parseUrl()"

I am installing on a subdomain.  The database credentials are in place, the permissions are correct and the craft folder is found.

I have devmode enabled and the last stack trace item is pointing to "craft/app/etc/web/UrlManager.php(18)".

That's a bug in Craft that occurs with the specific configuration of PHP you're running.  Just fixed it for the next release, though.

In the meantime, you can open up craft/app/etc/web/UrlManager.php, find the parseUrl method and change it from:

public function parseUrl(HttpRequestService $request)

to:

public function parseUrl($request)


User activation success path not working (Craft v2.3.2621) I'm at a loss. I've set up a font-end user activation workflow that looks like this:

User registers via a front end form based on Craft's example form
User is redirected to a page informing them that they'll be receiving an email with an activation link
User clicks the activation link and lands on a welcome page

Right now my user registration form is working. When a user registers, I can see them added to the CP user list with their email address, firstName and lastName (which I'm also collecting from the registration form). The redirect to the "you'll be receiving an email..." page is working as well.

But when I click the activation link to test, I end up on the homepage of my site, not on the uri I've specified in my config settings which look like this:

return array(
    '*' => array(
        'omitScriptNameInUrls' => true,
        'defaultImageQuality' => '65',
        'useEmailAsUsername' => true,
        'loginPath' => 'member/login',
        'logoutPath' => 'member/logout',
        'postLoginRedirect' => 'member/my-account',
        'autoLoginAfterAccountActivation' => true,
        'activateAccountFailurePath' => 'member/activation-failed',
        'activateAccountSuccessPath' => 'member/activation-success',
    ),
other settings below...

I'm making sure that when I test sign-ups, I'm logged out in a different browser. I've also tried the sequence without autoLoginAfterAccountActivation set to true but in that case, I just end up logged out on the homepage of my site rather than on the activation-success page.

The activation works, which I can verify in the CP, but I can't figure out why the site isn't respecting my config setting for activateAccountSuccessPath.

Anyone have any ideas?

The issue was solved by updating Craft to the latest version (2.3.2625), which brought back support for the activateAccountSuccessPath config setting. Thanks to Brandon Kelly for the heads up.


Is there a way to make Disqus notify an entry author when a new comment is posted? I'm setting up a multiple authors blog and one of the requirements provided is that authors be notified when someone posts a new comment. We're planning to use Disqus for comments, and that will notify the moderators in Disqus by default, but it's not really an option for us to add all authors in craft as moderators in Disques. Maybe this is just a limitation with Disqus.

In googling for an answer it seems that someone found a way to do this in Wordpress with a plugin. (http://wpdailybits.com/blog/notify-post-author-for-new-comment-disqus/45) Would it be possible to do something similar in Craft perhaps?

Disqus has a callback function that you can use to fire an email off to the author. Within that callback, you could make an AJAX request to another template which sends an email.


Redirect entry type to another domain I have an entry type (outsideCourse) that will never need its own page. It only exists so I can manipulate it in various lists of required courses. Thanks to Mats Mikkel Rummelhoff, I have a macro to plug its field attributes into a search URL for another website.

Another entry type in the same section, safsCourse, DOES have its own template URL scheme.

I don't want to have a mostly blank page show up if someone happens to go to the entry page for one of the outsideCourse entries (example: localhost/craftcms/courses/ecological-economics).

The options I can think of:

Somehow eliminate slugs or URLs for the outsideCourse entry type, so their URLs go to the 404 page
.htaccess redirects
A separate template just for this entry type that redirects either to my preferred destination (the http://msu.edu link generated by my macro) or the index page for this section (localhost/craftcms/courses).
One template for both entry types, with a conditional redirect.

I've been working on Option 4. I've tried adding the following to the very beginning of my courses/_entry.html template, before {% extends '_layout' %}:

{% if craft.entries.section('courses').type('outsideCourse') %}
     {% import 'partials/_helpers' as helpers %}
        {% redirect helpers.msuLink(entry) %}
 {% else %}

It tries to go to http://localhost/craftcms/%20%20%20%20https://reg.msu.edu/Courses/Request.aspx?SubjectCode=EEP&amp;CourseNumber=260#Results and gives me a 403 Forbidden error.

If I replace helpers.msuLink(entry) with "http://msu.edu", it redirects but ignores the conditional.

So here's what I'm wondering:

Why isn't the conditional working?
How can I add an absolute link to a redirect without just writing a string?
Should I be going about this in a different way altogether?

The reason that you get that odd URL with the {% redirect %} tag is just because there's some whitespace at the beginning of the value returned from your helpers.msuLink() macro. Using the |trim filter (which removes whitespace from both ends of a string) fixes that:

{% redirect helpers.msuLink(entry)|trim %}

If you prefer, you could also modify your macro so it returns the value without whitespace, by using the {% spaceless %} tag – then you don't need the |trim filter:

{% macro msuLink(entry) %}
{% spaceless %}
    {{ 'https://reg.msu.edu/Courses/Request.aspx?SubjectCode=' ~ entry.deptCode ~ '&CourseNumber=' ~ entry.courseNumber ~ '#Results' }}
{% endspaceless %}
{% endmacro %}

As for the conditional, I don't believe you want the craft.entries query there – just put the following at the top of your courses/_entry.html template (note that I'm also putting the {% import %} statement outside the conditional – it doesn't really matter but its cleaner and shouldn't impact performance):

{% import 'partials/_helpers' as helpers %}

{% if entry.type == 'outsideCourse' %}
    {% redirect helpers.msuLink(entry)|trim %}
{% endif %}

{# Rest of template below #}
...

If you decide that having the outsideCourse URLs 404 instead of redirect makes the most sense (I believe it would, and is cleaner, in most cases), the easiest way to achieve that is to put this at the top of your entry template:

{% if entry.type == 'outsideCourse' %}
    {% exit 404 %}
{% endif %}

{# Rest of the template below #}
...


Filter Entries by Field Value How do I filter a list of entries by the value of a field? For example, if I have a lightswitch field called "Featured", how do I output just the featured entries?

Filtering a list of entries is quite simple. Here's an example from one of our sites:

{% for job in craft.entries({
    section: 'jobs',
    applicationsClose: ">= " ~ (now|date('Y-m-d')),
    internalExternal: 'external',
}) %}

    ...

{% endfor %}

Here we define the section we're looking in and then filter by two custom fields: applicationsClose and internalExternal.


Craft 3 plugin backwards compatibility and maintenance for 2.x I've been updating a number of my plugins for Craft 3 lately; part of that process has been to create entirely separate repositories/projects to accommodate the differences between Craft 2.x & 3.

I'm curious to know how other developers maintain two plugins where the core functionality is essentially the same code.

Maybe having both plugins refer to the same dependancies via composer? (But still have two repos/projects)

Perhaps keep everything on one repo/project and simply have two versions of the plugin in there. Although that may conflict with Craft 3's plugin store; as half the files int he repo are redundant.

I'd love to know how others are dealing with their plugin upgrades and if there are any 'official' practices to resolve this.

This seems to be the common pattern emerging amongst developers in the same position...

A single repo:

craft-(pluginname)

Containing multiple branches:

v1 (your old Craft 2 version)
v2 (your new Craft 3 version)

There are a handful of variations to this, but that's it in a nutshell.

Examples:

https://github.com/craftcms/contact-form *
https://github.com/barrelstrength/craft-sprout-notes
https://github.com/doublesecretagency/craft-cpcss
https://github.com/marionnewlevant/craft-snitch
https://github.com/carlcs/craft-deleteentryversions

* P&T has mentioned that they didn't prefix their own repos with craft-, since the repo is owned by craftcms. But they said they would have, if they were a 3rd party developer.

Some people have prefixed their repos with craft3-, but that has been discouraged by the folks at P&T. It would force you to abandon this repo (or leave the name confusing) when Craft 4 is eventually released.


Retrieving all users with specified permission With a $user object, we can verify the user against a permission setting with the can() method. However, how can I retrieve all users who have a specific permission, including those under a group with the permission.

This needs to be generic PHP code as it's located in a service.

I don't think there is a clean or particularly efficient way of doing this using Craft's current services.

It'd have to be something like:

1. Grab all users
2. Loop through them calling craft()->userPermissions->doesUserHavePermission()
3. If true, save user in success array.

Alternatively you could use DbCommand to query the database directly for the info you're looking for.


Is it typical that data is fetched from within templates rather than in controllers? I'm assessing Craft's suitability for my next project, coming from using HMVC in CodeIgniter with a custom CMS.

In CI all requests go via a controller action which is responsible for inspecting request parameters, loading and filtering data and passing that data to a view. Pretty typical MVC.

From what I've seen so far of Craft and plugins developed for it, the requests are typically forwarded directly to Twig templates and those templates are responsible for analysing query strings and request data and fetching data from exposed template variables or built in "entries".

I'm thinking of a use case where data would need to be displayed and filtered by query string and session criteria and it strikes me that the template would be handling too much of this logic and become bloated.

Most of the website I will be developing will get its data in JSON format from a REST API and passing filter criteria from user interaction with forms and UI controls will come up a lot.

My question is, is this a typical and recommended approach to using Craft, or should I be using controllers to handle tasks such as filtering and fetching data and passing it to a view?

Are there any plugins that I could look at for reference that could help me to understand the flow and process?

Thanks

Jamie

From what I've seen so far of Craft and plugins developed for it, the requests are typically forwarded directly to Twig templates and those templates are responsible for analysing query strings and request data and fetching data from exposed template variables or built in "entries".

Not necessarily required.  You can register a custom CP route in your plugin and have a request routed directly to your plugin's controller action.

public function registerCpRoutes()
{
    return array(
        'path' => array('action' => 'pluginHandle/controllerAction')
    );
}

And have that controller render a the template directly, passing in whatever variables it needs:

$this->renderTemplate('pluginHandle/template', array('foo' => 'bar');


Need help troubleshooting DB connection I'm moving a craft install from a development to production server and am getting this error:

ERROR ERROR
Craft can’t connect to the database with the credentials in craft/config/db.php.

I've triple checked the db credentials and permissions and everything is correct. Here's my db.php file:

<?php

// uncommenting this gives me a 'connected okay' so I know that the credentials are correct.
// if ($con=mysqli_connect("localhost","thandtho_db","*********","thandtho_production")) // {
//  die('connected okay');
// } else {
//  die('couldn\'t connect');
// }

/**
 * Database Configuration
 *
 * All of your system's database configuration settings go in here.
 * You can see a list of the default settings in craft/app/etc/config/defaults/db.php
 */

// Import your local config settings
require( 'config.local.php' );

return array(
    '*'=> array(
        // Database Info
        'tablePrefix' => 'craft',
    // Production Domain
    '9thandthomas.com' => array(
        'server' => 'localhost',
        'user' => 'thandtho_db',
        'password' => '***********',
        'database' => 'thandtho_production'
    ),
    ),
    // Dev
    '9thandthomas.transomco.com' => array(
        'server' => 'localhost',
        'user' => 'ninththomas_dev',
        'password' => '4iJoi58@',
        'database' => 'ninththomas_dev'
    ),
    // Local
    // Needs to be placed after production since subdomain
    // is similar to production domain name.
    $localConfig['envUrl'] =>  array (
        'server' => $localDatabase['server'],
        'user' => $localDatabase['user'],
        'password' => $localDatabase['password'],
        'database' => $localDatabase['database'],
    )
);

************************** ANSWER **************************

I moved the database details from beneath the * and it worked.

db.php now looks like this:

<?php
/**
 * Database Configuration
 *
 * All of your system's database configuration settings go in here.
 * You can see a list of the default settings in craft/app/etc/config/defaults/db.php
 */

// Import your local config settings
require( 'config.local.php' );

return array(
    '*'=> array(
        // Database Info
        'tablePrefix' => 'craft',
    ),
    // Production Domain
    '9thandthomas.com' => array(
        'server' => 'localhost',
        'user' => 'thandtho_db',
        'password' => 'wR39fy2!k',
        'database' => 'thandtho_production'
    ),
    // Dev
    '9thandthomas.transomco.com' => array(
        'server' => 'localhost',
        'user' => 'ninththomas_dev',
        'password' => '4iJoi58@',
        'database' => 'ninththomas_dev'
    ),
    // Local
    // Needs to be placed after production since subdomain
    // is similar to production domain name.
    $localConfig['envUrl'] =>  array (
        'server' => $localDatabase['server'],
        'user' => $localDatabase['user'],
        'password' => $localDatabase['password'],
        'database' => $localDatabase['database'],
    )
);

I had a similar issue where my '*' was being chosen all of the time, meaning all my environments used the same DB details.

Possibly try splitting it up, and not have a '*' for your DB details, for any environment?


Craft Commerce 2 Ajax Add to Cart Trying to ajax add to cart but each submit returns a

https://www.website.com/commerce/cart/updateCart 404 (Not Found)

I have this in my twig template:

{% for book in craft.products().type('books').limit(8).all() %}

    {% for image in book.productImages.limit(1).all() %}

            {% set variant = book.defaultVariant %}
            <form method="POST" class="add-to-cart">
                {{ csrfInput() }}
                <input type="hidden" name="purchasableId" value="{{ variant.id }}">
                <input type="number" name="qty" value="1">
                <button type="submit"></button>
            </form>

    {% endfor %}

{{ book.title }}

    {{ book.defaultVariant.price|currency }}

{% endfor %}

And this as my javascript:

$('.add-to-cart').on('submit', function(e) {
    console.log('add to cart clicked');
    e.preventDefault();
    var form_data = $(this).serializeArray();
    console.log(form_data);
    $.ajax({
        type: 'post',
        url: 'commerce/cart/updateCart',
        data: form_data,
        success: function(response) {
            if (response.success) {
                console.log('success');
                console.log(response.success);
                $(this).hide();
                $(this).siblings('.success').show();
                $(this).parents('.hover-cart').fadeOut();
            }
            else {
                console.log('error');
                console.log(response.success);
                alert("We're sorry, but the item couldn't be added to your cart. Please try again. If the issue persists, please send an email to webmaster@lwf.org");
            }
        }
    });
});

Controllers in Craft 3/Commerce 2 use kebab-case (update-cart) instead of camelCase (updateCate), so adjusting that may correct your issue.

The common convention for forms processed by Craft controllers is to leave the action attribute blank and include a hidden input with the action URL value.

In your example, you can do that by adding an action param to your form_data variable

var form_data = $(this).serializeArray();
// Add the action URL to the submitted data
form_data['action'] = 'commerce/cart/update-cart'

Then you'd leave the url param on your Ajax request blank. The updated code would look something like this if you add the action in your script.

$('.add-to-cart').on('submit', function(e) {
    console.log('add to cart clicked');
    e.preventDefault();
    var form_data = $(this).serializeArray();
    // Add the action URL to the submitted data
    form_data['action'] = 'commerce/cart/update-cart'
    console.log(form_data);
    $.ajax({
        type: 'post',
        url: '',
        data: form_data,
        dataType: 'json',
        success: function(response) {
            if (response.success) {
                console.log('success');
                console.log(response.success);
                $(this).hide();
                $(this).siblings('.success').show();
                $(this).parents('.hover-cart').fadeOut();
            }
            else {
                console.log('error');
                console.log(response.success);
                alert("We're sorry, but the item couldn't be added to your cart. Please try again. If the issue persists, please send an email to webmaster@lwf.org");
            }
        }
    });
});

or the snippet below if you want to add the action to your Twig template

<form method="POST" class="add-to-cart">
    {{ csrfInput() }}
    {# Include the controller used to process the form  #}
    <input type="hidden" name="action" value="commerce/cart/update-cart">
    <input type="hidden" name="purchasableId" value="{{ variant.id }}">
    <input type="number" name="qty" value="1">
    <button type="submit"><i class="fas fa-shopping-cart"></i></button>
</form>

If you use the Twig code above, make sure you update the url property of your Ajax request to remove the existing URL.