Updating index tables' sortable attributes on AJAX I'm currently writing a plugin enabling users to easily add custom fields to index tables, using the native field layout designer.

My current goal is to have any datetime, boolean, string or number fields added to a source's FieldLayout, also automatically be added to the relevant index table's sortable attributes. Obviously, I've met a stumbling block with modifyEntrySortableAttributes.

Everything works great on initial pageload (I've found a way to work around the fact that modifyEntrySortableAttributes doesn't have a clue about the source).

My problem is that when navigating between sources, Craft uses AJAX, and the sortable attributes are not updated. Through logging I've confirmed that the modifyEntrySortableAttributes hook does run (see footnote!) every time the source changes, and I also know that my fix for identifying the current source also works (i.e. the plugin fetches the correct FieldLayout whenever the source changes).

So – as far as I can tell – I'm basically stuck with a CP frontend issue, which is that the ".sortmenubtn" button doesn't refresh its ".menu" container contents when the source changes. I'd be happy to refresh the menu myself through some JS in my plugin, but I've looked at the AJAX calls and can't spot any data related to the sortable attributes.

My backup solution is to create my own AJAX service to fetch the updated attributes, but it would be really cool to do this with a minimal amount of hacks (the plugin already contains a few...).

Would greatly appreciate any ideas for solving this!

Footnote: It's actually weird that the hook runs when the source changes, as this directly contradicts the following statement in the docs:

Note that this method will only get called once for the entire index; not each time that a new source is selected.

The modifyEntrySortableAttributes technically gets called each time you load new elements on the index page, just so that the controller can confirm that the posted order attribute is valid. But the only time that your plugin can actually affect what is shown in the dropdown is the first time it’s called, on page load.

Maybe a better way to go about this would be to have your plugin return all the available options up front, and then simply hide/show them with JavaScript when the source changes.


Example of Craft 3.0 plugin - querying an existing table Learning how to create plugins. I want to do a select query in an existing table in the Craft database, build navigation HTML and then return that HTML using a variable. I can see how to set up my own variable using the *Variable.php file. In the docs I don't see how querying database tables is done with any of the sections of the plugin found here.

I am guessing that I would use a class in the Craft classes?

If so then...

Do I put my logic for querying the table in my method to return the variable value, in my primary plugin class or somewhere else?

Which classes would I use?

A great place to start with this is over on https://pluginfactory.io/.

Select "Craft CMS Plugin Version 3.x" and check any plugin components you'd like to include, and it will build out the plugin scaffolding for you with ample comments and some examples.

For accessing database content, Craft heavily relies on the framework it uses, Yii 2.  The "Working with Databases" docs are a good place to start: https://www.yiiframework.com/doc/guide/2.0/en/start-databases#working-with-databases

