onBeforeDeleteCategory not working / inconsistent I need to run checks before allowing a user to delete a category. I have added the following code to my main plugin class:

craft()->on('categories.onBeforeDeleteCategory', function(Event $event) {
    $event->performAction = false;
});

This is just to test it. I expect this to cause any category delete functions to fail because I'm explicitly setting the event perform action property to false.

There are two problems:

No. 1 - This code only runs when I click into the category and then press the delete button. If you do it from the action menu in the category list this event is not even fired. This seems like a bug to me.

No. 2 - This code, even when executed, does not prevent the category from being deleted. Even though I set $event->performAction = false it still just deletes the category.

Any ideas?

EDIT:

I did some sleuthing regarding #1 and I found out that I have to call the event like this:

craft()->on('elements.onBeforeDeleteElements', function(Event $event) {
    $event->performAction = false;
});

However I'm still running into #2 on both instances where setting performAction to false does not prevent the action from completing... :(

Edit 2
It looks like there is no condition for performAction after the event is fired so there appears to be no way to stop a delete event via an event. Is this the case?

Neither onBeforeDeleteCategory nor onBeforeDeleteElements has a $performAction parameter that you can set to cancel the event, which would behavior #2 you're seeing.

The first behavior you're seeing can be explained by this, which you've already found the workaround for.  FWIW, that's changed for the upcoming Craft which, which behaves more as you'd expect now.


How to define template routes for a custom element type So I'm working on a prototyping plugin that has its own element type for pages.  My hope was to have a single _page.html template and much like entries or categories be able to tell Craft to map the routes for all the elements URIs to that template?

But not having much luck figuring out how to do that?

I have URIs saving with my elements but how do I note which template to load?

I assume it has something to do with registering routes but I'm not exactly sure where to start?

You'll need to override the BaseElementType's routeRequestForMatchedElement method in your element type class as follows:

public function routeRequestForMatchedElement(BaseElementModel $element)
{
    return array(
        'action' => 'templates/render',
        'params' => array(
            'template' => '_page',
            'variables' => array(
                'page' => $element
            )
        )
    );
}


Possible to merge and sum the values of an array? I have a super table that has 4 columns. I'm trying to create an array based off one column (contentType) and merges to get only the unique values while taking the sum of a different column (points). Here is a screen shot:

Based off that screenshot I would have the following results:

Motivation-To-Achieve : 2
Emotional-Stability : 2
Openness : 4

I'm able to get the unique content types, however, I can't figure out how to take the sum of the points column. This is what I have so far:

{% set results = {} %}

{% for row in entry.surveyData %}
    {% set type = row.contentType %}
    {% set pts = row.points %}
    {% set results = results|merge({ (type) : {'name': type, 'points': pts } }) %}
{% endfor %}

What you need to do is to add the row.points to any existing points for each type, before merging – otherwise you'll just overwrite the existing type/attribute and its values (in other words, the |merge filter won't automatically merge number values inside an object).

Something like this should work – note the use of the |default filter, to fall back to 0 if the results[type] key doesn't exist:

{% set results = {} %}

{% for row in entry.surveyData %}
    {% set type = row.contentType %}
    {% set pts = row.points + results[type].points|default(0) %}
    {% set results = results|merge({ (type) : {'name': type, 'points': pts } }) %}
{% endfor %}


Removing "action" from a module's route. Is it possible? I have a module with a route that looks like this:

http://localhost/actions/module/controller/action

Is it possible to set up a custom route within my module so I can send people to:

http://localhost/module/controller/action

I'm new to Craft 3, but so far loving it.

Cheers!

Yep, you can add the route in config/routes.php.

return [
    'custom/route' => 'module/controller/action',
];

(See https://docs.craftcms.com/v3/routing.html#advanced-routing-with-url-rules)


How to remove empty tags in rich text? (Redactor or Twig) What is the preferred method to remove an empty tag from the content of a rich text element?

Example result:

  Lorem ipsum

When editing text in the WYSIWYG editor (Redactor) the result can contain empty anchor tags. This is a problem when navigating the page with the tab key, for instance, because the user can not see the focus anymore.

How can I automatically remove those artefacts?

I ended up using this solution:

Filter empty tags in Craft/Twig template

{{ entry.houseDescription|replace('/<[^\\/>][^>]*><\\/[^>]+>/', '')|raw }}

The replace filter /<[^\\/>][^>]*><\\/[^>]+>/ searches for empty tags and removes them.
The raw filter stops Twig from escaping HTML tags.

Regular expression test (RegExr)


How do you handle routes in CP with Query Parameters? I am currently setting up routes for a one-page application. As soon as a Query Parameter is introduced, the route fails. The route "test" replaces "my-av1" in the following photos.

The documentation in Craft does not describe how Query Parameters are handled. How do I proceed from here?

Routes can't include query strings. A route is a path to a template file (or a controller action, if you've written a custom plugin).

You can retrieve a query string value from within a template using the craft.request.getParam method.

For example:

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

Update

Following the conversation in the comments, here is an example of this working with a standard Craft route.

My example route /querystring/test points to the template _views/querystring-test.twig, which contains the following example code.

Query String Test

{% if craft.request.getParam('example') %}

The query string value for example is "{{ craft.request.getParam('example') }}",

{% else %}

There is no query string parameter.

{% endif %}

Here is a screenshot of the page without a query string:

And here is a screenshot of the page with a query string:


Are there any Craft specific migration tools that extend Yii's built-in functionality? We're working on developing a proper deployment system for projects built on Craft, and wondering if there are any Craft specific tools built-in that can assist with generating database migrations, other than those included with Yii itself?

I have more questions, but we'll start here.

Craft has it's own version of Yii's console app, yiic, in craft/app/etc/console/yiic.php and we have a migrate command that lets you create, view history, see new migrations, etc. for plugins as well as Craft itself.

We've extended the default migrate command to add Craft-specific features and remove some default Yii functionality that we don't want to support (i.e. down migrations).

You can see the available commands to run here: http://buildwithcraft.com/docs/plugins/migrations


Different behavior when looping through a list of variables I apologize for the seemingly vague title, but I honestly don't know the best way to state this problem succinctly!

This is within the context of a particular section's entry template.

What I want to happen:

I want to loop through a list of variables that call different Entry elementCriteriaModels and for each iteration of this loop I want to get the section's handle.

How I tried to make it happen:

Get related entries from a number of different sections

{% set towns = craft.entries.section('towns').relatedTo(county) %}
{% set citizens = craft.entries.section('inductees').relatedTo(county) %}
{% set events = craft.entries.section('events').relatedTo(county) %}

Make a list of those elementCriteriaModel objects

{% set arrayOfSections = [
    towns,
    citizens,
    events
] %}

Loop through that list and try to get the section handle of whatever the first entry is of each section

{% for section in arrayOfSections %}
    {% set sectionHandle = section.first().getSection() %}
    {{ sectionHandle }}

What actually happens

I get the following error: "Impossible to invoke a method ("getSection") on a null variable."

When I try to do the same thing on an object that is outside of that arrayOfSections list, it works just fine!

Why am I even trying to do this??

There is a huge part of this template that repeats itself over and over. If I can successfully loop through these related sections in this way that problem will be fixed. I've thought about turning this into a macro, but I'd still have to call this macro nearly half a dozen times and manually feed in the desired section each time...

Make sure your section.first() returns an element. The error occurs because section.first() is null => no element was found with your criteria. And the value null has no function getSection.

However - keep in mind your sectionHandle variable is not the handle of the section, but the SectionModelthus your code as it is currently is not really performant


Internal server error in Admin after migration I'm setting up a website using Craft Cms.

Everything was working fine on local dev, but now I moved it to a development server, I'm getting an error every time I try to create a new entry (or section).

When devMode == false I get:

  CDbCommand failed to execute the SQL statement: SQLSTATE[HY000]:
  General error: 1785 Statement violates GTID consistency: Updates to
  non-transactional tables can only be done in either autocommitted
  statements or single-statement transactions, and never in the same
  statement as updates to transactional tables.. The SQL statement
  executed was: INSERT INTO craft_searchindex (elementId,
  attribute, fieldId, locale, keywords) VALUES (:elementId,
  :attribute, :fieldId, :locale, :keywords) ON DUPLICATE KEY UPDATE
  keywords = :keywords. Bound with :elementId='61',
  :attribute='field', :fieldId='1', :locale='en', :keywords=''

After some debugging I found the answer:

Problem is caused by craft_searchindex using MyISAM as the table engine, while the rest are using InnoDB, and the server having enforce_gtid_consistency ON. This caused issues on transactions that included queries to MyISAM tables.

Seems that the reason for this is supporting full text searchess in old MySQL versions (as InnoDB gained full text search support around 5.6.4)

I'm now experimenting on switching the engine for that table and seems to work nicely.


how to reroute old html pages? I want to reroute old html pages.
The format is:  /title-35-of-page.863.en.html
I want to route every adresse with .html at the end also get the lang and id part of the address for further handling, but have problems with the dots.
This are some versions that i tried, but none of them worked.

'(?P<title>[-\w\d]+).html' => array('action' => 'jpk/rerouteOldPages')
'(?P<title>[-\w\d]+)html' => array('action' => 'jpk/rerouteOldPages')
'(?P<title>[-\w\d]+)\.(?P<papayaId>\d+)\.(?P<language>\[a-z]{2})\.html' => array('action' => 'jpk/rerouteOldPages')

Ok, this works, the backslash behind "...language>" was wrong:

'(?P<title>[-\w\d]+)\.(?P<papayaId>\d+)\.(?P<language>[\w]{2})\.html' => array('action' => 'jpk/rerouteOldPages'),


Craft 3.1: value of craft/web/Application::getIsLive() must be of type boolean, null returned I tried upgrading a Craft 3.0 installation to 3.1, and got the following error:

  "value of craft/web/Application::getIsLive() must be of type boolean, null returned"

Has anyone else run into this?  Does anyone know a fix?

I resolved this by adding 'isSystemLive' => true in general.php


Updating Asset Indexes Fails with TemplatesController Not Found Error in Craft Logs Client wants to be able to upload a 90MB .mp4 file to a local asset folder, that understandably throws a 'General error: 2006 MySQL server has gone away'.