It will go over how to retrieve data using Active Record (Craft's AR classes) and Query Builder for direct database access.

You can do that data access from your plugin's Variable class, but a more common pattern is for the Variable class to have a wrapper method that calls a Service class method that returns the value to the Variable, then back to the template.

You can see Craft's Service classes here: https://github.com/craftcms/cms/tree/develop/src/services

And in case it's not obvious yet, the Craft source code itself is a great place to look for examples of how to do things in your plugin.


Element API: Is it possible to ignore/skip an Entry? I would like to exclude some of my entries, via my own validation inside the Transformer, from the api output.

Is there a possibility to move on to the next Entry without outputing anything? Right now im just returning an empty array, but i think it would be cleaner to return nothing.

Couldn't you modify the criteria to exclude that entry ?

id => "not X"


Can't get rid of 404 error I set up my first Craft site on my shared hosting and I can't get it to work for the life of me. Whatever I do, I run into a 404 error. .htaccess is there and named correctly, craft folder is one level up as it should be.
What I noticed is that it briefly works after setting the correct permissions on the craft files and folders. A couple of clicks later the permissions seem to reset again back to 755.
I haven't had this problem with my hosting before, so I am unsure if this is a craft problem? Or if the permissions even are the cause?

Edit: It doesn't appear to be a permission problem after all. Filezilla shows 755, although the permissions are set to 744. So now I'm at a total loss what the issue could be.... I can't even complete the installation because it stops working beforehand.
Tried several times more and got it installed. Just before it goes wrong again, I can see that it doesn't load the site properly, e.g. the login screen looks weird. Has anyone seen this before?

Do you happen to be on Dreamhost? I had a site there recently where they changed my permissions "for my own good".


Collecting total charge value where custom field is X I'm using Charge to collect donations toward individual projects for a charity.

On the frontend, I want to display how much has been raised for an individual project.

To get a list of charges for a project, I'm doing

{% set charges = craft.charge.charges({
      search : { query : 'projectDonateTo:' ~ entry.id }}
   )%}

{% for charge in charges %}
    {{ charge.amount }}
{% endfor %}

which obviously loops through all charges but I can't fathom how to total these together.

Any ideas?

Can you not do:

{% set total = 0 %}

{% for charge in charges %}
    {% set total = total + charge.amount %}
{% endfor %}

{{ total|number_format(2, '.', ',') }}

?


Import existing data in Matrix fields We have an existing CMS and I'm just learning how to use CraftCMS so that I port the data from SQL Server to MySQL database. I went through a few videos on how to create a basic site so I kinda understand the system.

I have used a couple of plugins to import the data and one of them being this:
https://github.com/boboldehampsink/import

This plugin doesn't export existing data from MySQL data from Matrix field (using sample data). I wanted to see how the data is stored so I can create a similar format. But unfortunately the Matrix field comes back empty. I am not sure how to create and insert data in CraftCMS for this specific field. I will also at some point need to retrieve this data so I would like to know how the insert/select works on these fields.

Thanks in advance.

I'm not 100% clear on exactly what you're looking for, but I'll just throw this out there.  Matrix content is saved in their own tables (table names are dynamically generated on a per-field basis) as opposed to most other fields, which have their content saved in the craft_content table.

You can look in MatrixService for methods needed for managing Matrix fields.


Upload images bigger than 1MB not working I am trying to upload jpg assets to Craft. As long as the files are smaller than approx. 1MB it's working, even in bulk upload. As soon as there's a file bigger than 1MB Craft gets stuck like this:

You can see on the image that files smaller as the 1MB have been uploaded successfully.

The file doesn't show up in the assets directory on the server file system.

I enabled devMode to take a look at the logs but no error level log entry shows up that is related to the upload request. JS console shows no errors as well.

So my question is: What is going on? How can I fix this so I can upload files within the limits I specified in php.ini?

Some info:
I am using Laravel Forge + DO
Web server: nginx/1.11.5
PHP Ver: 7.1.0
post_max_size = 14M
upload_max_filesize = 12M

PS: I say approx. 1MB because I was able to test with files that are roughly below/above 1MB file size.

Update
I noticed Imagemagick was not installed. After installation: no difference. I even disabled GD: no difference.

Nginx's setting client_max_body_size was set to its default value of 1M because it was not specified after provisioning the DO server with Laravel Forge. Weird thing is just that the user doesn't get any response.

Solution: Set client_max_body_size to something higher or 0 in your Nginx config file.


How can I repopulate my dropdown on a front-end form? I am allowing guest registrations - everything is working fine. I am hung up on getting my drop down menu to repopulate/hold its value if there are any errors while submitting.

I have a states field in the CP which is a dropdown.

Within my twig template I have this:

{#
 # Get all of the states.
 #
 #}
 {% set states = craft.fields.getFieldByHandle('states').getFieldType.options %}
 {% if states|length %}

         State
         <select id="state" name="fields[address][state]" class="form-control">
             <option value="">Select</option>
             {% for option in states %}
                 <option val="{{ option.value }}"
                     {%- if account is defined and option.value in account.address.state %} selected {% endif -%}>
                     {{ option.label }}
                 </option>
             {% endfor %}
         </select>

 {% endif %}
 {% if account is defined %}
     {{ errorList(account.getErrors('state')) }}
 {% endif %}

I am using SmartMap to capture my address hence the name of fields[address][state].

Just doing this:

{%- if account is defined %} selected {% endif -%}

Gets the last option selected, so I know account is getting defined, its something in my and part.

All of my data is getting captured correctly, I just can't see past the obvious here I guess.

SOLUTION

Thanks to @carlcs I found that the value of my state field was getting saved as the label. I'm not sure if thats a function of SmartMap, or something else I might have done.

Here is what I ended up with:

...
<option value="">Select</option>
{% for option in states %}
    <option val="{{ option.value }}"
        {%- if account is defined and option.label in account.address.state %} selected {% endif -%}>
        {{ option.label }}
    </option>
{% endfor %}

Alternatively, here is how I was able to repopulate a "normal" drop-down (not address/SmartMap):

...
<option value="">Select</option>
{% for option in myField %}
    <option val="{{ option.value }}"
    {%- if account is defined and option.label in account.myField.label %} selected {% endif -%}>
       {{ option.label }}
    </option>
{% endfor %}

I think it's also worth noting that by setting myField as a required field in the CP, I needed to hard-code the <option value="">Select</option> in the template rather than putting it as a field value. When I had it as a field value, I (think) Craft was accepting that as a selected value and I was not getting the error message.

You could dump the account variable to see why the conditional doesn't work as you're expecting. I don't really see the reason to why you'd need the in containment test, but I'd just use dump for debugging.


How do you set a users group? I am using the UserModel to create a user, and then injecting that into the User API service as is instructed in the documentation. The only thing I am not seeing is how to set the group.

I looked in the Model class and there is no method for setting the group and it's not part of the defineAttributes() method.

In the documentation there is no method to set group, just read only the groups: https://craftcms.com/docs/templating/usermodel#getGroups

Nothing here about it: https://craftcms.com/classreference/services/UsersService

Here is what I am doing to save user.

$user = new UserModel;

$user->username = 'username';
$user->email = 'yourmom@email.com';
// $user->groupID = "group";
$user->firstName = 'first name';
$user->lastName = 'last name';
$user->getContent()->setAttributes([ 'usersAddress' => 'Your face' ]);

craft()->users->saveUser($user);

Am I missing something obvious?

It's not documented, but UserGroupsService has a method assignUserToGroups($userId, int|array $groupIds). You'll have to save your user first, but once you have a user id, I believe you can just use that with something like this:

// Original code
$user = new UserModel;

$user->username = 'username';
$user->email = 'user@email.com';
$user->firstName = 'first name';
$user->lastName = 'last name';
$user->getContent()->setAttributes([ 'usersAddress' => 'Your face' ]);

craft()->users->saveUser($user);

// Add to single group
craft()->userGroups->assignUserToGroups($user->id, $groupId);

// OR, add to multiple groups
craft()->userGroups->assignUserToGroups($user->id, [$groupIdOne, $groupIdTwo]);


Eager load elements from Solspace Plugin I'm using Solspace plugin. I've related each event to a show. I want to get the event with its related show (Entry type).

I'v tried (Among others):

$calendarEvent = Event::find([
            'id' => $id,
        ])->with(['shows'])->all();

But, that gives me the event(✅) but in the show, I don't get the entry per se but I get like an unexecuted query. Looks something like:

        {
            "id": 22,
            "url": null,
            "title": "The Way You Sound",
            "slug": "the-way-you-sound",
            "start": "2018-12-14T18:00:00+00:00",
            "end": "2018-12-14T20:00:00+00:00",
            "allDay": false,
            "multiDay": false,
            "repeats": true,
            "readableRepeatRule": "Weekly on Friday, starting from Dec 14, 2018, forever",
            "calendar": {
                "id": 1,
                "name": "Shows",
                "handle": "default"
            },
            "site": {
                "id": "1",
                "name": "English",
                "handle": "default",
                "language": "en-US"
            },
            "editable": false,
            "enabled": true,
            "backgroundColor": "#C0BE11",
            "borderColor": "#868900",
            "textColor": "black",

    ======> "show": {
                "editable": false,
                "orderBy": {
                    "relations.sortOrder": 4
                },
                  ...
                "join": [
                    [
                        "INNER JOIN",
                        "{{%relations}} relations", [
                            "and",
                            "[[relations.targetId]] = [[elements.id]]",
                            {
                                "relations.sourceId": "22",
                                "relations.fieldId": "42"
                            },
                            [
                                "or",
                                {
                                    "relations.sourceSiteId": null
                                },
                                {
                                    "relations.sourceSiteId": "1"
                                }
                            ]
                        ]
                    ]
                ],
                "having": null,
                "union": null
            }
        }

Currently Calendar does not support eager loading, but it's much more likely the Craft 3 version will in the future, as we refactored a lot of code and tried to somewhat "normalize" the code to work more natively with Craft than we did in Craft 2.


Use Matrix field to output specific html I am quite new to this so, please be patient. I am wanting to output the following html:

Helping you to establish your outdoor brand in the world of retail and e-commerce

One of our top brands

We also have a design service

Visit us at our new site

I have a Matrix field set up as follows:

Field handle: homepageSlider
Block type handle: homeSlider
Field name handles: mainImage, whiteLogo, imageText and mainImage.

mainImage has a field type of 'Assets'
whiteLogo has a field type of 'Lightswitch'
imageText has a field type of 'Plain Text'
mainImageLink has a field type of 'Linkit' (from a plugin).

So far, I have written:

{% block content %}

{% includeJsFile "/js/jquery.jcarousel.min.js" %}
{% includeJsFile "/js/jcarousel.responsive.js" %}

{% for block in entry.homepageSlider %}

{% if block.type == "mainImage" %}
{% set image = block.mainImage %}

{% endif %}

{% if block.type == "whiteLogo" %}

{% set imagetwo = block.mainImage %}

{% endif %}

{% if block.type == "imageText" %}

{{ block.imageText }}

{% endif %}

{% if block.type == "mainImageLink" %}
{% set yourLink = entry.mainImageLink %}
{{ yourLink.link|raw }}
{% endif %}

{% endfor %}

This outputs html as I want, BUT, is empty between
 and
. I have tried following this post, but am so far getting nowhere.

Any help that anyone can offer would be most appreciated.

With kind regards,

Mark

In your code block.type is the matrix block type, ie homeSlider.

There's alot going on in your code that I'm not sure is intended or not, but let's say you had the fields mainImage and imageText as required fields in there, and have an optional whiteLogo (not sure where that link's suppose to go, it's not in your original html). Try something like this:

{% includeJsFile "/js/jquery.jcarousel.min.js" %}
{% includeJsFile "/js/jcarousel.responsive.js" %}

  {% for block in entry.homepageSlider %}

    {% set image = block.mainImage.first() %}

    {% if block.whiteLogo %}

    {% endif %}

{{ block.imageText }}

  {% endfor %}

So, inside you're for loop, the fields you've created are accessible by block.fieldHandle. If you want to make a conditional based on if a field has a value or not, that is done in different ways depending on the type of field. So you'd do {% if block.lightswitchField %} if it's a lightswitch, {% if block.assetField | length %} if it's an assets field, or {% if block.textField != '' %} if it's a text field.

Hope that helps you in the right direction.


How to redirect requests from root to subfolder (if they exist)? I am in the process of migrating a website from Wordpress to Craft and need to redirect the blog entries. In the existing site, the entries are in the root of the site, eg:

example.com/this-is-a-blog-post

In the Craft site, the post will be under a /blog subdirectory like so:

example.com/blog/this-is-a-blog-post

Assuming the slugs are the same, how would I go about creating 301 redirects for all existing posts?

There's a plugin to set up custom routes: Reroute by Trevor Davis, but this would require you to set them all up manually. If there's lots and lots of blog entries, you would probably want to avoid this.

As you said your slugs do match, you could just set up an ElementCriteriaModel with the slug parameter set to the relevant URI segment and see if there's an entry for that; and if that's the case redirect to that entry.

You would do this with this simple PHP code form a custom plugin. Set up a plugin and place the snippet in the init() method of your primary plugin class:

if (craft()->request->isSiteRequest())
{
    $inRoot = ((craft()->request->getSegment(2) === null) && (craft()->request->getSegment(1) !== null));

    if ($inRoot)
    {
        $criteria = craft()->elements->getCriteria(ElementType::Entry);
        $criteria->section = 'blog';
        $criteria->slug = craft()->request->getSegment(1);
        $entry = $criteria->first();

        if ($entry)
        {
            craft()->request->redirect($entry->url, true, 301);
        }
    }
}


How can I have translations for my subdomain I setup Craft with one domain-1, now domain-1 has sites domain-1Global and domain-1NL. On this domain, the translations work perfectly.

But now I added a second domain, domain-2 with the sites domain-2Global and domain-2NL. When I access the base url from the domain-2NL I get the template for the homepage of domain-1NL.

I tried removing the define('CRAFT_SITE', 'domain-1'); in the web folder, this worked for a while but ultimately failed. Does anybody know a different solution?

I'd double-check your index.php files for all domains and make sure they're all using the correct handle in the define('CRAFT_SITE') code. Sometimes I copy/paste files between sites and forget to update the site-specific variables.

I'd also make sure the Base URL for each site is correct in the settings.

Also make sure the section your homepage uses isn't set to the wrong propagation method.


Blank screen on install I have everything loaded, my path to "craft" is correct and the database credentials are correct but when I go to domain.com/admin, it pulls up a blank screen. Not a 404, server error, of the "oops" screen. It's just blank.

My folder permissions are also correct. Anyone else had this? I checked the server requirements and those are also within the correct parameters.

Jeremy

I simply deleted everything and re-uploaded and it worked. It must have been a corrupt upload because I'm up and running now. Thanks!


Craft database and Github - using multiple computers. Issue I have Craft set up and am using it for the first time. It seems to be ok. I am using git to back up my project to Github and push/pull it between computers as I partly work on my desktop (Windows) but also work on my laptop (Mac).

My issue is that when I pull to another PC often Craft database stuff is not the same. I lose changes made e.g. images that I’ve uploaded (even though they are in the actual Craft Image folder in my folders) or Matrix changes.
I didn’t realise this was happening and at first assumed my images weren’t updated because I’d forgotten to push to git before making changes on my laptop but when I went to pull my laptop changes to my Desktop last night and then tried accessing my Craft website through MAMP I got this error :

Craft\MatrixBlockModel and its behaviors do not have a method or closure named "myBlockSummary".

"myBlockSummary" is a matrix thing I added last night on my laptop. My sass and html and image files are moving correctly with git which is why Craft is confused(?), looking for something on the database (myBlockSummary) which I suppose isn’t there. The website works on the laptop that I pulled it from.

How can I easily continue using git and going between computers but have the database be included also?

This information on using Craft with git has not helped me really:
https://craftcms.com/help/craft-storage-gitignore
“So unless you have a way to keep the databases in sync between servers, there’s not a whole lot of point to sharing these files.”
Are they saying this is not possible?

Thank you for any help.

It's a good practice to designate one instance on one computer (or server) as the "canonical" instance. You can make all database changes there, adding fields, etc. It's easy to download that database via the Backup Database tool in the admin panel. You can then import that dump file into databases on other machines as needed with a tool like SequelPro (Mac).

Some prefer to include an updated database dump file in the git repo every time a change is made but that can get pretty tricky.


Painfully slow Feed Me import of User accounts I'm aware of this thread on Feed Me slow performance, but I'm raising it as a separate thread in case there is anything particular about my circumstance that is pertinent.

I'm running Craft 3.4.18 and trying to import a large number of users (about 1,500) into a specific user group using Feed Me:

I'm using .csv sources on the local file system above web root
I'm importing:

Username (as email address string)
Email
First name
Last name
Shared password
User group string

I'm batching imports in 500s but because things are so slow will now try smaller batches
I have read and attended to the performance aspects of the Feed Me troubleshooting docs
There is plenty of memory and execution time allocation to Craft and the instance is on a dedicated Linux server with 8Gb of RAM

Imports are working without error, but paaaaaainfully slowly -- we're talking hours -- to the point of the import process being effectively useless*.

I have looked into Andrew Welch's #1 solution to running the queue as a background process, but have bumped into installation issues with the Async Queue plugin.

Any suggestions much appreciated.

I'd be happy in principle to do SQL inserts directly into the craft_users and craft_usergroups_users tables but I infer that's not an option since each hash of the shared password is unique and there is a unique UID to generate for each row too.

Update on #3 above:

I'm currently running a batch of 100 instead of 500 and that makes no difference to speed whatsoever.

Next step is perhaps to try a JSON feed instead of CSV?

*'Effectively useless' in the sense that although I have time to run extended imports right now, if it's going to generally take this long it's a non-starter for time-pressured imports.

Second update on #3 above:

An import batch of 100 I started over 2 hours ago has crept along incrementally, with me periodically reviewing its status during that time and seeing barely any change, and then…

I have just revisited it and it suddenly went from 64% complete and unchanging to 100%. Now onto the next batch to see what happens.

Turns out the answer in my case is to use a JSON data source.

Importing users as .json instead of .csv appears to be about 10 times faster:

With .csv importing 480 users took 2.5 hours
With .json importing 455 users took 15 minutes

My JSON looked like this:

{"user": [
    {
        "username":"jane.doe@example.com",
        "email":"jane.doe@example.com",
        "firstName":"Jane",
        "lastName":"Doe",
        "password":"User pass phrase",
        "groupName":"User group name"
    },
    {
        "username":"joe.bloggs@example.com",
        "email":"joe.bloggs@example.com",
        "firstName":"Joe",
        "lastName":"Bloggs",
        "password":"User pass phrase",
        "groupName":"User group name"
    }
]}


Get entries filtered by author's category I got a list of entries news (channel type).
They are created by users (or author).
These users have a category region assigned to them.

My point is to list the news entries that have the same author's category than the currentUser's category...

I am trying with relatedTo but I am stuck here:

{% if currentUser %}
    {% set userRegion = currentUser.region.first() %}
{% endif %}

{% set regionNews = craft.entries.section('news').relatedTo('and',
    { sourceElement: currentUser, field: 'unepRegion' },
    { targetElement: author, field: 'unepRegion' }
) %}

Really don't know where I am going with this.

You probably have to query twice, first get all the users and then get all news entries
published by any of these users using the authorId parameter on your criteria model.

{% set userRegion = currentUser.region.first() %}
{% set regionUsersIds = craft.users.relatedTo(userRegion).limit(null).ids() %}

{% set regionNews = craft.entries.section('news').authorId(regionUsersIds) %}


Show an entry is being worked on Is there anything that will prevent an entry from being worked on by 2 editors at the same time?

Nope, not currently... though there is a feature request for it:

  http://feedback.craftcms.com/forums/285221-feature-requests/suggestions/9009169-add-an-alert-or-warning-when-multiple-authors-are

I guess it's possible for it to be done in a plugin, although I'm struggling to picture exactly how. At this time, no such plugin exists.


Which is the best place to learn Craft CMS with tutorials? I am new to craft cms and would like to learn craft cms with tutorials. I am ready to pay for the subscription but would like to know is there any best place where I can learn the craft ?

CraftQuest.io has some great Craft CMS videos; many are free, but some of the more in-depth ones are not.


Two domains - single install - Live Preview works only on one I have a multi-site setup on two different domains (actually subdomains) with a single Craft install. I have modified config/general.php file to make it work on both the subdomains. Each domain has different template set completely independent of each other. However, Live Preview will work on entries created for only one sub-domain (one that is specified in the control panel). The option is not available for the other subdomain. This is because the public link for the entries corresponding to second subdomain is being parsed as those belonging to the first subdomain. Obviously those links are giving 404 error and hence the Live Preview button is not active.

Is there a way to tell craft that certain entries belong to a specific subdomain?

In order to get Live Preview to work across different subdomains on a single install, you'll need to setup a few extra things as outlined in this support article: https://craftcms.com/support/cross-domain-live-preview


Search in section only How would I enable search in a single section only?

I want my search results template to be used regardless of which search option is used. Ideally I'm looking to pass another value from my search form to the search results to do

{% paginate craft.entries.search(query).section(sectionPassedFromSearchForm).limit(5) as entries %}

You would just pass the other value (i.e. the section handle) in to that template as GET or POST parameter and in the search results template grab the paramater and use it, as in your code.

If using GET, the url you'd construct would be something like:

http://whatever.com/search?query=blah&sectionHandle=blah2

or with POST you might use e.g. a radio for the section option with the name being sectionHandle and the value being the actual handle of the chosen section.

Either way, in your template you then just:

{% set sectionHandle = craft.request.getParam(sectionHandle) %}
{% paginate craft.entries.search(query).section(sectionHandle).limit(5) as entries %}


How can I "clear" an entire website I'm selling the same website build in Craft to multiple clients and was wondering if it is possible to clear all user generated content of an install.

So delete all the entries, categories, assets, globals, ...

You could achieve this using a tool like schematic https://github.com/nerds-and-company/schematic

This allows you to generate all your fields and sections from a file without content. Combine this with a migration to seed dummy data (if you need that)

However, craft 3.1 will ship with a Project config which will do the same thing.


How do I add next/prev controls to a blog? I want to show the latest blog post on the blog/index.html page of my blog which I have done. I now want to display a link to the next post.

Likewise, when I click a blog entry's url I want to add next / prev controls to the blog/_detail.html page.

What is a simple way to accomplish this?

Take a look at: How do I build a pagination nav?


Plugin settings multiline input field I created a plugin settings page following the example shown here but my entries need to include multilines (they are email bodies). My Twig template for the settings page is like this:

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

{{ forms.textField({
    label: "Submitted Subject"|t,
    id: 'submittedSubject',
    name: 'submittedSubject',
    instructions: "Input your setting"|t,
    value: settings.submittedSubject,
    errors: settings.getErrors('submittedSubject'),
    })
}}

(this field is repeated 6 times).
I tried using textAreas instead of textFields, but it doesn't have the same options and I don't think it works (doesn't have a value field). Also it doesn't help that there's barely any documentation for this. Is there a way for me to have multiline text inside the text field?

You are close, the template loaded by the macro can be found in craft/app/templates/_includes/forms/textarea.html. It does have a value attribute, and a few others, for example:

{{ forms.textareaField({
    label:         "Submitted Subject"|t,
    id:            'submittedSubject',
    name:          'submittedSubject',
    instructions:  "Input your setting"|t,
    value:         settings.submittedSubject,
    rows:          4,
    cols:          50,
    errors:        settings.getErrors('submittedSubject'),
    maxlength:     250,
    showCharsLeft: true,
    autofocus:     settings.hasErrors('submittedSubject'),
}) }}

All the form macros are defined in craft/app/templates/_includes/forms.html.


Changing product type for products in Craft Commerce At the moment there seems to be no UI / function for changing the product type for an existing product?

I see theres a typeId column in the products table. Would it be as simply to change this? Would this cause any issues elsewhere?

I personally think mucking with the schema here is bound to get you in trouble.  Very easy to miss something.

If you don't have much data in yet, simply start again, and chalk it down to learning/experience.  (Personally I think there should be a 'Start This Way' page in the Commerce docs that  emphasises Data Modelling for product types is where you should begin!).

If you do have a lot of data in, best to export & then re-import your data using e.g. FeedMe - https://sgroup.com.au/plugins/feedme/getting-started/introduction

(You will need the Pro version which support Products)


How can I delete all entries that belong to a user? It is 100% possible I am going about this the wrong way, so please feel free to correct me.

I have a registration form that creates a user. I have a plugin that is listening to the onSaveUser event:

MyPlugin.php

craft()->on('users.onSaveUser', function (Event $event) {
    if ($event->params['isNewUser']) {
        $entry = new EntryModel();
        $entry->sectionId = 16;
        $entry->typeId = 1;
        $entry->enabled = false;
        $entry->getContent()->title = craft()->request->getPost('firstName') . ' ' . craft()->request->getPost('lastName');

        ...

        if (craft()->entries->saveEntry($entry)) {
            // success
        } else {
            // trouble!
        }
    }
});

Everything works great. The entries I am creating are basically an extension of the user's account (height, weight etc).

I know there are events for deleting a user, but what is the best way to relate the newly created entry so it gets deleted along with the user?

I thought about having an entries field on the actual user account that somehow I populate with the newly created entry?

EDIT

Or, should I have a user field on the newly created entry? In that case, I'm not sure how I populate the newly created entry with the newly created userID.

For example:

...
$user = $event->params['user'];
$entry = new EntryModel();
$entry->sectionId = 16;
$entry->typeId = 1;
$entry->enabled = false;
$entry->getContent()->title = craft()->request->getPost('firstName') . ' ' . craft()->request->getPost('lastName');

// account is the handle of my users field
$entry->getContent()->account = $user->id;  // im not setting this correctly

if (craft()->entries->saveEntry($entry)) {
    // success
} else {
    // trouble!
}

...

You'll want to set the authorId of your entry to be the new user's id.

When you delete that user through the control panel, it'll ask "What do you want to do with this person's content?"... At that point, you can just select "Delete it".


Does anyone use Craft CMS to set up an intranet for client? I heard that Wordpress has a BuddyPress plugin could set up as intranet which has shared files, shared calendars, chat .. etc feature. Does Craft CMS has any plugin to do a similar feature?

There currently isn't a single plugin that does everything that BuddyPress does.

There are calender plugins, commenting plugins, social login and oauth plugins and Craft Pro has built-in front-end registrations with member accounts with user groups and permissions. It would be up to you to tie all of these pieces together for your site's requirements.


using cycle with unknown number of entries I'm using cycle to open and close a div for a row of content. It works great when there are more than a certain number of entries - in this case 4, but doesn't work when there are fewer than that. Is there a way to make this work so it always closes the div even if there are fewer entries than specified in the code?

{{ cycle(['
', '', '', ''], loop.index0) | raw }}
... stuff....
{{ cycle(['', '', '', '
'], loop.index0) | raw }}

Maybe you can use Twig's batch for this?

Twig Batch

{% set items = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] %}
{% for row in items|batch(3, '') %}

    {% for column in row %}

{{ column }}

    {% endfor %}

{% endfor %}

Batch lets you have something to fall back on when you have less items. In this case there are 3 items within my row and if there will be 2, it will output what I have in the '', in this case nothing. (but I can put what I want in that '').


Commerce 1: Different default order status based on product types I want to assign different default order status based on product types.  Is this possible?

What I need to achieve is to send different email notifications based on product types.  Can this be configured or do I need to add logic to and customize the email templates?

Edit: I'm sorry! I missed Commerce 1 in the title! This answer only applies to Commerce 2.

Take a look at the defaultOrderStatus event!

The description is a bit misleading—it's actually used to do exactly what you've described: alter the "default" completed order status in situations where it might not be desirable.

From the docs:

use craft\commerce\Plugin as Commerce;
use craft\commerce\events\DefaultOrderStatusEvent;
use craft\commerce\services\OrderStatuses;
use yii\base\Event;

Event::on(
    OrderStatuses::class,
    OrderStatuses::EVENT_DEFAULT_ORDER_STATUS,
    function (DefaultOrderStatusEvent $e) {
        $myOverriddenOrderStatus = Commerce::getInstance()->getOrderStatuses()->getOrderStatusByHandle('myCustomStatusHandle');

        $lineItems = $e->order->getLineItems();

        foreach ($lineItems as $lineItem) {
            // Your logic for checking the ProductType would
            // replace this basic test:
            if ($lineItem->price > 500) {
                $e->orderStatus = $myOverriddenOrderStatus;
            }
        }

        // Whatever `$e->orderStatus` ends up being by the time we exit
        // this event listener will be used as the new `OrderStatus`.
    });


Output two date languages on the same page without localization I'm trying to output a date like this for instance:

{{ now|date('l, j-m-Y') }}

This outputs the date in my standard language. I need it output on the same page in English too. Is this possible?

The Craft/Twig dateFilter that you're using will currently only translate the string into the current locale the site is set to.

You could probably write a plugin that added its own Twig Extension that added its own filter... let's call it |translatedDate and you could pass in the target locale code as a parameter |translatedDate('en_us').

That filter would do something like:

$currentLanguage = craft()->getLanguage();
craft()->setLanguage('en_us');
...
// Do logic similar to Craft's existing date filter
...
craft()->setLanguage($currentLanguage);


Extracting an attribute from top level node of a Feedme XML feed using template I'm trying to extract an attribute from a top level XML node but having some difficulty.

Given some XML:

<?xml version="1.0" encoding="UTF-8"?>
<slots>
  <slot start="Monday" finish="Tuesday">
    <title id="1234">John</title>
  </slot>
  <slot start="Thursday" finish="Friday">
    <title id="5678">Fred</title>
  </slot>
</slots>

and some Twig:

{% set params = {
        url: 'http://above.xml',
        type: 'xml',
} %}
{% set feed = craft.feedme.feed(params) %}

I can extract values and attributes from the inner nodes

{{feed.slots.slot.0.title.attributes.id}}
{{feed.slots.slot.0.title}}

which yields 1234 John as I would expect. But now, how do I get the attributes from the slot node e.g. I want the 'Monday'. I've tried something like

{{feed.slots.slot.0.attributes.start}}

but that just throws an error.

EDIT: If I change the XML (remove the inner title nodes) to

<?xml version="1.0" encoding="UTF-8"?>
<slots>
  <slot start="Monday" finish="Tuesday">
  </slot>
  <slot start="Thursday" finish="Friday">
  </slot>
</slots>

then

{{feed.slots.slot.0.attributes.start}}

works. So maybe the question now is how do I extract attributes from a node that has sub-nodes?

It appears now that this is an issue with the plugin being unable to read attributes of a node which has sub-nodes. The developer has noted this, and will hopefully post a fix. In the meantime as work around I used a short php script on the server to call the XML file first and rework the data into a format that the plugin can read.


How to call two separate images from Matrix field I'm new to Craft and using Matrix fields.

I've got a matrix field called imageDouble with two child fields called firstImage and secondImage.

The template code I have is returning a 500 error. I want it to display firstImage and secondImage each in their own separate div. Any help with my structure here?

{% for block in entry.body %}

    {% if block.type == "text" %}

{{ block.textContent }}

    {% elseif block.type == "imageDouble" %}

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

            {% if image %}

            {% endif %}

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

            {% if image %}

            {% endif %}
 {% endfor %}

I think the issue here where you are setting your image variable.

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

This should reference the field handle of the asset you are trying to get the url of, so it should be this instead:

{% set image = block.firstImage.first() %}

Then where you try and display the image it should be:

You would then need to update this for the secondImage.

It might be worth mentioning that there is a cleaner way to achieve what you’re after, with just one asset field.

You can upload multiple images to a single asset field, so assuming firstImage has two assets attached, your code could be shortened to the following:

...
{% elseif block.type == "imageDouble" %}

 {# this has two assets attached #}
 {% set images = block.firstImage %}

 {% if images and images|length %}

    {# Loop through the images #}
    {% for image in images %}

    {% endfor %}

 {% endif %}

{% endif %}
...

This will help keep your code from repetition and will be easier to maintain in the future :)


Get Entrys relationships regardless of context This might be a little complex, but here it goes:

Goal: For any given entry, determine where it's located. (Ex. Entry XYZ exists in a news entry, global field, single (page), etc...)

Context:
So far I figured I could go the custom SQL route until I learned more about craft internals, so what I did was create a Service that does the following query:

    $query = craft()->db->createCommand()
        ->select('element.*, detail.type, relation.fieldId AS sectionId, section.handle, section.name, section.hasUrls')
        ->from('elements_i18n AS element')
        ->join('relations AS relation', 'relation.sourceId = element.elementId')
        ->join('elements AS detail', 'detail.id = element.elementId')
        ->join('sections AS section', 'section.id = relation.fieldId AND section.hasUrls = 1')
        ->where('relation.targetId = :id', array(
            ':id' => $elementID
        ));

    $results = $query->queryAll();
    $results = MyPlugin_EntryRelationshipModel::populateModels($results);

I'm using MyPlugin_EntryRelationshipModel as a Facade and it extends Craft\ElementCriteriaModel

Problem: This works flawlessly until a Matrix field comes into play.

So I found this: https://github.com/iainurquhart/craft_introvert which is exactly what I wanted to do. Hope this helps anyone else!


Display entries by category (multiple categories) I would like to know how I can create a page that contains all entries from a section e.g. 'news'. I want to divide the entries by their given category.

News (section)

Category 1:

entry in category 1
second entry in category 1
third entry in category 1

Category 2:

entry in category 2
second entry in category 2
third entry in category 2

etc.

Does anyone know the code for this? The categories are all in the same category group.

You can use .relatedTo(category)

{% for category in craft.categories.group('categoryName') %}

{{category.title}}

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

  {% endfor %}
{% endfor %}

You can check for length if you don't want to show categories which aren't related to any entry.

See the relations documentation


Adding .html to end of page url? I am currently using Craft to manage only certain pages on a site. The static pages all end in .html but Craft's pages don't. Is there a way to rewrite them via Craft to add .html or do I have to do some .htaccess wizardry? I only want to rewrite the pages and not the categories (for example, /news/).

If I can achieve this, should I? Are there enough SEO benefits to a consistent URL format? I've also read using .htaccess in this way may affect SEO negatively, which is why I'm wondering if there's a way of doing it with Craft.

You can change your entry's URL format right inside Craft. It's under Settings -> Sections then choose the section you want.

Under URL Format, just add .html after the {slug}. In this example, I've also added the year that the entry was added to the URL as well and you can really make it whatever you want.
Using .htaccesss you could also remove the .html extension from the static pages too if you want to follow Craft's format (though be careful with that one).
SEO
As far as whether it's a good idea to do either for SEO purposes, you're going to get a lot of differing opinions. I'm a URL minimalist,  so I tend to keep my URLs simple, including removing www from the hostname and removing any trailing slash from URLs if possible.
Google tends to favor short URLs among other things but it's not a big factor.
Content is content. Years ago, I remember there used to be some SEO benefit to adding .html but if search engines can index it, it doesn't matter what the URL is.
The bigger issue for me is any time you change a URL, you risk blowing something up. I'm always reminded of the saying Cool URLs don't change.
If your site has been around awhile,  I wouldn't mess with them. Other people may be linking to your pages and if you change the URLs, you'll want to put in 301 redirects—otherwise they'll 404, which is a much bigger problem.


Running Craft updates This is a newbie question regarding running Craft updates. In the past I've been caught out by stupidly running updates on the live server. I'm now trying to get into the habit of running the updates on a local version, then pushing that to the live version - the proper way of course. Am I right to assume that the only files that have been changed after an update are composer.json and composer.lock (along with the db)?

composer.json and composer.lock aren't technically the only files that change; for example some of the files in the vendor folder change each time you update. If you're using Project Config, occasionally the project.yaml file will change if a plugin update makes some data architecture changes or something.

Some Info on Composer and Craft and Updating

The only time composer.json would change on an update is if you ran the update via Craft's updater. When you use Craft's updater, it disregards what is specified in the composer.json; it does its own checking and when it updates a package it locks the packages down in the composer.json to that particular version number. However, when you use composer update to do your updating, it will use what is specified in the composer.json to do see if there are any new versions that match the specified semantic versioning constraints (semver); running a composer update changes nothing in your composer.json file.

Here's an example of what the difference might look like:

1) "nystudio107/craft-seomatic": "3.2.3",   // Craft updates style (note the absolute version number)

2) "nystudio107/craft-seomatic": "^3.1.0",  // Composer semver style (note the '^')

When you run Craft's updater; it won't matter which of these lines you use. Craft will do its own checking and overwrite the current semver as necessary. If you use composer update, #1 won't allow you to install anything other 3.2.3 because that is what is explicitly declared; #2 will allow anything that fits 3.X.X. So if you've used Craft's updater in the past, you'll need to manually add ^ or ~ to your version numbers before composer update has any affect.

The composer.lock file works quite similarly to the way the Craft updater uses the composer.json package version numbers. It's basically a big file that contains the installed version number (as well as a bunch of other stuff) of every single package as well as all the dependencies. It changes any time you update, whether via Craft or composer.

Then you've also got composer install which behaves differently than composer update. composer update takes the semver provided in the composer.json file and checks to see if any newer version that fits the constraints are available, if so it installs it. composer install looks in the composer.lock file and installs whatever is specified there. This means that running composer install on an existing codebase should have no effect provided everything's previously been installed.

A Typical Craft Upgrade Strategy

Here are the typical steps for updating your Craft sites locally and pushing those changes to a live/production server.

Depending on whether you use Craft or composer for your updating:

Run composer update locally. Again, this fetches any newer package versions that comply with the semver, installs them, and makes the necessary changes to the composer.lock file. OR
Run Craft's updater locally. Again, this fetches any newer package versions, installs them, and makes the necessary changes to the composer.json and composer.lock file.

Depending on the nature of the updates, you may need to run a database migration locally. You'll also want to quickly test your site and make sure nothing broke because of the updates.
You'll commit the changes to composer.lock (and if you used the Craft updater, the changes to composer.json) and merge branches / push to your remote Git repo per your typical process.
Usually you'll have some sort of deployment process setup (Buddy, DeployBot, Laravel Forge deployments, etc) that watches your remote Git repo and does a deployment every time you push. This deployment usually looks like a git pull of the latest changes and then, depending on your deployment tool of choice, this next step might be done on the deployment server and the resulting files pushed to the live server or it might be done on the live server itself...
You'll typically need to do several things as part of the final step of the deployment process:

Run composer install - remember, this takes that composer.lock file (which is now different from the files in the vendor folder on the live server) and installs anything it can (i.e. if the lockfile and the vendor folder agree on a certain package, it skips it; otherwise it updates it).
Run your database migration on the live site.
If you're using project config, and the project config file changed during the updates, you'll want to sync any changes there.
Finally you'll want to clear caches so you get the latest and greatest on the frontend of your site.

These steps take some time to do manually, which is why it is a good idea to automate them. You can run them all via the CLI via your deployment tool, but an even better idea would be to add them to the scripts in your composer.json file. For example:

...
"scripts": {
  "post-install-cmd": [
    "@php craft migrate/all",
    "@php craft project-config/sync",
    "@php craft clear-caches/all"
  ],
  ...
},
...

If you add that to your composer.json, any time you run composer install those other three commands will be run directly after.

My apologies on the short answer, I was pressed for time. JK lol


Conditional variables within a certain matrix block type So I have a matrix field with 3 different block types. The first two block types have markup contained within their scope. The last type, has opening and closing tags for the first of type and last of type (basically creating a row with two columns). I was able to successfully get the markup, but wanted to see if there is a better way to to this write this.

{% for block in entry.homeContentBlocks %}
    {% if block.type == "leadGeneration" %}
        ...
    {% elseif block.type == "banner" %}
        ...
    {% else %}
        {% if block.next() %}
            {% if block.next().type == "contentBlock" %}
{% endif %}
        {% endif %}

            {% if block.next() %}
                {% if block.next().type == "contentBlock" %}

                {% endif %}
            {% endif %}
            {% if block.prev() %}
                {% if block.prev().type == "contentBlock" %}

                {% endif %}
            {% endif %}

{{ block.heading }}

                {{ block.body }}
                {% if block.btnLink | length %}
                    {% set link = block.btnLink.first().url %}
                    {{ block.btnLabel }}
                {% endif %}

        {% if block.prev() %}
            {% if block.prev().type == "contentBlock" %}
{% endif %}
        {% endif %}
    {% endif %}
{% endfor %}

So this works, but let's say the blocks out of sequence. I thought maybe a increment variable could work, but wasn't sure how to implement it.

Why don't you do something like this? You can use switch and case to change the output of each part of the matrix (we call them blocks).

This is part of a snippet to output a documentation matrix that contains code, titles, content etc.

{% for block in entry.documentation %}
    {% switch block.type %}

         {% case 'subsectionTitle' %}

{{ block.subsectionTitle }} #

        {% case 'description' %}

{{ block.description }}

    {% endswitch %}
{% endfor %}


How can I write a PHP script to zip and download an Assets subfolder? I've searched everywhere but can't seem to get a straight answer.  I want to write a php script to zip and download an entire subfolder in my assets directory.  The subfolders are named based on a variable.  Where do I write this php code?  Must I write a custom plugin for something so simple?

Yes, you'd need to write a plugin to do this... or you could write a module. There are some plugins that may already do what you want tho: Squeeze / Compress


Rendering pages from Craft CMS as static HTML Has anyone tried creating a process whereby the pages/entries generated from Craft could be presented as static HTML?
I am keen to know what different approaches have been taken in the past as we are considering it for a company website.

There are a few different solutions for this. Personally my favourite is to switch on static caching in nginx, as it's a relatively quick and easy solution. Andrew has you covered on how to do that here: https://nystudio107.com/blog/static-caching-with-craft-cms
If you're not using nginx, then a popular choice is the Blitz plugin: https://plugins.craftcms.com/blitz (I've not used it myself so can't really comment, but it sounds good if you're not into rolling your own solution in nginx). Blitz offers a static export of your site too, so it's literally just html files, which would be more portable than nginx's static cache (i.e., you could host the site directly on a CDN).
With any kind of static system, you'll need to ensure:

That any form submissions such as keyword search and contact forms still work by dynamically refreshing any CSRF tokens via AJAX.

That the relevant actions in Craft cause the cache to be deleted. Again, Andrew has you covered here if you're using nginx static caching with the FastCGI Cache Bust plugin: https://github.com/nystudio107/craft-fastcgicachebust

Overall I prefer nginx static caching because I still have the dynamic benefits of a CMS and don't have to worry about complicated workflows for updating an entire load of files and redeploying them somewhere whenever someone corrects a spelling mistake... but I guess if you can fully automate that it's a fine solution.


Craft 3 RC 11: Deleting Assets Issue When I delete an asset in the CP, the asset/file will be deleted, but it is still shown in the assets list (without thumb).

The issue can't be solved with the "Update asset index" function. (There is also the file listed: "Missing file"!)

  yii\base\ErrorException: unlink(/Applications/MAMP/htdocs/xxxxxxxx/storage/runtime/assets/sources/108.png): No such file or directory in /Applications/MAMP/htdocs/xxxxxxxx/vendor/yiisoft/yii2/helpers/BaseFileHelper.php:407

This looks to have been fixed a few hours ago:

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

You could apply the fix yourself for an immediate solution:

https://github.com/craftcms/cms/commit/30db5af5b596e267db136a218209a65cc9fde36e


Display entries by tag I've read through the docs but can't figure out what I'm doing wrong here:

I'd like to display a list of entries by tag, where the tag is in segment 2 of the url.

Here's what I've tried and is not working (they output nothing):

{% set secondSegment = craft.app.request.getSegment(2) %}

{% set diaryEntries = craft.entries.section(['gardenDiary','gardenInfo']).relatedTo({
        sourceSite: craft.app.sites.currentSite.id,
    element: secondSegment,
    field: 'gardenTags'
}).limit(null).all() %}

Also tried:

{% set diaryEntries = craft.entries.section('gardenDiary').relatedTo(secondSegment).all() %}

...

{% for entry in diaryEntries %}
{{ entry.title }}
...etc...
{% endfor %}

Entries are known to be related to tags
I've tried adding a known related tag directly - still nothing.
If I don't specify a tag, it lists all the entries.
Example URL: mydomain.com/tags/fruit
Template is loaded via a Route: [Global] tags/* -->  tags/index.html

What am I doing wrong? Thanks in advance.

The relatedTo param expects an object, an ID or an array of object or ID (docs), in your case secondSegment is a string and this is the issue. Try:

{% set tag = craft.tags.slug( craft.app.request.getSegment(2) ).one() %}
{% set entries = craft.entries.relatedTo(tag).all() %}


How do I check if a structure has any entries at level 3 when I'm at level 1? I'd like to output a special link in level 1 upon current top-level entry doesn't have any entries at level 3. If It have move that special link one level above.

To picture it:

Page 1

Subpage 1
Subpage 2
Special link A

Page 2

Subpage 1

Subpage 1.1
Special link A

Currently I didn't have any difficulties with level 2:

{% set lvl = entry.level %}
{% if lvl == 2 and entry.children|length %}
    A link
{% endif %}

To set that special link at level 1 is.
Most logical way to me is to use EntryModel's method getDescendants( distance ) as I don't have to set any variable. If I understand it correctly It should get descendant entries at given level? of a current entry's variable.  When I set to (distance) other integer than 1 let's say 2 It prints out all entries from second level including level 2. So It's unclear to me what distance does in this case.

{% if lvl == 1 and entry.getDescendants(2)|length %}
    A link
{% endif %}

Argument is true even if there are no descendant entries of second level. Because When looping in It prints all entries from second level up including second level as I mentioned before.

Or I can't use this method?

To make it works I had to query in the section for descendant entries at level 3 of a current entry variable.

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

{% if lvl == 1 and products.descendantOf(entry).level(3).first()|length %}
    // If the above statment is true we don't want that special link at level 1
{% elseif lvl == 1 %}
    // A special link
{% endif %}

{% if lvl == 2 and entry.children|length %}
    // A special link
{% endif %}

I welcome a smarter solution.

Updated: Thanks to @carlcs comment a performance has been enhanced

{% if lvl == 1 and products.descendantOf(entry).level(3).total() > 0 %}
    // If the above statment is true we don't want that special link at level 1
{% elseif lvl == 1 %}
    // A special link
{% endif %}

{% if lvl == 2 and entry.children.total() > 0 %}
    // A special link
{% endif %}


Plugin Development: extending a vendor plugin I'm using composer to import a third-party (vendor) plugin into my own Craft plugin. But can't figure out how I extend the functionality of the imported (vendor) plugin.

For example assuming imported plugin defines a base class of XXX I can try to extend this with class YYY extends \XXX but not sure where I save this so I can access this in my code, eg I want to extend the base plugin through a class, eg

class YYY extends \XXX
{
    public function doThis($str) { return $str; }
}

I'd then want to access this in my Craft plugin with

$var = new \XXX();
$var->doThis = 'CONTENT HERE';

Obviously grossly simplified but hope you get the gist.
Just can't figure out how to achieve above or where I should save the code that is extending the vendor class?

Any thoughts?

In your example, if you do this:

$var = new \XXX();
$var->doThis = 'CONTENT HERE';

Then doThis will never exist for class \XXX because \XXX isn't where the method was defined.  It would work from your extended class, though:

$var = new YYY();
$var->doThis = 'CONTENT HERE';

Keep in mind that (usually) if the vendor plugin instantiates any instances of that class internally, it will always be of instance \XXX, not your YYY class.

Where that wouldn't be true, is if the vendor plugin supports dependency injection where they allow you to inject your extended YYY class wherever \XXX would usually be referenced.


Help with the latest Redactor, removing formatting options In the past I've managed to remove a few formatting buttons from Redactor but am having trouble with the new version.
The goal is to remove 'quote', 'code' and 'heading1' from the formatting-dropdown. (see attached).

So far I have tried various ways of inserting this from the documentation:
['p', 'h2', 'h3', 'h4', 'h5']
This is the only attempt which hasn't resulted in a syntax error, but which has resulted in the formatting button disappearing completely!
  "buttons": [
    "html",
    "formatting: ['p', 'h2', 'h3', 'h4', 'h5']",
    "bold",
    "italic",
    "unorderedlist",
    "orderedlist",
    "link",
    "image",
    "video"
  ],
  "plugins": [
    "fullscreen",
    "video"
  ],
  "linkNewTab": true,
  "toolbarFixed": true
}

Please could you spoon feed me the json as I cannot seem to find the answer anywhere. Thanks in advance for your help!

Inside the buttons array, you should only mention formatting.
The actual styles you want to put inside an array with key "formatting".
{
  "buttons": [
    "html",
    "formatting",
    "bold",
    "italic",
    "unorderedlist",
    "orderedlist",
    "link",
    "image",
    "video"
  ],
  "formatting": ["p", "h2", "h3", "h4", "h5"],
  "plugins": [
    "fullscreen",
    "video"
  ],
  "linkNewTab": true,
  "toolbarFixed": true
}

Reading a bit further in the docs, you could also remove the styles you don't want, instead of stating the ones you do want:
formattingHide: ["blockquote", "pre", "h1"]


Accessing array/object attributes in Twig There are three methods for that:
object.attribute

object['attribute']

attr(object, 'attribute')

How are these different from each other?

{{ entry.title }}

compiles down to:
        echo twig_escape_filter($this->env, craft\helpers\Template::attribute($this->env, $this->source, (isset($context["entry"]) || array_key_exists("entry", $context) ? $context["entry"] : (function () { throw new RuntimeError('Variable "entry" does not exist.', 19, $this->source); })()), "title", []), "html", null, true);

...and
    {{ entry['title'] }}

compiles down to:
        echo twig_escape_filter($this->env, craft\helpers\Template::attribute($this->env, $this->source, (isset($context["entry"]) || array_key_exists("entry", $context) ? $context["entry"] : (function () { throw new RuntimeError('Variable "entry" does not exist.', 20, $this->source); })()), "title"), "html", null, true);

...and
    {{ attribute(entry, 'title') }}

compiles down to:
        echo twig_escape_filter($this->env, craft\helpers\Template::attribute($this->env, $this->source, (isset($context["entry"]) || array_key_exists("entry", $context) ? $context["entry"] : (function () { throw new RuntimeError('Variable "entry" does not exist.', 21, $this->source); })()), "title", [], "array"), "html", null, true);

If they look similar, that's because... they are identical in terms of the PHP code they compile down to.
So the difference is... whichever one uses the fewest keystrokes to type.


Create web report able to be exported in pdf I'm new in the Craft CMS world, and I'm approaching it because I need to create a web app where I and my colleague can create reports based on what we do for customers and export them in PDF format.

Can I accomplish this task with Craft?

In positive case can anyone give me some hints about what to do to begin (example.. plugins to study etc..)

Thanks so much.

This is a really broad question since it does not cover a specific topic but many things about plugin development. I would suggest you to read articles like So You Wanna Make a Craft 3 Plugin? or Enhancing a Craft CMS 3 Website with a Custom Module. You can create a boilerplate of a plugin with Pluginfactory.io.

To get used to the topic there are official documentations as well. If you have specific problem/question you can ask it.

In general there aren't many things that can't be accomplished with Craft. It's a really dynamic and flexible CMS and can be enhanced/extended in many ways.


Solspace Freeform email notifications I'm a relative newbie to Craft CMS / Solspace Freeform. I'm trying to implement a form which will capture some basic details and send to an email address.

I've done the setup correctly (from what I can see) however when I go into email notifications I can only see database entry templates and no email notification templates.

When I test my form it submits the data to the submission page on Craft but no email is ever sent.

Could anyone point me in the right direction?

There is a contact form and related template setup by someone prior to me on the website which I know emails to a specified email address, but I can't seem to get mine working.

Thanks.

Freeform allows you to send email notifications 5 different ways (all of them each being able to have their own notification templates, etc).

For setting up Admin Notifications specifically, follow these instructions:

  Email notifications can be sent to one or more admin email addresses. To setup:

  In Composer interface for the form, click on the Admin Notifications (envelope icon) tab at the top right.
  Select and/or add an email template.
  Specify admin email address(es) in the text area below. Separated multiples by line breaks only.

As for actually choosing between database-based notifications or HTML file-based notifications, setting them up, etc, you can check out the documentation here.


Problem adding new locale / Resaving matrix blocks Failed / Table 'matrixcontent_files' doesn't exist I've got an error message from my craft (2.6.2990) after adding a German locale:

  Resaving all localizable elements: Failed

  Resaving matrix blocks: Failed

in the sidebar and here is what I found in craft logs:

2017/09/20 14:52:13 [error] [system.db.CDbCommand] CDbCommand::fetchAll() failed: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'zg_blike.craft_matrixcontent_files' doesn't exist. The SQL statement executed was: SELECT `elements`.`id`, `elements`.`type`, `elements`.`enabled`, `elements`.`archived`, `elements`.`dateCreated`, `elements`.`dateUpdated`, `elements_i18n`.`slug`, `elements_i18n`.`uri`, `elements_i18n`.`enabled` AS `localeEnabled`, `content`.`id` AS `contentId`, `matrixblocks`.`fieldId`, `matrixblocks`.`ownerId`, `matrixblocks`.`ownerLocale`, `matrixblocks`.`typeId`, `matrixblocks`.`sortOrder`

I checked the DB and of course did not find table called craft_matrixcontent_files, instead only craft_matrixcontent_file

Any ideas?

I had a field called files, it did not belong to matrix. After deleting it (tried also simply renaming), the problem disappeared.

After that I created a field with the same name and that did not cause any problems.

Still do not know the exact reason, but later will have time dig a bit deeper, so if get some results will post them.


Plugin not displayed on Plugins Section I'm trying to install Sprout Report plugin, so I downloaded from here
so I followed the instructions from the plugin documentation site: here
According to that documentation the zip folder from GitHub just need to be placed on craft/plugins folder but after I do this the plugin still does not show on dashboard.
Do I have to do something else so it can be displayed?
Also the zip file from GitHub gives me a folder name: craft-sprout-reports-1 but according to the official documentation the plugin folder's name should be named as: sproutreports
Will be the name of the folder the reason why it's not showing?
Thanks for any help.
plugin-sproutreports
plugin-sproutforms

When downloading from the Github releases tab be sure that you are downloading the latest plugin release for the version of Craft you are using.

In the case of Sprout Reports:

v0.x releases are for Craft 2
v1.x releases are for Craft 3

When in doubt you can look at the files within the plugin folder and try to determine which version of Craft the plugin is for. Most Craft 3 plugins will have a composer.json file and src/ folder.


2 multi sites with separate root pages I have 2 sites within 1 Craft 3 installation, they are both the same language and generally have nothing to to with each other.

I would like both to have individual startpages at the URL "/".

Is this possible?
With 1 or 2 sections (structures in my case)?

Thanks,
Matthias

Create a new site in Settings > Sites > New Site
Make sure "This Site Has Its Own Base URL" is checked
Go to the "Entries" section, publish a page, and set the entry slug as __home__
Return to the Entries section, switch to Site 2 using the dropdown menu at the top of the screen
Publish a page and set the entry slug as __home__

Craft knows which site each page belongs to, so there will be no conflict between the slugs.

You can use any section you like to publish your homepages, as long as the Entry URI Format in the section's settings doesn't require a special syntax. Many people use a "Single"-type section or a "Structure"-type section with a URL setting of {parent.uri}/{slug}. Make sure the section is available to be used by Site 2 in the section settings.


Ordering Entries without using entry date Looking to explore solutions for ordering entries in a channel. My current ideas are:

For example purposes let's say this is for recipes and the client wants to be able to pick the order of recipes by some method other than changing the date of the recipe.

1. Add a matrix field, with blocks as entry fields ( for recipes channel ) on the single section (recipes index), where you can select and reorder the entries. Then loop over matrix field to print out the recipes in that order.

Pros: Very easy drag and drop sort.

Cons: Every time a new recipe is added, it as to be manually added to the matrix field.

2. Add a custom field to the recipe channel entry as an integer. Use that integer to sort the entries.

Pros: No extra field on a single section that is somewhat de-coupled from the recipe channel.

Cons: As far as I could find, there is no way to add a column to the entries overview page on the backend of Craft, so you would have to go into each entry and make sure to not have duplicates of the same number. If you wanted to add a new entry at spot 5, and you already had 10 entries, that would be very tedious.

We are brainstorming today, and thinking about what we could make plugin-wise that may add this kind of functionality as well. Will post more info if I come with anything else.

I'd suggest changing the Recipe section to a "Structure" section type.

This lets the client order the entries with a drag and drop from the Entries tab where they can see the whole list of entries during the reordering.


Listing categories with post count in a nav? I'm trying to list my categories (and sub categories, just one sub level) as a nav, and have the number of entries in each of those categories beside each one.

There is another question on here which achieves a simple list here but trying to apply that logic to what i have for my nav is scrambling my brain as everything I've tried throws an error.

This is what i have, taken from the Get Help section of the craft site:

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

        {{ category.title }}
        {% ifchildren %}

                {% children %}

        {% endifchildren %}

{% endnav %}

Any thoughts on how i can get the number of entries each category has in it, in this?

Within you nav loop, you would use the method total() with an craft.entries ElementCriteriaModel, to only count the entries that are related to the category you're looping. Pass the CategoryModel to the relatedTo parameter.

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

    {# Get the count of entries related to `category` #}
    {% set entryCount = craft.entries.relatedTo(category).total() %}

    {{ entryCount }}

{% endnav %}


Exception on trying to install Craft CMS 3 plugin I'm trying to create a new plugin for my website in Craft CMS 3, just to do some really basic stuff, like parsing an XML file from an external site.

I created it using the plugin creator at https://pluginfactory.io/ as per the craft docs. I have only included the controller and variable components.

I've added it in to my composer.json file, run the composer require command and it has successfully been added to the plugins list with my craft install. However, when I go try and install it from the plugins page, I get this error:
"The use statement with non-compound name 'Craft' has no effect in /var/www/html/[websitename]/plugins/[websitename]/src/[websitename].php at line 15"

This is what the code that has been generated looks like (website name redacted):

11 namespace \[websitename];
12
13 use \[websitename]\variables\[websitename]Variable;
14
15 use Craft;
16 use craft\base\Plugin;
17 use craft\services\Plugins;
18 use craft\events\PluginEvent;
19 use craft\web\UrlManager;
20 use craft\web\twig\variables\CraftVariable;
21 use craft\events\RegisterUrlRulesEvent;
22
23 use yii\base\Event;

Does anyone have any idea what is happening here? I've tried reading the plugin docs but I can't see what is going wrong. I assume the plugin creator is generating files correctly, I've used it several times for Craft 2, but this is my first attempt at a Craft 3 plugin.

Thanks, Jai.

Please remove the first \ and include a vendor directory

11 namespace [package]\[websitename];
12
13 use [package]\[websitename]\variables\[websitename]Variable;

The namespace must always consist the package and the plugin name docs

Here is an example

namespace ns\prefix; // <-- see: ns\prefix, not only prefix

class Plugin extends \craft\base\Plugin


How do I set up PhpStorm for plugin development Can someone explain how to set up PhpStorm so that I can use it to develop/debug a plugin? I have

local webserver set up
craft files in the usual place above the webroot

The new project wizard gives me a choice between "Web server is installed locally, source files are located under its document root" and "Web server is installed locally, source files are located elsewhere locally. (Source files are copied to project root, then synchronized with server when necessary.)" Neither of which seems quite right.

Directory structure:

craft

app
plugins

myplugin

public <== this is webroot

.htaccess
index.php

I point File->Open Directory at craft/.., and PhpStorm pick up everything for me. You probably have to set up path mappings to make debugging work properly, but PhpStorm will alert you to that and launch the mapping UI.

I have a sandbox Craft install running at local.sandbox.dev and I create a git repo in the plugins directory, and develop the plugin in there. That way I can have multiple plugins in this sandbox, all with different repos, whereas the Craft install itself is not version controlled. Makes it easy also to dump the entire installation and replace it whenever the database becomes too mangled.


How to remove entire Craft CMS folder? or rather uninstall it I have to reinstall it because i f'up by changing "localhost" to "mysite.dev" on the installation page.

To delete craft, all you need to do is delete the craft/app folder, so you don't lose all your templates/plugins etc. That said, this won't affect your site url as siteUrl stored in the database.

Here are a few options:

You would need to go into the database under the table craft_info and then change siteUrl back to localhost or whatever you need it to be.
If you have only just gone through the installation page then you can just delete the database and start again.

My most preferred thing to do to avoid these sort of issues is to set the siteUrl within a config file and simply reference it.

For example in craft/config/general.php you would have:

return array(
 '*' => array(
   'environmentVariables' => array(
     'siteUrl' => 'localhost'
   )
 ),
 '.com' => array(
   'environmentVariables' => array(
     'siteUrl' => 'http://somedomain.com'
   )
 )
);

So basically here we are setting the siteUrl config within a wildcard config using * which means it gets applied to all environments.

Straight after we are then overriding the siteUrl config for just .com domains.

See Multi environment config and Multi environment variables

The beauty of this is now when you install Craft (or change siteUrl in the database) you only need to put {siteUrl} within the input and Craft will automatically fetch the value from your config file, based on your environment.

Hope that helps!


How can I call a controller method from the front-end using ajax I would like to call an action method from within my plugin via ajax but I am always getting a 404 response.

I have a controller method that matches the ajax url:

jquery

$.ajax({
    'type': 'post',
    'contentType': 'application/x-www-form-urlencoded; charset=UTF-8',
    'cache': false,
    'data': data,
    'url': 'pluginHandle/checkStatus',
    'dataType': 'json',
    'timeout': 50000
}).done(function (response) {
    // Success
}).fail(function (error) {
   // Total fail.
});

MyPluginController.php

...

/**
 * Checks what the current status is RIGHT. NOW.
 *
 * @throws HttpException
 *
 */
public function actionCheckStatus()
{
    $this->requireAjaxRequest();

    $response = [
        'status' => 'open'
    ];

    $this->returnJson($response);
}

...

What am I doing wrong?

Make sure to check out the documentation on routing. Pay special attention to the part about action request(s).

In this example, I want to call a controller method via ajax on page load.

MyPluginController.php

...

/**
 * Checks what the current status is RIGHT. NOW.
 *
 * @throws HttpException
 *
 */
public function actionCheckStatus()
{
    $this->requireAjaxRequest();

    $response = [
        'status' => 'open'
    ];

    $this->returnJson($response);
}

...

jquery

$.ajax({
    'type': 'post',
    'contentType': 'application/x-www-form-urlencoded; charset=UTF-8',
    'cache': false,
    'data': data,
    'url': '/actions/pluginHandle/checkStatus',
    'dataType': 'json',
    'timeout': 50000
}).done(function (response) {
    // Success
}).fail(function (error) {
   // Total fail.
});

The key part to note is the url attribute in the ajax request. It is prepended with 'actions'. As you will note in the docs you can change 'actions' to whatever you want.


503 Response on fresh install, FastCGI possible culprit I've spent all of today trying to configure a server block that will let me install Craft 2.62797 on a Digital Ocean droplet running Ubuntu 14.04 with NGINX and PHP 7.

After uploading the craft directory and a public directory with the index.php file, a visit to my site gets the

**Service Unavailable** Our site is temporarily unavailable. Please try again later.

error.

At first I was using the server block recommended by Brad Bell in this post.

Unfortunately that setup uses 127.0.0.1:9000 for a socket, and none of the other sites on our droplet uses a TCP socket -- they all use this chunk for fastcgi

location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
   }

So I tried dropping that in, no dice. Here's some of the debug info from the site's error log. I think this is where it all goes wrong:

2016/07/19 16:50:08 [debug] 4362#4362: *18 connect to unix:/var/run/php/php7.0-fpm.sock, fd:23 #20
2016/07/19 16:50:08 [debug] 4362#4362: *18 connected
2016/07/19 16:50:08 [debug] 4362#4362: *18 http run request: "/index.php?"
2016/07/19 16:50:08 [debug] 4362#4362: *18 http upstream check client, write event:1, "/index.php"
2016/07/19 16:50:08 [debug] 4362#4362: *18 http upstream recv(): -1 (11: Resource temporarily unavailable)
2016/07/19 16:50:08 [debug] 4362#4362: *18 http upstream request: "/index.php?"
2016/07/19 16:50:08 [debug] 4362#4362: *18 http upstream dummy handler
2016/07/19 16:50:08 [debug] 4362#4362: *18 post event 00007FB15402C770
2016/07/19 16:50:08 [debug] 4362#4362: *18 post event 00007FB15403E780
2016/07/19 16:50:08 [debug] 4362#4362: *18 delete posted event 00007FB15402C770
2016/07/19 16:50:08 [debug] 4362#4362: *18 http upstream request: "/index.php?"
2016/07/19 16:50:08 [debug] 4362#4362: *18 http fastcgi parser: 0
2016/07/19 16:50:08 [debug] 4362#4362: *18 http fastcgi header: "Status: 503 Service Unavailable"

(I edited it for brevity, don't think I clipped out anything relevant).

For what it's worth, I tried editing PHP's www.conf settings, to allow for listening on 127.0.0.1 and port 9000, as per this post. I knew this would break all the other sites, but I wanted to see if I could get it working -- still got a bad gateway error. (Possible that I hadn't restarted PHP after that change, though.)

The bizarre thing about all this is that I have a working Craft CMS install on this same droplet. I tried duplicating its server block, which was auto-generated by Laravel Forge, but that netted me the same error message and didn't log anything to the error log.

Anyway, that's about all I know -- I'm sure I'm leaving something out, but I'm a bit frayed by the debugging process. Would be grateful for any advice.

Okay, my next stackexchange question will be "Where is the dunce cap?" because I could use one. My problem was not actually a problem, and Lindsey D was exactly right: I was just going to mysite.com, not to mysite.com/admin.

And I see now that that was clearly stated in the install instructions, a tab that I was referring to over the course of the whole afternoon!

Thanks, Lindsey, my morning just opened up. And to the dev of posterity who finds his way to this question and answer: I know it hurts.


Craft Commerce: Displaying Individual Product Options in the Cart? In the cart example code the selected options are displayed in an unformatted list like so:

{{ item.options|json_encode }}

I noticed that the note field text could be outputted individually like so:

{{ item.note }}

I'm looking to do the same for the select fields on my product, so if I had a list of options like the gift wrap example, how would I then output the result individually (so that I can format how I like)?

<select name="options[giftWrapped]">
  <option value="no">No gift wrap.</option>
  <option value="yes">Gift wrapped.</option>
</select>

Answer is the example code for the cart:

{{ item.options.giftWrapped }}


Freeform Element Connections to Update Existing Entries I have a Freeform 3 form and I have mapped it to an existing channel. The connection works, and filling out a form creates a new entry, but it only create new entries. The form is on an entry page. The channel has an autogenerated Title and I am pulling that into the form template via a hidden field.
I was hoping to be able to "update" existing entries and not just create new ones. Do I need to also pull in the entry.slug or entry.id? Or do the element connections not have this functionality?
What I am getting is only new entries: entry-01, entry-02, etc.

According to the Freeform docs it looks like you'll need to pass an element ID.

Freeform allows you to edit/update existing Craft elements (Entries, Users and Calendar Events currently) by including the elementId parameter in your form. It works by feeding a Freeform form an element ID.

{{ craft.freeform.form("editCraftUsers").render({
    elementId: currentUser.id
}) }}

The docs have more details on the exact options.


Best location for Craft development? Local or Server? Subfolder of production? What's the best practice for development Craft installations? I think I would like to work on the production web server but in a hidden folder either upstream from my public HTML or as a subfolder.

Does it matter where I install and develop my Craft site? Looking for easy migration when I want to go live.

The best way to do it would be to develop locally, ideally managed with a version control system like Git and then push your site to your server. Craft handles a multi-environment workflow very well.

From the Craft docs on Mult-Environment configs

A good screencast from Straight Up Craft

There are also several questions and answers dealing with this topic in Stack Exchange here.


Checking the link type from a LinkIt field returns the whole path I'm doing a project in Craft 3, there are many types of links so I installed the LinkIt plugin. I'm facing problem with this because I didn't find a method to check link type.

If I use {{ entry.linkItField.typeHandle }} it returns the whole path (e.g. "fruitstudios\linkit\models\Url"), not just category, entry, URL etc.

Also, using {{ entry.linkItField.url }} only works on custom links.

Please have a look at the new docs for the plugin version for craft 3: https://github.com/fruitstudios/craft-linkit/blob/master/README.md#using-linkit

Instead of {{ entry.linkItField.type }} you should use {{ entry.linkItField.typeHandle }}


Craft v3 gives 500 error on installation... how to get v2 instead I installed Craft v3 on a live server running Debian 10, apache, latest PHP, and Mariadb. My structure is /var/www/html, and everything except for the files in "web" are in the www folder (along with the html folder which holds the public files - tested with an index.html), and then all of the files in "web" are in that html folder. My new user owns all of the files and they are set to 744.

I ran the install in terminal (command line) and it checks for the database, user and password and says everything is successful. Then I go to the link specified to complete installation and get a 500 error. I've worked at this over the past 2 days and have never had any problems like this installing any PHP CMS or framework before. Can you tell if I'm missing something key here or direct me to a clearer set of instructions? I've seen the other posts about this issue and the solutions presented haven't worked for me yet.

I'm also wondering if it's possible or worthwhile to go back to a previous version? I want to recommend and use Craft for a commercial project but I need to be sure I can get past the installation first.

I definitely would not recommend trying to install v2. Craft CMS 3 has many improvements over v2, a strong plugin ecosystem, and it will be supported for significantly longer.

As for your setup issues, this is very likely some kind of a server config issue or Craft config issue. To find out which, we need to look at the error logs.

First, look to see if there are error logs in storage/logs/ (relative to your project root).

If not, then the request isn't even hitting Craft, so it's likely an Apache misconfiguration (usually the server root isn't pointing to the right place or such), and you can get more information by looking at your Apache logs.

If you do see logs there, then open up the web.log and search on [error] to see what the source of the error is. Often it is missing or incorrect database credentials.

c.f.:

Official Craft CMS Tutorial
Zen and the Art of Craft CMS Log File Reading
Setting up a New Craft CMS 3 Project


How do I create a dynamic field on a front-end form with the Sprout Forms plugin? I have a job listing channel. I want to create a form on the front-end that has all the jobs that are created in the channel inside of it. I'm using the Sprout Forms plugin, but when I create a custom plugin that creates a new field type. I get the error that this field isn't meant to be used on the front-end.

Has anyone encountered this situation? Have any recommendations? Or am I going about it all wrong?

Sprout Forms needs to know how a field should render on the front-end. By default it supports several common fields, but you will need to add support for custom fields on your own.  It sounds like you've got your field created and working, so you'll just need to add Sprout Forms front-end field support.

Adding support on the front-end is very similar to how you added support for your field in the Craft control panel. If you want to see several examples of custom fields adding front-end field support for Sprout Forms, take a look at the Sprout Fields plugin.


How can you get an entry type's name from its handle in a template? Each of my entry types have their own template.

The url is something like:

/foo/{entryTypeHandle}

And the route is:

'foo/(?P<routesEntryTypeHandle>[-\w]+)' => 'bar.html'

In the template I can get the section the entry type is in:

{% set section = craft.sections.getSectionById(5) %}

And I can get ALL the entry types:

{% set entryTypes = section.getEntryTypes() %}

And I can get all the entries of that entry type:

{% set entries = craft.entries.section(section).type(routesEntryTypeHandle) %}

But I can't seem to get the entry type's name.

In the Sections Service there's a method called getEntryTypesByHandle but that's not available in the model.

I could get the entry type name from the entries, but that relies on there actually being results, which isn't assured.

{{ entries.first.type.name }}

I must be missing an easier way. Anyone?

A simpler way to do this might be:

{{ entry.type.name }}


Use-case: custom plugin or extended use of entries/categories/tags I have to integrate a jobs feed into our website and I've been digging in the documentation, reading the core's code for a while now, and I am in a dilemma trying to figure out if in out use case I should write a plugin or just try to build everything on top Craft's core types?

It's important to know that each job will belong to a company, and will have a lot of custom settings that apply to each job. I've started developing a plugin for it, based on the Brandon's events plugin, which until now is working fine, however I's still not convinces if I'm doing things rights, since the Elements API is a little under-documented.

The questions that I have now are:

Should I base the Company on the Sections type, if I want the jobs to be translatable?
Should I base the Job on the Entry type, and write custom field types for every custom setting a job has to be translatable? (eg. Benefits and Requirements blocks, Many-to-Many relationships between job's industry, employment type, etc.)
Should I handle the saving of Many-to-Many relationships on my own, or Craft handles these if I choose the right core type?
Should I save all these custom fields a job has in the content table or in a custom table?
I will also import jobs from out ATS system, would it be enough to write a plugin just for this, and integrate all the aforementioned requirements into Craft's code types, without developing a plugin?
I would like to tag every job with the technologies a job requires, and assign custom logos of these technology tags. How would I handle this using a custom plugin, extending the core tags?
The jobs will have an advanced search and filtering based on the Many-to-Many relationships with industries, experience level, employment type; what would be the best approach to achieve this? using custom queries in a plugin with a custom element type or building on top of core types?

I just started using Craft, so I still don't understand 100% the core, that's why I cannot decide which would be the best approach.

I just started using Craft, so I still don't understand 100% the core, that's why I cannot decide which would be the best approach.

Welcome to the community! You're asking a lot here!

Someone more knowledgeable about plugin-development will want to chime in here but in my experience, Craft is quite flexible and can handle a lot of things out of the box, even without writing a plugin. It's awesome when you have to relate content to and from each other, like you're wanting to do here.

I don't quite know all the requirements but if I were spec'ing this job, it sounds like you could do a lot of this by using most of Craft's entry types.

Jobs (section)
Companies (section)
Skills (Category / Source )
Industry (Category / Source)
...

I would deal with ATS import as a separate plugin.

You'd create entries in the Jobs section. Create fields that relate the job back to an entry in the company section as well as categorize it using those categories. Like entries, categories can have custom fields so you can put assets field on a skills category and upload logos so every job that has, say, jQuery in it, could have that logo appear.

Depending on your requirements, your Jobs section could have multiple entry types. So if you have specific fields that need to appear on certain jobs categories and what not, you can do that.

I see Matrix being an MVP here, too. When a regular set of fields doesn't cover what you need (you mentioned "custom settings that apply to each job"), you can mix and match a ton of different combinations with Matrix.

Bottom line: I would play more with Craft before you get into plugin development. If you're new to Craft, how many sites have you built with it before you started plugin development? Is there something that led you to know you actually need to use a plugin or is it just a programmer scratching an itch? (We've all been there!)

When it comes to programming and web design in general, to paraphrase The Matrix, "there is a difference between knowing when to reinvent the wheel and not." That only comes with experience.


Compare Value to Category Title In Template I'm new to Craft and am trying to set up a condition that will compare the value of a category (entry.position).  However, I get this error message:

Object of class Craft\ElementCriteriaModel could not be converted to string

I'm not really sure how to do a textual comparison.  The 'position' field is, in my case, a category.  How would a comparison be achieved?

I've tried this:

{% set entry_pos = entry.position %}
{#   {%  craft.categories.slug('position') %} #}
{{ entry_pos }}

{% if entry.position != 'staff' %}
    {% if entry.UBFUserName != '' %}
        {% set name_var = entry.UBFUserName %}
            {{ craft.aitest.AiTestVariable(name_var) }}
        {% else %}
    {% endif %}
{% endif %}

Your entry_pos is an Element Criteria Model. You want to get the first (and probably only) category from this ElementCriteriaModel, and then compare its title to 'staff':

{% set entry_pos = entry.position.first %}
{% if entry_pos.title == 'staff' %}
  ...
{% endif %}

This will give you an error if there is no entry.position.first, as entry_pos will be null, so you should defend against that somehow. One possility is:

{% if entry_pos and entry_pos.title == 'staff' %} ...

Another is to use twigs useful null-coalescing operator:

{% if (entry_pos.title ?? '') == 'staff' %} ...

With Craft 3, you will use one instead of first, but otherwise everything is the same.


System Status Off Custom Text I'd like a more personalized version of the offline page when the System Status is set to: Off. Is there a way to customize the page and/or change the text?

When the System Status is set to "off", Craft will return a HTTP 503 response, which will then automatically trigger the "503.html" template in craft/app/templates to load, which is what you're seeing by default.

But if you put your own "503.html" in your craft/templates folder, Craft will load that one instead.  Same goes for the other HTTP status codes (400, 403, 404, 500, etc.).


Craft Pro Adding Users no email is sent I am adding new users in Craft Pro, I don't get a chance to specify password, seems its is auto generated but I don't get any email sent to the user I just created. Is there any setting I have missed?

I have setup Gmail in settings >> Email >> Protocol and tested and received test email but doesn't send email when a new user is added.

Any help will be appreciated.

Cheers.

I don't get a chance to specify password, seems its is auto generated but I don't get any email sent to the user I just created.

From the CP, you can't create a password for a user.  They'll receive an email, in which they can click on an activation link and they can set their own password by following the workflow.

There is extra logic in registering a new user from the CP that will detect if Craft can create the user, but not send the email, and the CP will notify you if that is the case.

It sounds like maybe the email is being sent, but caught up in a SPAM filter somewhere.

You can also check through your craft/storage/runtime/logs files to see if any [error] or [warning] entries are getting logged.