I uploaded the file directly to the server via FTP and attempting to re-index the assets throws an unknown error in the CP for each individual asset and crashes the server.

Craft Log reads this error for each asset in the index:

2019-07-10 13:20:43 [-][-][-][error][yii\web\HttpException:404] yii\web\NotFoundHttpException: Template not found: 403.shtml in "path"/craftcms/cms/src/controllers/TemplatesController.php:87

With either 403.shtml or 500.shtml being the only difference between errors.

There are ~60 assets, all under 8MB, except one other 200MB .mp4 file.

My suspicion is that the server only has 512MB of RAM and it's crashing while attempting to process 300MB worth of data from just two of the 60 assets, as the entire site goes down in the attempt.

PHP Options max_upload memory_limit are 256MB, post_max_size is 128MB, and max_execution and max_input_time time are 240s.

I would check your server logs for any further clues.


Is Shorter Twig Conditional possible? Is there a way in Twig to make this conditional shorter so I don't use "craft.request.getSegment(2)" twice?

{% if craft.request.getSegment(2) == "knowledge" or
craft.request.getSegment(2) == "search" %}

The Containment Operator helps with this...

  It returns true if the left operand is contained in the right

{% if craft.request.getSegment(2) in ['knowledge', 'search'] %}

OR

{% if craft.request.getSegment(2) not in ['', 'sale'] %}


Is there an easy way to loop through all existing values of an entry field and store them in an array? Looking to loop through and filter based on possible values in a text entry field...I have a text field called storeBanner that has 11 possible values (but could have more). Just need a way to go through every entry and create an array with all possible values.

I'm not sure about an array of the possible values. But you can get the actual values. You can do this with twig's merge filter. First get all the entries:

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

Then loop over the entries and add them to an array:

{% set allValues = [] %}

{% for oneEntry in allEntries %}
  {% if oneEntry.storeBanner not in allValues %}
    {% set allValues = allValues | merge([oneEntry.storeBanner]) %}
  {% endif %}
{% endfor %}

Now allValues will be an array of the values

Things to notice:

You need to set allValues outside of the for-loop. Otherwise it will only exist in the scope of the for loop, and not afterwards - ouside it.
You need to pass an array as the parameter of merge. In this case an array with one value: [oneEntry.storeBanner]


Convert string to date format that can be used in a craft.entries tag I've got a date string from the url in this format: "2021-06-01" (year-month-day) and I want to find entries that have a date in the year and month from that string. The date is a date field in Craft.
{% set entries = entries.startsOn(craft.app.request.getParam('departure')|date("Y-m")) %}

That does not work!
Any ideas gratefully received!

You could do this:
{# Your date 2020-11 in atom format e.g 2020-11-01T00:00:00+01:00 #}
{% set departureDate = craft.app.request.getParam('departure') | date("Y-m") | atom %}

{# Your date + 1 month in atom format e.g 2020-12-01T00:00:00+01:00 #}
{% set untilDate = departureDate | date_modify('+1 month') | atom %}

{# Query between those 2 dates #}
{% set query = query.startsOn(['and','>=' ~ departureDate, '<' ~  untilDate ]) %}

Note that on the November the 25th for example, you'd only be querying 5 days of the month


Craft plugin services in subfolders So I'm getting to a point where I have a lot of services in a particular plugin, and I would like to organize my plugin services into sub-folders. I've tried a couple ways but the controllers don't seem to be able to find the appropriate services unless they are in the main services directory. I know I can put controller files in sub-folders of the controllers folder, so I thought the same would be true for services. Does Craft support what I'm trying to do?

Craft will only look in the immediate pluginHandle/services folder when auto-loading and registering a plugin's service files.

If you wanted to support services in subfolders (i.e. pluginhandle/services/subfolder1, etc.), you'd have to manually autoload and register those classes yourself from your plugin's init() method.


Export from Craft 3.4 to Craft 3.0 using Feedback I have a very strange situation.

A production site is running Craft3.0 - there is no easy way to get this site up to Craft3.4. This is not possible at present because of the server and upgrading PHP.

I have used FeedMe locally on Craft3.4 to import a few thousand entries into the site.

Now I have these entries on my local machine running Craft3.4, and I need them placing onto the live site which is Craft3.

Exporting that tables that I think are needed results in multiple copies of the entries being created. E.g. 5 of the same news articles all with the same slug.

I am exporting and then importing the following tables...

craft_assets (because of images on the entries)
craft_categories
craft_content
craft_elements
craft_elements_sites
craft_entries
craft_relations
craft_userpermissions
craft_userpermissions_usergroups
craft_userpermissions_users
craft_userpermissions_users
craft_users (because of authors)

Am I missing a table?

Am I confusing Craft3 by adding a certain table?

Is this impossible because of the differences between Craft3 and 3.4? I have looked at the tables and they are identical so I am unsure why it is getting itself into such a state.

I realise this is a very odd and suboptimal situation - but I am stuck with this at present with no way to upgrade the server and the PHP version.

I would highly advise against trying to import anything directly into tables. I don't know when it was added, but everything now has a global identifier (UID) which you cannot add manually. FeedMe sounded like the right approach; I'd look at running that import on the production site and letting FeedMe import the content for you through the control panel rather than trying to directly add it to the database.


Is it possible to have entries only visible to logged-in users? I want to have a public and private (logged in users) section on the front-end. Is that possible on craft?

Yes. You need to build a frontend login form and then block non logged in users from seeing the entries with something along the lines of this:

{% if craft.session.isLoggedIn %}
    {# put content here #}
{% endif %}

You can also check if the user belongs to a specific group with isInGroup('groupHandle') (more here)


How, in a plugin, can I check that a User's "Favourite Entries" field contains a specific Entry? Users in my project have a Favourite Entries field. In my plugin I want to check whether a specific Entry is present in that field for that user. I'm passing the Entry ID to look for. I am not interested in getting the Entry itself - I just want to check to see if it's already in the Favourite Entries field or not.

I'd hoped that this would work:

if( $user->favouriteEntriesField->id($searchingForThisEntryId)->total() === 0 ) {
    ... doesn't contain the Entry yet ...
}

But it doesn't work ( Object of class Craft\ElementCriteriaModel could not be converted to string )

[edit]

A working solution is to loop through everything:

foreach ($user->favouriteEntriesField as $favouriteEntry) {
    MyPlugin::log("ID of loop iterations Favourite Entry: $favouriteEntry->id", LogLevel::Info);

    if($favouriteEntry->id === $searchingForThisEntryId) {
        craft()->userSession->setError(Craft::t('This document is already favourited.'));

        $this->documentFavourited = "yes";
    }
}

You can avoid looping by getting an array of the IDs of the favourite entries, then check to see if the specific Entry ID is in the array.

$favouriteEntryIds = $user->favouriteEntriesField->ids();
if( in_array($searchingForThisEntryId, $favouriteEntryIds) ) {
    ... the Entry has already been favourited ...
}


Missing buttons after upgrading site to 2.5 Same issue as found here - but no resolution: Missing buttons in settings after update to 2.5 beta

All of the orange buttons in the CP are missing but the code is there for the css and if I select a checkmark and unselect it then press return the functions still run.

The only thing I can think that may have triggered this is there was a license discrepancy while I ran the upgrade, but I can't recreate it on a new install.

It's missing on every single browser across multiple computers.

I had this same issue and resolved by fixing my Redactor configs. If you have a misconfigured file or a formatting error it causes problems related to rendering later in the page, likely related to Redactor throwing a javascript error.


Display different Categories groups in custom breadcrumbs I have a custom list of breadcrumbs that two of the levels reference different Category Groups. I'm able to get the correct breadcrumb to display for the page that I'm on using category.title, but I need to display the correct category for the previous breadcrumb also.

I've made some progress and have managed to get it to display the first category in the group I want by using {% set county = craft.categories.group('counties').first() %} but I need it to display the category that I've attached to the page with a category field, and not just the first item in the category.

Here's the current code:

{% block breadcrumbs %}

                All Developments
                {% set county = craft.categories.group('counties').first() %}
                {{ county.title }}
                {{ category.title }}

{% endblock %}

I've managed to solve it. {{ category.counties.first().title }} did the trick.

Clearly I just needed to print the category field, although I'm not sure why it needs the .first() after category.counties to print it? But it works at least after days of struggling to find an answer.


Update User "Field Type" for Entry in Plugin I have a channel called "Groups", with a users field type called members for the entries. I need to be able to add/remove users to the members entry field via plugin.

What I've tried is:

// criteria
$criteria = craft()->elements->getCriteria(ElementType::Entry);

// filter
$criteria->slug     = 'groupNameHere';

// section
$criteria->section('groups');

// get entry
$entries = $criteria->find();

foreach($enries as $entry)
{
    // get current members of group
    $members = $entry['members'];

    // add new user model to $members
    $members[] = craft()->users->getUserByUsernameOrEmail("newUserEmailHere");

    // update field with new $members array
    $entry->getContent()->setAttribute('members', $members);

    // save
    craft()->entries->saveEntry($entry);
}

This simply clears the previous members value for the group, without even adding the new user. I can't find anything online about updating this type of field-type via plugin so I'm just guessing how to do this. Does anyone know the right way to do this?

Any information would hugely help! Thanks!

When a User field is saved, it takes an array of user IDs only – not complete UserModel objects. Something like this should work:

// get IDs for current members of group
$members = $entry->members->ids();

// add new user ID to members
$members[] = $addUser->id;

// update field with new $members array
$entry->getContent()->setAttribute('members', $members);

The rest of your code looks fine, except for a minor typo – $enries should be $entries.


Instructions for Using Craft "Embedded Assets" Plug-in? I'm trying to use the "Embedded Assets" Craft plug-in to embed Youtube videos in my content, but I can't figure it out. I've read through the instructions on the Github page, and I've looked at other resources online, but it's not working and I can't make sense of it.

I have successfully installed the plug-in, and it seems to be "grabbing" the videos correctly because a thumbnail for the video appears when I enter the URL for it in the "Embed link" Asset selection. These are also saving in their respective fields when I enter them into an Entry.

Where I'm having trouble is understanding how to integrate them into my templates; the only configuration I changed was the 'extraAllowedFileExtensions' => 'json' setting in the general.php file. It said something else about configurations in the documentation, but it was very vague and said their should already be defaults in place. I tried dropping the code in that they suggested, as well, and played with the values a bit, but it's just empty space when I preview the page (or it breaks the page altogether).

Here is the code I tried to put into my template in different forms (tried the given loop, not looping, and etc.):

{% for asset in assets %}
    {% set embed = craft.embeddedAssets.fromAsset(asset) %}
    {% if embed %}
        {{ embed.safeHtml|raw }}
    {% endif %}
{% endfor %}

If you care to write an example, the handle for the field I'm using is embeddedMediaUrl and the embed links are stored in assets/mediaEmbeds (not sure if this info is needed or not.)

Any and all help with this will be greatly appreciated. I apologize if this is vague, but I've been messing around with it long enough that it seemed time to reach out to the community to see if someone could give me some help. Thank you.

Author of EA here. Adding in that extraAllowedFileExtensions config setting is about all you need to do. Any other configuration is just for "power" users (for lack of a better term) and you shouldn't need to worry about them.

There's many reasons why you might not be seeing anything show up in your templates. You also said it sometimes breaks the page altogether? Can you please elaborate on this? Are you running in dev mode? If there are any errors, what are they?

It might be better for you to post this as an issue on the Github page, so it can be more of a discussion. I don't really have an answer for you as I don't yet know what the cause of the problem is.


Admin assets not being served over https I switched my craft install to be completely served over SSL. The front end continued working fine, but the backend is 404'ing all static assets. I assume this is because the http was handling the /admin/resources/ rule fine but not the https. I'm using NGINX but am using the exact same config that I was before, just adding in my SSL Certificate keys. Any thoughts on config settings to look at or lines of code to investigate?

So I added the following lines to my nginx file and it all worked

location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
    try_files $uri /index.php?$query_string;
}

location ~* \.(?:css|js)$ {
    try_files $uri /index.php?$query_string;
}


Generate PDF preview images automatically? Is it possible to auto generate PDF preview images with Craft transforms? This popular Q/A at Stack Overflow shows a PHP solution making use of ImageMagick and GhostScript. Is installing these plugins all I'd need to make Craft do the transforms with pdf.getUrl('thumb')?

Currently I use an assets - asset meta field on the PDF to achieve what I want (see code below), but that means I have to generate and upload the image myself. So I wondered if there's a nice and easy way to automate that process.

{% for pdf in entry.pdfAssets %}

    {# Get the pdf preview thumb or use a generic one as a fallback #}
    {% set previewImage = pdf.previewImage|length ? pdf.previewImage.first.url('thumb') : 'pdf_thumb.jpg' %}

{% endfor %}

There a plugin for that:

https://github.com/carnesmedia/pthumb

PThumb is a Craft plugin that generates thumbnail preview images for PDF documents. It's easy to drop into your templates, requires only the commmand-line version of ImageMagick (not the PHP bindings), and caches the generated thumbnails.


Plugin record no dateUpdated and uid I'm building a small analytics plugin and as such, I don't need the dateUpdated and uid columns in my records, but I dind't find any way of disabling them.
Currently I have tried:

Not setting them in the install::safeUp: doesn't work as Craft adds the attributes to the list and PDO complains "column not found dateUpdated"
Making my record directly extend Yii2's active record and not craft's one

Nothing worked.
Is there any clean solution to this?
Thanks a lot for your help!

This might not be the answer you were looking for, but I don't think you need to go to great lengths trying to achieve something that in my opinion is not necessary. While it might seem to be not "clean" to have database table columns that are not required by your application/plugin, consider that todays ICT infrastructure is powerful enough to not slow down due to a few additional columns in a database and its tables.
I would even consider it more risky trying to alter the "base" of Craft or the Yii framework than to live with a few autogenerated columns.
If you are very sensitive to performance and have many database requests, you might not want to use active record since its higher level of abstraction can come with a performance penalty in certain situations.


How can I find entries that link to a given entry? I'm retiring a section of my website and want to remove all existing internal links to this section. Is there an existing way to find any links to each entry in that section?

These links are all in Redactor fields (eg. inserted via the toolbar), and these fields may have different names etc across multiple sections.

I've tried running a regex search across a Craft database dump, looking for a pattern of {entry:[0-9]+:url} which shows me all the places that link to other entries, but this alone only gives me the entry IDs so I'll have to write further code to look up those IDs and work out which ones are in the section I'm removing.

Is there an easier way to do this, or is it going to be a semi-manual job?

Have you thought about running something like Screaming Frog https://www.screamingfrog.co.uk/


Taxcloud.net integration for Craft Commerce? We have a lot of exemptions, re-seller and agriculture, as well as states to report. this tool calculates and accepts the customers exemptions. We are looking at making a plugin but wanted to see if it has already been done.

The service is no or low cost and does the filing for a good number of states. So this is a great alternative to other sales tax services.

As of Sept. 27 2016, I'm not aware of any existing taxcloud.net integrations with Craft Commerce and I'm not seeing any on https://straightupcraft.com/craft-plugins/ as well.


How do I pass a user's first name and last name from a user profile page to the title in _layout? I am trying to pass a member's firstName and lastName to the title on a member profile page. I am using segment 2 to capture the username. This works well in the for loop in the block:

{% set thePartner = craft.users.username( craft.request.getSegment(2) ) %}
{% for partner in thePartner %}
First Name and Last Name: {{ partner.firstName}} {{ partner.lastName }}
{% endfor %)

Outside the block, where I set the <title>, it doesn't work. Essentially, I would like to set the full name and use it in the title, like:

{% set fullname = partner.firstName ~ ' ' ~ partner.lastName %}

with something like the following in _layout:

<title>{{ fullname }} | {{ siteUrl }} </title>

How can I pass the full name through?

Since you're just expecting one, you should only look for one. Then you don't have to use a for loop. Plus, fullName is already an attribute of user models. So you can do this for the title:

{% set thePartner = craft.users.username( craft.request.getSegment(2) ).first() %}
<title>{{ thePartner.fullName }} | {{ siteUrl }} </title>

If you're still having trouble, it may be with what segments you are pulling from the URL.


Table button missing in Rich Text fields? I updated to Craft 2.3 and noticed that the Table button is now missing from my Rich Text fields?

How can I get that button back?

Update: since version 2.3.2621 Craft comes with Redactor's table plugin preinstalled again. So there's no need to do anything special, simply add it to your Redactor json config.

Craft 2.3 now comes with a new version of Redactor. With the release of Redactor 10 non-essential functionality was removed from Redactor's core and is now released as separate plugins.

So, to get the Table function back, you have to add the Redactor Table plugin to Craft.

You can download and save the plugin into craft/app/resources/lib/redactor/plugins/ or you can make a little Craft plugin that adds this Redactor plugin to Craft.


Check if a FieldHandle exists in Module without throwing 'Invalid field handle' exceptions I've been pulling my hair out trying to work this one out.
I'm building a module to auto-populate a super-table on EVENT_BEFORE_SAVE, the module works exactly the way I want it to, everything seems to be working fine.
Except Craft throws a "Invalid field handle:" exception if the custom field doesn't exist on that entry.
I've tried to check if the field exists with a few different methods, but anything that directly references the fieldhandle seems to throw an exception.
What's the proper way of checking if a field exists and running the code if it does?

Without modifying your code too much, you could simply add an exception handler with a try/catch block.
Another method would be to retrieve the field handles for the entry type's field layout, and check for a match:
Getting the $entryType as necessary,
$etFieldHandles = [];
$fields = $entryType->getFieldLayout()->getFields();
foreach ($fields as $field) {
    $etFieldHandles[] = $field->handle;
}

if (in_array('yourfieldhandle', $etFieldHandles) ) {
    // the field exists in this entry type's layout.
}


Pass image transformations into macro I have a very basic macro for a lazyloading responsive image tag:

{% macro isotopeItem(imgParam) %}

  {% set thumb = { mode: 'fit', width: 100, quality: 60, } %}
  {% set tSM = { mode: 'fit', width: 1536, quality: 80, } %}
  {% set tMD = { mode: 'fit', width: 340, quality: 80, } %}
  {% set tXL = { mode: 'fit', width: 1536, quality: 80, } %}

    <img
    src="data:image/gif;base64,{# yadayada #}"
    data-sizes="auto"
    data-src="{{ imgParam.url(thumb) }}"
    alt="{{ imgParam.title }}"
    data-srcset="
      {{ imgParam.url(tSM) }} {{ imgParam.getWidth(tSM) }}w,
      {{ imgParam.url(tMD) }} {{ imgParam.getWidth(tMD) }}w,
      {{ imgParam.url(tXL) }} {{ imgParam.getWidth(tXL) }}w"
    class="lazyload" />

{% endmacro %}

As you can see the image transformations are inside the macro which is not very nice.

How do I write the transformations outside the macro and then pass it into it? I tried tried to write one param for each transformation:

{% set thumb = { mode: 'fit', width: 100, quality: 60, } %}
{% set tSM = { mode: 'fit', width: 1536, quality: 80, } %}
{% set tMD = { mode: 'fit', width: 340, quality: 80, } %}
{% set tXL = { mode: 'fit', width: 1536, quality: 80, } %}

{% macro isotopeItem(imgParam, transformParam1, transformParam2 {# and so on #}) %}
   {# responive image srcset code like the above example #}
{% endmacro %}

{# I then would have to call the macro like this: #}

{{ _self.isotopeItem(asset, thumb, tSM, tMD, tXL) }}

This works but I have to pass all the transforms everytime I use the macro.

There must be a better way right?

Edit: I changed it to your variables, not sure if I set the array brackets 100% correct but the idea should work.

You could set the defaults in the macro as you already did,
then in your template call the macro and pass the options e.g. :

{% set image = block.slide.first() %}
{# macro #}
  {% set imgParam = [
    thumb: { quality: 60, },
    tSM: { mode: 'crop', width: 1536 },
%}

{% macro isotopeItem(imgParam) %}

and merge the passed options in the macro with your macros defaults e.g.:

 {% set defaults = [
    thumb: { mode: 'fit', width: 100, quality: 60, },
    tSM: { mode: 'fit', width: 1536, quality: 80, },
    tMD: { mode: 'fit', width: 340, quality: 80, },
    tXL: { mode: 'fit', width: 1536, quality: 80, }
  ]
%}

{% set imgParam = imgParam ? defaults|merge(imgParam) : defaults %}

so you will only need to pass explicit changes.


Charge object not available on first page load I have a custom donation form that I'm using that includes some custom Craft fields. Two of those fields are dropdowns which I populated with options from within my Craft admin panel.

Since this is a custom form, it must use Stripe.js, so I have the following lines in my template per the tutorial on the SquareBit site:

{% includeJsResource('charge/js/stripe_v2.min.js') %}
{% includeJsResource('charge/js/jquery.charge.js') %}
{% includejs %}
    $(this).charge();
{% endincludejs %}

Here are my Payment options that are set inside the <form> declaration:

{% set chargePaymentOptions = { 'allowDynamic' : true, 'planCurrency': 'usd', } %}

{{ craft.charge.setPaymentOptions(chargePaymentOptions) }}

I borrowed some code from the Charge plugin examples for initializing the select fields like so:

{{ forms.selectField({
     label: 'Donation Recurrence',
     name: 'donationRecurrence',
     id: 'donationRecurrence',
     options: (charge is defined ? charge.donationRecurrence.options),
     value: (charge is defined ? charge.donationRecurrence),
     errors: (charge is defined ? charge.getErrors('donationRecurrence'))
}) }}

{{ forms.selectField({
     label: 'Would you like to donate to a specific cause?',
     name: 'donationDesignation',
     id: 'donationDesignation',
     options: (charge is defined ? charge.donationDesignation.options),
     value: (charge is defined ? charge.donationDesignation),
     errors: (charge is defined ? charge.getErrors('donationDesignation'))
}) }}

As you can see, the select fields get their options from the aforementioned pre-populated custom Craft fields. Those options do not show up on first page load, but if the form is subsequently submitted and comes back with errors, then the select field options appear.

I figured out that on the first page load, doing a dump(charge) shows that the charge object does not exist until the page has been reloaded after the form was submitted.

Thanks for any help.

My current workaround: Get the select field directly and set its options to the select field options:

{% set donationRecurrenceOptions = craft.fields.getFieldByHandle('donationRecurrence').settings.options %}


How to show entries with IF statement based on field I'm showing entries on a page. Depending on the value of the field postAspectRatio, I would like the layout of this shown entry to change just slightly and thus requiring it's own unique markup.

I've tried to do this using what I know about twig IF syntax but it's not working.

Any help?

{% block content %}

{% for entry in craft.entries.section('projects').order('postDate asc').limit(500).find() %}

        {% if entry.postAspectRatio == 'Portrait' %}

{{ entry.studio }}{{ entry.title }}

        {% endif %}

        {% if entry.postAspectRatio == 'Landscape' %}

{{ entry.studio }}{{ entry.title }}

        {% endif %}

{% endfor %}

{% endblock %}

Your if statements looks correct. You might check that you are testing the value vs. the name (i.e. 'Portrait' vs 'portrait') or printing out the value (using {{ entry.postAspectRatio }}) so you can see the output. Also, a 'dryer' way to write this might be:

{% block content %}

    {% for entry in craft.entries.section('projects').order('postDate asc').limit(500).find() %}

{{ entry.studio }}{{ entry.title }}

    {% endfor %}

{% endblock %}


How to set the commerceCurrency filter in an European style Using commerceCurrency filter from the Craft commerce plugin, how can I add the currency name after the price instead of before the price, and drop the zeros when not necessary ?

For example :

{{ product.variants[0].salePrice | commerceCurrency(cart.currency) }}

  €68.00

How can I output this :

  68€

Thank you!

The current formatter looks at the currency's format and the current locale of the user. What locale are you set to?

You can drop the zeros with the stripZeros param in the currencyConvert filter. See docs here: https://craftcommerce.com/docs/twig-filters


Pulling the currently rendered field layout inside the CP Inside the CP, is it possible to pull the ID for the current field layout being rendered (both in the Field Layout Designer and in element editing forms)?

A bit of context:

I'm writing a plugin which adds functionality to the built-in Field Layout Designer. The extra functionality basically allow admins to add metadata when they are editing field layouts. This metadata is stored in a custom table, using the field layout's ID as FK. The idea is that whenever a field layout is rendered (either inside the FLD, or when an element is edited/created) the plugin should pull the metadata for the current field layout.

Modifying the FLD UI is easy – when the plugin loads, I basically check the DOM (with jQuery) for a FLD container. If a container is found, the plugin loads up a script.

Saving the metadata is also easy; the plugin hooks into fields.saveFieldLayout like this:

craft()->on('fields.saveFieldLayout', function (Event $e) {
    $myPluginModel = new MyPlugin_MyPluginModel();
    $myPluginModel->fieldLayoutId = $e->params['fieldLayout']->id;
    $myPluginModel->metadata = craft()->request->getPost('myPlugin.metadata');
    craft()->myPlugin->saveStuff($myPluginModel);
});

The hard part is querying for the relevant metadata whenever a field layout is rendered, because I can't find a way to pull the currently rendered field layout's ID.

Here's ideas I've explored/solutions that doesn't work:

Neither the FLD nor the element editing forms expose their field layout's ID to the the DOM.
I've looked at the HttpRequestService to see if the field layout ID (or any other data I could use to query for the field layout ID) could be pulled from the request.
I've tried accessing the current controller class via craft()->controller – thinking if I could get to the current element type I might be able to pull the field layout from its model, but craft()->controller is always NULL.
I've attempted to pull the global Twig context (via craft()->templates->twig) to look for the fieldLayout variable.
Ideally, I wouldn't want to pull the relevant metadata client side (i.e. with AJAX), but I did also look at the global Craft JS object to look for clues, but found nothing.
Parsing the request path and storing the ID of the entry type, asset source, category group etc. along with the field layout ID would work. I'd like to avoid this, because it makes it impossible to support custom element types without hard coding stuff.

If it isn't possible – by any means – to pull the current field layout ID, the alternative approach is to somehow figure out which element type is being edited, then pull that element type's model and finally get the field layout model/ID from there. Ideally, I'd like to do this without having to hard code attribute names (i.e. entryTypeId, categoryGroupId etc), because I want this to work for any custom element type, too. Any suggestions in this regard is very welcome, as well.

It looks like EntryTypeModels have a fieldLayoutId attribute. By inspecting the route params, we can get the entry type ID, and then create a model from that. Other than this, I haven't been able to find anything passed to the FLD.

    $params = craft()->urlManager->getRouteParams();
    $variables = $params['variables'];
    $matches = $variables['matches'];
    $entryTypeId = $matches['entryTypeId'];
    $entryType = EntryTypeRecord::model()->findById($entryTypeId);
    $fieldLayoutId = $entryType->fieldLayoutId;

Hopefully this helps!

Edit:

I also found that a fieldLayoutModel is passed to the fieldlayoutdesigner.html template when it is included. See the include in templates/settings/section/_entrytypes/edit.html as an example. Content from the FieldLayoutModel is then loaded.

I know you said you would rather not load with ajax, but it is definitely better than nothing. I don't see any hook or event that gives you access to this information.

You could do something like

var fieldLayoutId = '{{ fieldLayout.id|e('js') }}';

from within your included js file and then go pull your metadata via ajax.


How can I list all sub-field handles of a Matrix parent field? If I want to get a list of all fields that I've defined on the site, I can do this:

craft()->fields->getAllFields()

But how do I get a list of all sub-fields defined within a Matrix field?

I have access to the MatrixBlockModel, if that helps.

You’ll need to start by figuring out the Matrix field’s ID. If you already have a MatrixBlockModel object as you say, you can get that via $matrixBlock->fieldId.

Once you know the Matrix field’s ID, you can get all its block types like this:

$blockTypes = craft()->matrix->getBlockTypesByFieldId($matrixFieldId);

That will give you an array of MatrixBlockTypeModel objects. From there you can loop through each of those and get their fields like this:

foreach ($blockTypes as $blockType)
{
    $fields = $blockType->getFields();

    // ...
}


link twig template in a tag I created two twig templates: home.twig and about.twig.
in home.twig it's this code:

go to about template

and in about.twig it's:

about

when I click "go to about template" it shows 404 error but, when I go to http://MY_HOST/about it shows me the about template.
how to link this templates? thank's

What is the URL of the page, where the link to /about is shown?
Make sure you do not have a  tag in the source of the page
Make sure you are not switching from http:// to https:// (SSL), which could also cause the 404 if the host is not available on http:// AND https://


How to change the display of asset fields in the control panel via plugin? I would like to modify how assets are displayed within asset fields in the control panel's edit entry page, so that thumbnails are larger and the name is not displayed.

After some investigation I found that when assets are added to an entry the following line is called {% hook "cp.elements.element" %}. This is calling the template service generating the html that displays the thumbnails and the name. ( _getCpElementHtml() is the function that is associated with the hook ) Is there a way to modify this without directly changing the core files?

Short answer: no. The thumbnail size (30x30) is hardcoded into the method you found (_getCpElementHtml), so there's no way you can change that.

You could try extending the control panel's CSS (using this plugin) to enlarge and/or hide certain elements, but that won't get the thumb any bigger.


Serving Cloud Assets over SSL How does one go about serving asset files stored in cloud locations over SSL?

For S3, serving assets over SSL is simply a matter of changing 'http' to 'https'. However, Rackspace uses completely different domains for their SSL. This creates a situation where http://container1.rscf.com/myfile.jpg mightb be served over https://weird.something.rscf.com/myfile.jpg.

There just seems like there should be a property in the getUrlForFile method in AssetsService.php that helps with this, but I'm not seeing it.

Personally, I would just go with S3 (I've ranted about this before), but I understand that sometimes your hand is forced.

I was not even aware that Rackspace supported SSL or that it would be a different domain. I did some digging through their docs and it seems there'll be some work involved to get this feature in and it will cause a change in behaviour, so I'd say this will have to wait until 2.2.


Not a Craft CMS designer and need help I am actually doing on page SEO for a Craft site. I created 4 new pages. I have no idea how to publish them, put the links into a block on the home page, add an image to the content, and add to the menu via a dropdown. Is this all possible?

I am well versed in WP but not Craft.

Craft often requires a different approach than Wordpress, but can be just as easy and powerful to use when set up correctly. The big unknown in your situation is how your content architecture and templates are set up.

Content architecture and template decisions in Craft are custom from site to site and designed by the firm that created or maintains the website. To help further with you question, we'd need to understand how your sections and navigation are set up, if your sections have URLs, what assumptions your templates are designed to make about the content they output, and so on. Getting training from the firm who built the site or hiring a consultant to walk you through your site and give you a tour of how things work could be helpful in your situation.

A few resources that could help you get started:

Craft Feature Videos - Short videos on how key features in Craft work
Straight Up Craft Training - Free, weekly intro training
Mijingo Video Course - Overview of building a site in Craft

If you are in the situation where you are looking for a consultant or firm to work with, there are a couple of Craft professional listings and job directories. At the time of this post:

Straight Up Craft - Jobs
Straight Up Craft - Professionals
Work With Craft
Work With Craft - Professionals
Craft CMS Partners
Craft Slack #jobs channel


Twig function to load templates into variable? I'm trying to figure out how to load a template file and pass it as a variable to another template file while it is being included. In some sense I want to do something like this:

{% include 'component/footer', with 'component/nav' %}

I know I can't do that directly, but in the twig documentation there is an example showing this:

$template = $twig->load('some_template.twig');
$twig->display('template.twig', array('template' => $template));

Is it possible to do the same thing with Craft's twig support?

You can't do it exactly like that in Twig. But there're different approaches that'd do the same thing depending on exactly what you're trying to achieve.

For instance, you could parse the template into a variable, and then pass the variable to your include:

{% set nav %}
    {% include 'component/nav' %}
{% endset %}

{% include 'component/footer' with { nav: nav } %}

Or, you could just pass in the template name as a string, and parse it inside the component/footer template. In you base template:

{% include 'component/footer' with { navTemplateName: 'component/nav' } %}

Inside component/footer:

{% include navTemplateName %}

What approach suits your use case depends on whether or not the scope that component/nav is parsed in, matters.


Protecting paths with htpasswd I would like to know if it is possible to protect some sections of the site with an htpasswd or not?  I know that I could protect it by using user groups in my template, but I'm looking at avoiding the cost simply because the site is very temporary (1 week) and not for external purposes.

So basically,

http://mysite.com/mysection1

http://mysite.com/mysection2

http://mysite.com/mysection3

Those 3 sections would be protected by a different password, but they would also be pages in my site.  Can I just create the real physical folder and create the same page with same url in Craft?  Is there a way to achieve this?

Thanks!

Using htaccess/htpasswd in each folder does work, but I don't find it really elegant.  Would there be a better way of doing this without Craft's users?


Archive pages with full month names? I've got News Archive pages that display all entries posted in a certain month/year. For example June 2016 shows all entries created in June of 2016!

I'm fetching the entries based on craft.request.segment (as the URL ends in /june/2016 etc). This works great for all English months, but when my URL says /juni/2016 (the German month name) it can't find any entries??

{% set month = craft.request.segment(2) %}
{% set year = craft.request.segment(3) %}

It's defintely a translation thing. Anyone know how craft.request.segment can work with locales (German and simplified Chinese) too?

Twig’s date filter is aware of the current Craft locale, so you should be able to create a DateTime after composing a string that the filter accepts (see PHP strtotime function docs, which the filter uses behind the scenes).

{% set day = 1 %}
{% set month = 'juni' %}
{% set year = 2016 %}

{% set dateString = [day, month, year]|join(' ') %}
{% set date = dateString|date %}

{{ date }}


How to require form submission before template display? I have a white paper PDF file that I want visitors to be able to download, but only after they've submitted a form with their contact information. How can I do this in Craft?

Currently, I'm using the Sprout Forms plugin to build a form, and I've set the redirect for the form to a template containing the download link. This does work, but seems clunky, and any visitor who has the URL for the download page can visit it without submitting the form.

How can I require a form submission before displaying the template with the download link to the visitor?

Not terribly familiar with Sprout Forms, but it looks like you could gate the download with a query string parameter, like in Sprout Forms' Thank you Page example

Example:

Add this to your form:

<input type="hidden" name="redirect" value="/DOWNLOAD_PAGE?submitted=true">

and then in your download link template:

{% if craft.request.getParam('submitted') == 'true' %}
    DOWNLOAD_LINK
{% else %}
    Please submit the form here LINK_TO_YOUR_FORM to access this whitepaper.
{% endif %}


When accessing a Category url is there direct access to the Category's fields? I have setup a category group to use Url's. When navigating to that url does the template have direct access to that category's inputs like you would with and entry? Or do you have to use the segment and get the data that way?

Yes, the CategoryModel for your category will be available to the template as the variable category.

{{ category.title }}

{{ dump(category) }}


How do I reference a variable/expression inside an expression in twig templating? This is the desired code

Which works. However I want the transform name to be replaced by the contents of

entry.newsImageSize

So in a kind of pseudocode it would be

which of course does not work.

With Twig, you'll never need to nest tags within other tags. In fact, it's impossible to do.

You can simply pass your variable into getUrl instead of using a string.

<img src="{{ asset.getUrl(entry.newsImageSize) }}">


Loop through assets field on detail/product page I am trying to loop through an assets field called gallery on entries in a commerce products channel.

This field can have multiple images in it. I can get this to work on a channel listing page domain.com/shop/ but can't get this to work on the entry detail page domain.com/shop/products/detail/.

Any help is appreciated.

{% for asset in product.gallery.first() %}
    <img src="{{ asset.url }}">
{% endfor %}

product.gallery returns an ElementCriteriaModel, which you can think of as a list of elements. product.gallery.first() will return the first element in this list.

What you want is to loop over all the elements:

{% for asset in product.gallery %}
  <img src="{{ asset.url }}">
{% endfor %}

(Note that this will work if there are no elements in the list (because the for loop will never be entered). One thing you should avoid doing is product.gallery.first().url, because it is never possible to be certain without checking that there is a first element in the list.)


Resaving blog entries keeps failing Recently changed the URL format for a section. Now I have a red circle in the upper right and an error message of "resaving blog entries - failed". Trying again results in same error. Any ideas what could be wrong?

The section that entry #392 belongs to is called blog and it's Entry URL Format setting is set to blog/{slug}.

You also have quite a few entries (100 to be precise), with their slug set to: snippet generating a URI for that slug of blog/snippet.

That works great for the first one, but when you try to save the 2nd one, Craft sees that blog/snippet is already taken and will start appending numbers to the end to try and find a unique URI like so: blog/snippet-1, blog/snippet-2, etc.

But Craft wants to have a reasonable way to know when to stop trying to find a unique URI, so it will look to the maxSlugIncrement config setting and use that, which defaults to 100 - hence the error you're running into.

You either need to 1) use something to generate more unique entry slug formats - like post date/time or 2) increase the maxSlugIncrement config setting to a higher value.


Use subdomain for S3 assets in multi-site Craft installation I have found the section in settings where I can set the URL Prefix for an asset source using a CNAME and pointing to the relative S3 bucket where the file actually lives but I am using a multi site environment so I need the value of the URL Prefix to be dynamic.

I have tried setting it to assets.{{ craft()->request->getServerName() }}, also have tried assets.{% craft()->request->getServerName() %}but that is what's getting spit out on the page (asset url as rendered on page looks like assets.{% craft()->request->getServerName() %}images/home-banner.jpg.

How can I make Craft parse this field's dynamic value? The statement isn't parsed as it would be if it was in a Twig template.

Your example of setting the S3 "URL Prefix" setting to something dynamic won't work because there are only a few settings in the Control Panel that Craft parses for dynamic Twig content and that isn't one of them.  i.e. in an Asset Field's Upload Location, Section Title/URL Formats, etc.

Honestly, I don't think there currently is a way to do that in Craft 2.

This should be possible in the upcoming Craft 3 by overriding the setting in config/volumes.php and doing your dynamic logic from PHP.


Show all discounts at checkout with Craft Commerce I've taken the difference between the actual price and sale price of items and created a variable to hold the total value to give me a total discount at my checkout. I am curious if there is a way to do this with less code though? If I try to show {{ cart.totalDiscount | currency(cart.currency) }} it just comes up as $0.00, and this is with promotions -> sales at 10% off for all products. If there is a simple snippet like the one I referenced I'd love to know about it. Thanks!

Hmm, something else is at play here.

I use:

{% if cart.totalDiscount != 0 or cart.couponCode %}
  - {{ cart.totalDiscount | currency(cart.currency) }}

...and it works.

Are you sure the promotion is actually being applied?  I guess it is if you can calculate the discount.


Query all categories once and get individual categories from array I am working on a site that needs to both list all categories and also pull out individual categories by their id.

I would like to query the DB once for all the categories (to improve performance), and then pull out which ones I want, but am struggling to find a solution.

{% set catNavigation = craft.categories.group('products').limit(null).find() %}

{{ catNavigation.id(102).first.title|raw }}

{{ catNavigation.id(126).first.title|raw }}

This is giving me an error.

Array to string conversion

So I guess I can't grab pieces of an element criteria model after using find.

If I don't use find, then I query the DB multiple times.

I thought about creating my own array of categories dynamically with twig, but that has not gone well.

Is there a way to accomplish what I'm after? It's as if I need to search within an array of data that has already been returned from the DB. Hope that makes sense.

Your issue is that as soon as you call .find(), your ElementCriteriaModel returns an array of elements. In other words, the ElementCriteriaModel is gone, and it's no longer possible to add parameters (i.e. id()) or call other methods that you'd otherwise be able to call on that object (i.e. .first()).

On the other hand – like you say in your description; if you don't use .find() (keeping the ElementCriteriaModel around) you'll hit the database every time you use the .id() method.

A workaround could be to loop over the categories and add them to an indexed array (using the category IDs as keys) and then pull your individual categories from that index instead of the original array.

Important: One gotcha to note is that the |merge filter will actually renumber numeric keys, so you have to add an arbitrary character to the ID to retain the actual ID values (the example below uses an underscore prefix):

{# Get the categories #}
{% set categories = craft.categories.group('products').limit(null).find() %}

{# Create category index #}
{% set categoryIndex = {} %}
{% for category in categories %}
    {% set categoryIndex = categoryIndex|merge({('_'~category.id): category}) %}
{% endfor %}

{# Do your thing #}

{{ categoryIndex['_102'].title|raw }}

{{ categoryIndex['_126'].title|raw }}

Note that when you want to pull a category from the index, categoryIndex['_102'] and categoryIndex._102 will both work – I just find that the former looks a bit cleaner, with the underscore in front of it (obviously you can use any character, it doesn't have to be an underscore).

Edit

As pointed out by @carlcs in the comments below, another approach to creating the index is to use the group filter. With this approach you'll avoid the underscore hack and the for loop. The gotcha here is that this filter will actually create an array of arrays, meaning you'll have to use categoryIndex[102][0] (note the [0] at the end) to access a specific category (you could also use categoryIndex[102]|first, of course):

{% set categories = craft.categories.group('products').limit(null).find() %}
{% set categoryIndex = categories|group('id') %}

{{ categoryIndex[102][0].title|raw }}

{{ categoryIndex[126][0].title|raw }}


Element query - using "search" vs using field handle as query method With element queries, we can search for elements using search method:
craft.entries.search('someField:something')

or by using field handle as method:
craft.entries.someField('something')

How these two techniques are different from each other and when whould we use each?

The search parameter gives you an entire range of search functionality, as explained in the docs at https://craftcms.com/docs/3.x/searching.html
Using a field handle as a parameter essentially specifies what the value of the field must equates to. How this is determined can vary, based on the field type, but in most cases it will be an exact match.
So in the following example, only entries with the exact plaintext field value something will be returned.
craft.entries.somePlaintextField('something')

If you dump the query's raw SQL then you will see this.
{{ dump(craft.entries.somePlaintextField('something').getRawSql()) }}

Outputs: SELECT ... WHERE ... AND (`content`.`field_somePlaintextField`='something') ...


When should I build upon existing models in my own plugins? In the Craft Models documentation example the model extends the BaseModel class. However in the example Events plugin source code the Events_EventModel extends the BaseElementModel.

While poking around in PHPStorm I also noticed other "base model" classes such as:

BaseComponentModel
BaseElementModel
BaseEntryRevisionModel

I also wondered if it makes sense to extend non-base models such as the EntryModel (if you're modeling entry data for example).

BaseComponentModel, BaseElementModel and BaseEntryRevisionModel all ultimately end up extending BaseModel, which itself extends Yii's CModel.

I like to think of them, roughly, as beefed up Data Transfer Objects.  Primarily useful for transferring data throughout the various layers of Craft (templates, controllers, services, etc.).

Regarding which ones you extend, it depends entirely on what you are trying to do in your plugin and with your Models.

BaseModel is the most "generic" one as far as Craft is concerned that gives you all of the Craft specific attributes of Models.

BaseElementModel is useful if your plugin is dealing with Element Types.

BaseComponentModel is useful if your plugin is dealing with Component Types (tools, widgets, tasks, etc.).  You can check the craft/app/enums/ComponentType.php enum for a full list.

And BaseEntryRevisionModel is pretty self explanatory.

And there is nothing stopping you from extending things like Craft's own EntryModel directly, if you need specific features that it has.


Front-end registration validation I have a front-end registration page and need to change the validation to add (minimum characters for information on the page and to make fields to accept only letters and other to accept only number how can I accomplish this )
if there is any guide or step by step it will be nice ,
thanks in advance
my site is on this link : todo.net
registration page is : todo.net/register

You could use Regex (Regular Expression), /^[a-zA-Z]{3,}$/ would for instance allow a minimum of 3 characters behind the comma would be the max value.

As for numbers it would be something like this /^[0-9]{3,}$/

http://regexr.com/ to test your regex en examples

And I would do this before the user is saved with the users.onBeforeSaveUser Event in a plugin.


Appraising Craft CMS - newbie questions I am looking into the idea of porting my first site into Craft CMS. It is the site of a friend/client who has a railway engineering consultancy, and it's currently running on another CMS (TidyCMS). Before I dive in and look through all your documentation, I would appreciate some help, just so that I don’t run into a design roadblock further down the road.

There are really only two areas where I am concerned about porting to Craft CMS :

Actualités (News) page :
http://www.study-technologies.com/fr/actualites.html
These are news listings on the page (image + date + title/text), which point to individual article pages when clicked. Can this be done in Craft?

Project pages :
http://www.study-technologies.com/fr/projets-ferro.html
These are project galleries which are dynamically populated as individual project pages are created. An image in the project page is chosen to appear in the gallery grid. Can this be done in Craft?

A few other questions :

Can Craft CMS handle bilingual sites?
Is the Craft CMS admin available in French?
Can my client set up different user permission levels?**

I hope you can answer all of these, and if so, I’ll be diving in right away! I have other clients that I’d like to port over, but this client has the most complex design, so I’d like to use it as a test case.

Thanks,
Ric

Craft is the perfect CMS to handle everything you just pointed out.

Can Craft CMS handle bilingual sites? YES.

https://craftcms.com/docs/localization-guide

Is the Craft CMS admin available in French? YES.

https://craftcms.com/support/cp-languages

Can my client set up different user permission levels?** "YES".

Depending on your use case this will be doable. Then its just a matter of "how" your client wants to be able to do this. Craft supports dynamic user permissions creation so whatever your use case is I'm sure Craft will handle it with ease.


Update form entry using the Guest Entries plugin I am trying to create a form that anyone can submit regardless if they are logged in or not. I found the Pixel & Tonic Guest Entries plugin for this.
Now that I've installed and configured the plugin updating entries doesn't work. Whenever I want to update an entry a new one is created instead.

Here is the code I use:

<form method="post" accept-charset="UTF-8" id="loginForm">
    {{ getCsrfInput() }}

    <input type="hidden" name="entryId" value="88">

    <input type="hidden" name="action" value="guestEntries/saveEntry">
    <input type="hidden" name="redirect" value="entryform?hash={{ hash }}">
    <input type="hidden" name="sectionId" value="3">
    <input type="hidden" name="enabled" value="1">

    <input type="hidden" name="title" />

    Wat is de naam van uw organisatie/onderneming?
    <input type="text" id="text-naamSite" name="fields[naamSite]" />

    <button type="reset" style="float:left;">Reset</button>

    <button id="send-btn" type="submit">Opslaan</button>

</form>

Thanks!

In Craft 3 / Guest Entries 2, you could pull this off without hacking Guest Entries by writing  a module that listens to the beforeSaveEntry event, and sets the id on the entry.

use Craft;
use craft\elements\Entry;
use craft\guestentries\controllers\SaveController;
use craft\guestentries\events\SaveEvent;
use yii\base\Event;
use yii\web\BadRequestHttpException;

// ...

public function init()
{
    // ...

    Event::on(SaveController::class, SaveController::EVENT_BEFORE_SAVE_ENTRY, function(SaveEvent $event) {
        $request = Craft::$app->getRequest();

        // Get the entry being edited
        $entryId = $request->getValidatedBodyParam('entryId');
        $currentEntry = Entry::find()->id($entryId)->anyStatus()->one();

        if (!$currentEntry) {
            throw new BadRequestHttpException('Invalid entry ID: ' . $entryId);
        }

        // Populate the guest submission with the entry ID, UID, and content ID
        $event->entry->id = $currentEntry->id;
        $event->entry->uid = $currentEntry->uid;
        $event->entry->contentId = $currentEntry->contentId;
    });
}

Then in your form, add an entryId input set to the hashed entry ID.

<input type="hidden" name="entryId" value="{{ entry.id|hash }}">

It’s important that you hash the entry ID and use getValidatedBodyParam() instead of getBodyParam() so users can’t repurpose the form to edit any entry on your site.


Exception Running garbage collection When I run ./craft gc I get the following error:

Running garbage collection ... Exception 'yii\base\InvalidConfigException' with message 'Invalid section ID: 30'

The Section ID of 30 that it's referencing is one of the deleted

EDIT: Adding Stack Trace (Craft Pro 3.4.9):

Delete all trashed items? (yes|no) [no]:yes
Running garbage collection ... Exception 'yii\base\InvalidConfigException' with message 'Invalid section ID: 30'

in /srv/www/website.com/vendor/craftcms/cms/src/elements/Entry.php:836

Stack trace:
#0 /srv/www/website.com/vendor/craftcms/cms/src/elements/Entry.php(867): craft\elements\Entry->getSection()
#1 /srv/www/website.com/vendor/craftcms/cms/src/elements/Entry.php(812): craft\elements\Entry->getType()
#2 /srv/www/website.com/vendor/craftcms/cms/src/base/Element.php(2740): craft\elements\Entry->getFieldLayout()
#3 /srv/www/website.com/vendor/craftcms/cms/src/base/Element.php(2564): craft\base\Element->fieldLayoutFields()
#4 /srv/www/website.com/vendor/craftcms/cms/src/elements/Entry.php(1287): craft\base\Element->beforeDelete()
#5 /srv/www/website.com/vendor/craftcms/cms/src/services/Elements.php(1213): craft\elements\Entry->beforeDelete()
#6 /srv/www/website.com/vendor/craftcms/cms/src/services/Drafts.php(474): craft\services\Elements->deleteElement(Object(craft\elements\Entry), true)
#7 /srv/www/website.com/vendor/craftcms/cms/src/services/Gc.php(57): craft\services\Drafts->purgeUnsavedDrafts()
#8 /srv/www/website.com/vendor/craftcms/cms/src/console/controllers/GcController.php(56): craft\services\Gc->run(true)
#9 [internal function]: craft\console\controllers\GcController->actionRun()
#10 /srv/www/website.com/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)
#11 /srv/www/website.com/vendor/yiisoft/yii2/base/Controller.php(157): yii\base\InlineAction->runWithParams(Array)
#12 /srv/www/website.com/vendor/yiisoft/yii2/console/Controller.php(164): yii\base\Controller->runAction('', Array)
#13 /srv/www/website.com/vendor/craftcms/cms/src/console/Controller.php(187): yii\console\Controller->runAction('', Array)
#14 /srv/www/website.com/vendor/yiisoft/yii2/base/Module.php(528): craft\console\Controller->runAction('', Array)
#15 /srv/www/website.com/vendor/yiisoft/yii2/console/Application.php(180): yii\base\Module->runAction('gc', Array)
#16 /srv/www/website.com/vendor/craftcms/cms/src/console/Application.php(87): yii\console\Application->runAction('gc', Array)
#17 /srv/www/website.com/vendor/yiisoft/yii2/console/Application.php(147): craft\console\Application->runAction('gc', Array)
#18 /srv/www/website.com/vendor/yiisoft/yii2/base/Application.php(386): yii\console\Application->handleRequest(Object(craft\console\Request))
#19 /srv/www/website.com/craft(22): yii\base\Application->run()
#20 {main}

This will be fixed in Craft 3.4.11, per craftcms/cms#5820.


Does Craft enforce a maximum filesize for large files? A client we're working with has a requirement to upload one large file (about 320MB) every 2–3 months. Craft has been configured with a local asset source to handle this.

I'm trying to decide the best way to approach this: whether we upload this large file via SFTP for them when required, or if the client can do this through Craft in their own time.

This previous question provides some good pointers. I've increased the necessary settings, however when attempting to upload a test file (315MB), Craft displays an alert ‘The file “testfile.zip” could not be uploaded, because it exceeds the maximum upload size of 128.0 MB.’

I haven't seen any filesize limits of 128MB, so is this value hardwired into the file upload logic? To confirm that the changed settings do work, a test file of 100MB was uploaded fine.

The only thing Craft enforces is the maxUploadFileSize config setting, which by default is set to 16MB.  Outside of that, any limitations you run into will be environmental/server config related.


Showing just the child category titles of a parent I have a category group with parents each with 1 level of children.

On my category entry page I want to list JUST the children of the current category being viewed.

I'm sure it's simple but I can't figure what to put in my category template?

Many thanks in advance.

Martin

You should actually already have a variable named "category"
pre-assigned by Craft, if you've set up your categories to have URLs in the category settings.

So this simplified code is probably all you need.

{% set subCategories = craft.categories.descendantOf(category) %}

{% if subCategories|length %}

        {% for category in subCategories %}

{{ category.title }}

        {% endfor %}

{% else %}
    {% exit 404 %}
{% endif %}

To have different template code for your sub-category pages you're linking to, I would
put the code above in a partial _partials/mainCategory and include it with the include function.

{% if category.level == 1 %}
    {% include '_partials/mainCategory' %}
{% else %}
    {% include '_partials/subCategory' %}
{% endif %}


Get future multi-day event entries with custom date field I have an event section with custom fields for eventDate and eventEndDate.

I'm listing upcoming events in my template using:

{% for event in craft.entries.section('events').eventDate('>='~now).limit(3).order('eventDate ASC') %}

This works fine for single day events. But multi-day events disappear after the first day, when I want them to be listed until the event is over. I can't do .eventEndDate('>='~now) because the Event End Date field is left blank for single day events. Is there a way to add an OR to my query to get events with future eventDates OR events with future eventEndDates?

I think the simplest solution would be to make the eventEndDate field required even for single day events. Then you could do something like this:

{% for event in craft.entries({
  section:'events',
  eventEndDate:'>= '~now,
  limit: 3,
  order:'startDate'
}) %}

Given you have 3 events:

Starts Monday, ends Friday.
Starts Wednesday, ends Thursday.
Starts Thursday, ends Thursday.

On Wednesday, you'll still see those events in order (1,2,3).


Multilanguage without url segments Is it possible to use craft multilanguage capabilities without locale url segments?

Example:

German: domain.com/wetter

English: domain.com/weather

I know this is pretty dangerous. If one forgets to translate the url everything will fall apart. But I wonder if it would be possible theoretically :)

You can pull data from entries by specifying a locale.

{% craft.entries.section('yourSection').locale('en_us') %}

Determine the locale you need by the custom segment.

{% set locales = {  'wetter': 'de', 'weather' : 'en_us' } %}
{% set segment = craft.request.firstSegment() %}
{% set entries = craft.entries.section('yourSection').locale(locales[segment]) %}

The big issue you will have is translating strings for each language.  If you are not at domain.com/de, I believe, you won't receive the benefits of the translation files in Craft/Translations. You will need to build in your own mechanism to translate strings depending on the segment.


Commerce 1 get customer from user model In PHP, is it possible to grab the customer model from a user model?

EDIT:
I just noticed that it is possible to attach a customer info field to the user.  How do we achieve this?

You shouldn't really need to do that, you're just adding custom fields to the user when those can be fetched easilly.
A customer will always be a user, but a user might not be a customer.

If you intend to get the customer details from a plugin (with PHP) you can just get the customer details (if exist) from the user, by using the Commerce_CustomersService

code example would be

$customer = craft()->commerce_customers->getCustomerByUserId($user->id);

this will either return the customer model or null (if a customer is not created against the user).


What is the best approach for multi categories filtering I need a solution for a good filter approach in Craft.

I used 3 Categories related to an entry (Project). The 3 Categories are
(Type / State / Location)
How do I have to set up the routes for the multiple slugs?

Example:

example.com/project/office/finished/germany.

I already fetch projects with AJAX for one category, but it should also work with a combination of categories.

You could leave the Category URI Format blank in your settings and set an advanced route in config/routes.php like so:

'projects/<type:{slug}>/<state:{slug}>/<location:{slug}>' => ['template' => 'projects/index'],

Which would make {{ type }}, {{ state }} and {{ location }} available as variables in your template.


Basic ajax - how to? I am new to Craft. I have done some ajax in the distant past. I have searched this forum and see lots of issues with ajax but it seems that there are a lot of different approaches. Craft docs have very little on Ajax.

I am wondering if there is a clear tutorial on doing ajax within craft. I have an address field set up and would like to click a button to retrieve all entries in a certain state and replace currently displayed data with the new data.

There is no real difference between a "normal" ajax request and an ajax request in Craft. You just leave the url blank, and insert an action parameter for your route. Craft 3 uses snake-case routes instead of camelCase. So when you want to access your plugin you would do.

action = "plugin-handle/controller-name/function-name

I full example as a CP request is

var data = {
    action: 'form-builder/setting/get-settings-for-site',
    siteId: siteId
};
// include csrf token
var tokenName = Craft.csrfTokenName;
data[tokenName] = Craft.csrfTokenValue;
$.ajax({
    type: "post",
    url: '',
    data: data,
    success: function (response) {
            ...
    },
    error: function (XMLHttpRequest, textStatus) {
        console.log("Status: " + textStatus);
    }
});

This would access my Form-builder plugin. The controller is SettingsController and the action actionGetSettingsForSite.


No more than 10 blocks in globally used Matrix fields get saved When saving a globally used Matrix field, no more than 10 blocks (of the same type) get saved. The Matrix field has no max. Any ideas?

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

Matrix field input error from within the control panel


Template error: A template that extends another one cannot have a body How am I able to use bootstrap in Craft? I created a folder in a templates directory named _layouts and inside of that I have base.html

<!DOCTYPE html>

<meta charset="UTF-8">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">

and this is where i want to include the bootstrap (contact.html)

{% extends "_layouts/base" %}
{% macro errorList(errors) %}
{% if errors %}

{% for error in errors %}

{{ error }}

        {% endfor %}

{% endif %}
{% endmacro %}
{% from _self import errorList %}

<form method="post" action="" accept-charset="UTF-8">
{{ getCsrfInput() }}
<input type="hidden" name="action" value="contactForm/sendMessage">
<input type="hidden" name="redirect" value="../public/index.php/contact.html">

Your Name

<input id="fromName" type="text" name="fromName" value="{% if message is defined %}{{ message.fromName }}{% endif %}">
{{ message is defined and message ? errorList(message.getErrors('fromName')) }}

Your Email

<input id="fromEmail" type="email" name="fromEmail" value="{% if message is defined %}{{ message.fromEmail }}{% endif %}">
{{ message is defined and message ? errorList(message.getErrors('fromEmail')) }}

Message

<textarea rows="10" cols="40" id="message" name="message">{% if message is defined %}{{ message.message }}{% endif %}</textarea>
{{ message is defined and message ? errorList(message.getErrors('message')) }}

<input type="submit" class = "btn btn-submit" value="Send">
</form>

I'm having an error => "A template that extends another one cannot have a body."

In your base.html you need to include a block section, so something like this:

<!DOCTYPE html>

<meta charset="UTF-8">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">

{% block content %}{% endblock %}

Then in your contact.html you need to wrap your main markup in the same block, like this:

{% extends "_layouts/base" %}
{% macro errorList(errors) %}
{% if errors %}

{% for error in errors %}

{{ error }}

        {% endfor %}

{% endif %}
{% endmacro %}
{% from _self import errorList %}

{% block content %}
<form method="post" action="" accept-charset="UTF-8">
{{ getCsrfInput() }}
<input type="hidden" name="action" value="contactForm/sendMessage">
<input type="hidden" name="redirect" value="../public/index.php/contact.html">

Your Name

<input id="fromName" type="text" name="fromName" value="{% if message is defined %}{{ message.fromName }}{% endif %}">
{{ message is defined and message ? errorList(message.getErrors('fromName')) }}

Your Email

<input id="fromEmail" type="email" name="fromEmail" value="{% if message is defined %}{{ message.fromEmail }}{% endif %}">
{{ message is defined and message ? errorList(message.getErrors('fromEmail')) }}

Message

<textarea rows="10" cols="40" id="message" name="message">{% if message is defined %}{{ message.message }}{% endif %}</textarea>
{{ message is defined and message ? errorList(message.getErrors('message')) }}

<input type="submit" class = "btn btn-submit" value="Send">
</form>
{% endblock %}

So you are basically saying create an area called content in your base.html and you want to fill this area with the markup wrapped in the content block inside your contact.html. You can call the block whatever you want, so here we've called it content, it doesn't have to be that, but it seems a fairly logical name for it.

You can have more than one block in your base.html, if you want. For instance you could have a header, content and footer blocks. All you need to remember is to use the same names inside the template file you are extending the base.html from.

More information can be found in the Twig documentation


Programatically Adding Fields to a Layout I am looking to add a field (or perhaps a group?) to the userlayout via a database migration.  I've looked over the docs, and found Is it possible to add a custom field to User model from a plugin? but that isn't exactly what I want.  I do not wish to delete the layout and then recreate it.  I just want to add a new field to it.

I was hoping to be able to use the getFields() and setFields() methods directly on the FieldLayoutModel but thus far no dice.  Is there a better way to do with, with a service or something?

Right now I am:

Creating a new FieldModel, populating it and saving it.
Finding the fieldLayout I want through craft()->fields->getLayoutByType()
Calling getFields() on it and saving the result to a variable
Popping my saved field onto the end of that array
Calling setFields on the fieldLayout with that new updated array

But it's not functioning.

Thank you for your time!

While I am adding them from a plugin, I ran into a similar issue as you, and like you, I didn't like the "recreate the layout from scratch" method the linked answer used. I know this question is old, but it seems the most apt place to put my solution to this issue and contribute to more code samples.

After some experimenting, I got a solution that works (whether it's "the Craft way," I'm not totally sure, and I'm sure some of it could be cleaned up, but it's not like there's a lot of documentation on that front, as we've both found).

This code creates the fields, a field group, and a tab, then adds the tab and fields to the User Layout:

    // Create the field group
    $groupModel = new FieldGroupModel();
    $groupModel->name = 'CustomGroupName';
    craft()->fields->saveGroup($groupModel);

    // I haven't yet found a way to get the group ID without looping through all of the groups. saveGroup() returns a boolean and doesn't appear to update the id attribute of the original model instance.
    $groups = craft()->fields->getAllGroups();
    foreach($groups as $group) {
        if($group->name != 'CustomGroupName') {
            continue;
        }
        $groupModel = $group;
    }

    // Create the tab
    $tabModel = new FieldLayoutTabModel();
    // Get the desired layout (in this case, the User layout) and use the tab's setLayout to link the two
    $layout = craft()->fields->getLayoutByType(ElementType::User);
    $tabModel->setLayout($layout);
    $tabModel->name = 'CustomTabName';

    // Create the fields. I have a protected class member that contains the fields in a 'fieldName' => 'FieldName' format.
    foreach($this->fields as $field => $name) {
        $fieldModel = new FieldModel();
        $fieldModel->groupId = $groupModel->id;
        $fieldModel->name = Craft::t($name);
        $fieldModel->handle = $field;
        $fieldModel->translatable = false;
        $fieldModel->type = 'PlainText';

        craft()->fields->saveField($fieldModel);
    }

    // Get all of the group's fields. This could also be done by saving an array of the fields in the loop above, but this seems a bit cleaner to me, and since we already have the group object, saves us an object/variable declaration.
    $fields = $groupModel->getFields();

    // Set the tab's fields. This gives us a custom grouping in the layout editor.
    $tabModel->setFields($fields);

    // Get the existing tabs (and, by extension, fields), since we don't want to nuke the layout, just add to it. I couldn't find any sort of "addTab" type function, so this is how we have to do it.
    $layoutTabs = $layout->getTabs();

    // getTabs() returns an array, so simply add our new tab to the array.
    $layoutTabs[] = $tabModel;

    // Now, set the tabs back in the layout.
    $layout->setTabs($layoutTabs);

The reversal is exactly that--a reversal:

    $group = null;

    // Delete the fields
    foreach($this->fields as $field => $name) {
        $fieldModel = craft()->fields->getFieldByHandle($field);
        if($fieldModel) {
            // Grab the group from one of the fields. Presumably (in my case), they're all in the same group. This could be refined for a less ham-fisted approach. Unfortunately, it's either this, or doing the loop-through-all-groups method we did in the create section, that I've found.
            $group = $fieldModel->group;
            craft()->fields->deleteField($fieldModel);
        }
    }

    // Delete the field group
    if($group) {
        $groupModel = craft()->fields->getGroupById($group->id);
        // I made sure it was empty, since I don't want to delete the group if more fields were added.
        if($groupModel && empty($groupModel->getFields())) {
            craft()->fields->deleteGroupById($groupModel->id);
        }
    }

    // Delete the layout tab
    // Get the layout...
    $layout = craft()->fields->getLayoutByType(ElementType::User);

    // Get the tabs...
    $tabs = $layout->tabs;

    // Find and delete the tab we want, in the same fashion, except now we're unsetting the array instead of setting it.
    foreach($tabs as $index => $tab) {
        if($tab->name != "CustomTabName") {
            continue;
        }
        unset($tabs[$index]);
    }
    $layout->setTabs($tabs);


How to export order data for reporting I'm wondering what the best way to export order data from Craft Commerce would be for the client's order and revenue reporting.

Ideally they'd like to be able to export a report after filtering by date on the Commerce > Orders screen, which I think would also be a great feature request.

For now it looks like Sprout Export might be the only/best option. I'm wondering if this has come up for anyone who might have other suggestions?

You could also export the data to a CSV with your own SQL commands. These commands could be created in a way to take parameter that your client could set through the CP.

You'd need to create a plugin with a controller method that runs your SQL query. Take a look at the docs for more info on querying the database.


How to Auto-Generate a Craft Commerce Product Title How can I auto-generate the product titles in Craft Commerce? I'd like to auto-generate it from the post date and a custom field value. I can see how to auto-generate the SKU, but can't see how to do this for the product titles in the same way (like you can do for normal Craft entry titles).

I asked about this in the Craft Commerce Slack but didn't get a response, so just asking the question here instead. Thanks in advance for any help or possible workarounds.

You can generate the Variant titles automatically, but not for top level Product Types:


Checking if user authored an entry in another channel while in loop, N+1 problem I have 2 channels set up: Channel A and Channel B.  I also have public registration so users can log in and fill out two forms (Form A and Form B), each form creating an entry in their respective channel with the user as the author.  The user can only create an entry in Channel B if they already have an entry in Channel A.

To get all the users who have an entry in Channel A but not in Channel B, I tried writing something like this in my class:

public function getUsersWithoutChannelBEntry()
{
    $channel_A_entries = Entry::find()
        ->sectionId(1)
        ->all();

    $userIds = [];
    foreach ($channel_A_entries as $entry) {

        $channel_B_entry_exists = Entry::find()
            ->sectionId(2)
            ->authorId($entry->authorId)
            ->exists();

        if (! $channel_B_entry_exists) {
            $userIds[] = $entry->authorId;
        }

    }

    return User::find()
        ->id($userIds)
        ->all();
}

However, this creates an N+1 problem. I have roughly 200 users, so potentially 200 entries in either channel, and thus a lot of db queries and a substantially larger load time.

As an alternative approach, I've also tried looping through Channel A, adding each author ID into an array (Array A), then doing the same with Channel B making Array B.  Then I use array_diff() to extract the author IDs that are in Array A but not in Array B.  However, this still causes a bit of long load time.

I've looked into eager loading, but that seems to only apply to related fields.

Is there a more efficient way to get all users who authored a Channel A entry but not Channel B entry?

There's one bit missing in the constrains you explain above, do users end up with 1 entry only per channel so a total of 2 posts max?

If so, we know that:

each users can have a max of 2 posts
a user cannot post in B is they haven't completed their post in A

So assuming this first condition is also true (2 entries/user) you could just loop through users post count looking for those with less than 2 posts and they would automatically be the users who haven't posted in B..? Just a shot in the dark :)


What is the best way to number form entries in Freeform? I am trying to number Form submissions using an incrementing number that would display in Email Notifications.

Increment Plugin Field produces an incrementing number and would be ideal but it doesn't work because Freeform uses its own field type set.

What would be the best way to generate and associate a unique number per form entry that could then be displayed?

If you want to do this without creating a plugin, a "cheat" way would be to use the entry id of the submitted form - that would guarantee that you have a unique number and, assuming they are being saved to the same section, they would be in sequence.


Previous and next entries nav – within a categeory I'm not sure what I've done, I had this working at the top of my entry.html template:

{% set params = craft.entries.section('ourWork').relatedTo(category) %}

{% set prevEntry = entry.getPrev(params) %}
{% set nextEntry = entry.getNext(params) %}

{% if prevEntry %}Previous{% endif %}
{% if nextEntry %}Next{% endif %}

For some reason I just get:
Variable "category" does not exist

The section name is correct and this does have a category field assigned.

my index template category part is:

{# Projects
---------------------------------------------------------------------------#}

  {#
  Display catgeory nav 'ourWork'
  #}
    {% nav category in craft.categories.group('ourWork').level(1) %}

          {#
{{ category.WorkCategoryDescription }}
 #}

 {{ category.title }}

    {% endnav %}

When you are within your nav tag context, category definitely exists, even if you're using include for the first snippet you posted. If you're talking about the automatically pre-assigned variable for a single category's page, make sure the category group settings are still correct and that you are requesting the right URLs.


How to sort entries by their descendant count? I want to sort (and paginate) entries from a structure section based on the number of descendants. This is the effective criteria I want to query:

craft.entries.section('myStructure').level(1).order('descendants desc')

Since getDescendants.count() is not a number stored against each entry in the database (AFAIK), how does one go about getting this result?

You could use a Preparse field to calculate and store that value.

The only downside is, it'll only do that calculation when you save the parent entry. So if you add another descendant, you'd have to go back and re-save the parent entry to re-calculate the value.

  Pro tip: You can go to Settings > Sections and re-save the section you are working with. This will automatically trigger a re-save of every single entry in that section.


Email template variables not rendering from plugin I am loading an email template for custom registration via a plugin.
I reset the template path and load my template like this:

    $oldPath = craft()->path->getTemplatesPath();
    $newPath = craft()->path->getPluginsPath().'businesslogic/templates';
    craft()->path->setTemplatesPath($newPath);
    $bodyhtml = craft()->templates->render('emailreg.html', array(
        'user' => $user
    ));

In my html template ( an evil abomination of tables etc ) I am accessing the user variable {{user.firstname}} just fine. But the other variable $user->mycustomfield will not render - even though I can send it in the subject line, e.g.,

$email->subject = 'New User Registration: ' . $user->firstName . ' ' . $user->registrationNumber;

So whats up here?

The above template path code works fine. I was just looking for a user variable that hadn't yet been set


404 error on Craft homepage I'm having some trouble on a fresh install of Craft. I've uploaded all the files to my server and moved index.php (etc) out of the public folder and into the root directory.

I've also changed index.php's $craftPath to this:

$craftPath = './craft';

But I'm still getting a 404 error on the homepage. I've set permissions on the folders, but still nothing.

My file structure looks like this:

Any suggestions..?

Change this:

$craftPath = './craft';

to this:

$craftPath = 'craft';