Any plugins to add drop down for selecting template? One of my biggest issues with craft so far is having to type out which template file a section is using, I don't understand why we don't have a location to enter all our possible templates, which could then be chosen when creating sections "new pages" etc. Or having craft know which template files exist.

Could this be possible via a plugin, or would the core need to be modified. Having to explain to a client they need to know the name and location of a template file when creating new pages isn't great.

Updated Scenario:

Simple example, say I have news post, and events, and I want an index of both as well as single news post and single events both using different templates. When a client wants to create a new event, they would need to know the name of the template that is used for single events otherwise it would default to index.html if the auto generated entry-template name doesn't exist.

When creating a new entry craft defaults to a news item or I call it a news "post". So to create a new event, I need to create a new section, and then specify the entry-template otherwise it defaults to the name of the section, and if no template exists for that entry template "which ends up being the name of the section" it defaults to the index.html template. Then they still need to assign fields to each section that is created. The assigning fields can be simplified by creating a group say called Single Events, with all the possible fields allowed for that type of section "page" this case being single events...

The only easy solution I can think of is to not use groups at all for fields, and just throw every field into each section, then in the index.html template check for each field and if it exists before displaying it. But what about not wanting to display it or displaying dynamic content based on the entry type news post vs single event vs team members vs resources vs contact forms. A solution to that is creating another field called content type with a drop down for single event, team member, resources, contact form... then in the index.html template check the value of the drop down before determining what is going to be displayed and what isn't.

My whole point is it seems like this could all be simplified by having a drop down to choose a template when creating a section since a section needs to be created so that you can create a new entry that is not a news post, and I also think once you create a new section it should allow you to either start editing that section, or take you to the field selection to add fields to that section, after you save a section it just takes you back to the sections which you then have to click edit entry types to choose which fields are used for that section.

To me it would make more sense to have fields assigned to templates, and sections are just holders for "entries" or what I call pages. Example basic-page.template has a bunch of fields assigned to it. I create a section called about us, and choose basic-page.template after saving the section allow me to start editing the entry for that "section".

Sorry for the wall of text just trying to give some examples and I hope they make sense. Just trying to understand the concept of some of this, I'm getting by but it seems odd not to allow to choose a template that is used unless you are a dev on the project and know exactly the name of the template.

Short answer – no, there isn't any way to add a dropdown for template selection to Sections without modifying the core (which is never a good idea).

Beyond that, its difficult to advice without a brief description on what you're attempting to build. Craft is generally perfect for flexible, modular content and layouts, and what you want to achieve is most likely very doable – but I suspect your approach may be a little misguided.

Sections in Craft are the basic containers for your content, and creating a whole new Section should never be part of the basic editorial workflow.

If the OP provides a little bit more context, I'll try update this answer with a suggested approach.

EDIT:

Your problem is that you're using Singles – one of three possible Section types – as entries in a stream of content (events). This is not a feasible workflow. Singles are meant as one-offs; completely unique bits of content that doesn't fit anywhere else and needs its own, unique field layout and/or template.

Any content that is part of a stream, such as a blog post, news item or event listing should be published as actual entries to either a Channel or a Structure Section (in your case I'd use Channels for both news and events; the latter is only appropriate if you need to nest entries or put them in a specific order).

Using a Channel or Structure means that whatever template you specified when you created the Section will be automatically loaded for all its individual entries, and your client will also not need to re-create the field layout every time they want to publish something.

Obviously, with Craft Personal edition, you're limited to only one Channel – and you specifically need two. You have two options:

Upgrade to Craft Client/Pro. If you want to test it out before purchasing, see this page for info.
Delete the News channel and create a new, generic channel called "Content" or the like. Create two different Entry Types for the channel, called "News" and "Events". This would enable you to create different field layouts for news and event entries. In your channel's entry template, you could then do something like this:

{% if entry.type == 'event' %}
    {% include 'event.html' %}
{% else %}
    {% include 'news.html' %}
{% endif %}

Note that this solution will not really scale well at all, and the editorial workflow would also be subpar compared to having separate channels. I'd strongly recommend the first approach :)

Finally, I'm not familiar with ProcessWire and couldn't advice which is better for your specific project, although your site would be a doozy to set up in Craft – as long as you apply its concepts and tools the way they're meant to be used. Obviously, if you're coming from ProcessWire or any other CMS (like Wordpress or ExpressionEngine) it can take a little time to adapt to a different terminology, toolset and workflow and to absorb platform best practices. I'd advise you to read through the basic docs (they're quite concise) for a better understanding of how Craft manages content, and to give Craft Client or Pro a test run before deciding.


When deleting a user do the entries they created also get deleted? We had an instance where a user deleted an admin and it seemed to delete the content that user had created. Is this currently how Craft works? If so is there a way around that without having to change every entry's author. Or suggestion adding a prompt to warn user of content being deleted and to just suspend them.

Currently, yes, that's how it works.

It's on our list to 1) Add a prompt warning what's about to happen and 2) Add options as to what you want to do with that author's current content (assign to a different user, delete, etc.).

Update:

As of Craft 2.3, when a user's account is deleted you'll be prompted what you want to do with their content.


Assign a category group to a category field via migration I am writing a plugin that sets up Craft in a particular way and have created a category field, but can't figure out how to assign a category group to the field, I have the following:

 protected function createCategoriesField() {

        // Get the field group
        $group = (new \craft\db\Query())
            ->select("id")
            ->from("fieldgroups")
            ->where(["name" => "common"])
            ->one();

        // Get the category group
        $catGroup = Craft::$app->categories->getGroupByHandle("categories");

        // Initialize the field
        $field = new \craft\fields\Categories([
            "groupId" => $group["id"],
            "name" => "Categories",
            "handle" => "categories",
            "selectionLabel" => "Select categories",
            "sources" => $catGroup
        ]);

        // Save the field
        return (Craft::$app->getFields()->saveField($field));
    }

It seems sources is the correct setting, but it accepts 'source keys' which I'm unfamiliar with

Figured it out, the format it expects is 'source' => 'group: <group UID>'

So...

    protected function createCategoriesField() {
        // Get the group
        $group = (new \craft\db\Query())
            ->select("id")
            ->from("fieldgroups")
            ->where(["name" => "common"])
            ->one();

        // Get the category group UID
        $catGroup = Craft::$app->categories->getGroupByHandle("categories")->uid;

        // Initialize the field
        $field = new \craft\fields\Categories([
            "groupId" => $group["id"],
            "name" => "Categories",
            "handle" => "categories",
            "selectionLabel" => "Select categories",
            "source" => "group:" . $catGroup
        ]);

        // Save the field
        return (Craft::$app->getFields()->saveField($field));
    }

This was, and is, going to be a big help with migrations -> https://github.com/markhuot/craftql/blob/master/src/Console/ToolsController.php


"Failed to instantiate component or class" when calling Craft module I created a module with the pluginfactory generator. The module is used for generating a zip file with all the files belonging to a project.

In the composer.json file, I added the following:

"autoload": {
    "psr-4": {
      "zipassetscraft3module\\": "modules/zipassetscraft3module"
    }
  },

in the config/app.php I added:

'modules' => [
      'zip-assets-craft-3-module' => \modules\zipassetscraft3module\ZipAssetsCraft3Module::class,
    ],

In the file controllers/DefaultController.php I added a function called actionDownload() as well as a download() function in the file services/ZipAssetsCraft3ModuleService.php

On the website I have a form with the following url as action: https://default.com/actions/zip-assets-craft-3-module/default/download

When I submit the form, I get an error:

  Invalid Configuration – yii\base\InvalidConfigException Failed to
  instantiate component or class
  "modules\zipassetscraft3module\ZipAssetsCraft3Module".

  Caused by: ReflectionException Class
  modules\zipassetscraft3module\ZipAssetsCraft3Module does not exist

I have dumped the composer autoload, but I don't know why it's not working. Any ideas what I need to change to get this working?

This is the file structure of the module:

So the error message says, there is a class missing, in which file is this class looked for?

I came across the same issue. So how i solved it is to modify the modules array like this and now the module is loading:

return [
    'modules' => [
        'zip-assets-craft-3-module' => [
            'class' => \modules\zipassetscraft3module\ZipAssetsCraft3Module::class,
        ],
    ],
    'bootstrap' => ['zip-assets-craft-3-module'],
];


How can I separate assign user groups and permissions for users? I've been here before Users allocating permissions beyond their own and the only solution offered was to vote for it as a feature request, which I did. But after 7 months there have only been 10 votes for it.

I can't understand how so few people find this a problem.
You need to give someone the ability to add users and put them in a suitable user group, but you then give them a free pass to increase their own access permissions and potentially reduce the access permissions for me the prime admin, this can't be acceptable for any user management system.

I need to have an administrator role that can register users and put them into suitable groups, but not let that person manage the permissions for themselves or others.

The most obvious option is to separate "assign user groups" from "assign user groups and permissions"

Non-admin users cannot change permissions for Admin users.

However, I agree with what you've said on users being able to assign groups and permissions. On practically every site I build, I need the client to be able to assign users to the groups that I created, but not be able to change a new user's permissions manually. This should definitely be separated in to two different options in the control panel.

UPDATE: In 2.6.2996 Craft added this functionality:

The “Assign user groups and permissions” permission has now been
split into “Assign user permissions” and “Assign user groups”, and
the latter now has nested permissions for each of the user groups.
Users with the “Assign user permissions” permission are no longer
allowed to grant new permissions to user accounts that they
themselves don’t already have.


Creating / manage content - how is everybody doing it? I need some ideas for creating content.
It's a bit of a pain the way i have it now.

I tested this: https://nystudio107.com/blog/creating-a-content-builder-in-craft-cms
But i don't really like it because text and images are all over the place in the backend.
If i could combine certain stuff in blocks that i could move around it would be better.
But it seems like this (like in my example image) is not possible (images is a Super Table):

For example here: https://skulltronics.net/phantasialand-hoerspiel-und-videokassetten

I have the audio tape and video tape.
If i want to add the next tape and want it on top or between then i have to move every text and image block if i can't group them.

Then i have the links to the single view of the images. This are not the same images that you see on the pages. They are hi res and a mix of png and jpg.
At the moment a put them in by hand like:

FHD Ansicht

At the moment I'm using %%image1%% in my content and they are replaced by the code in the template.

Problem is if i want to add more i always need to count the rows.

row 1 = %%image1%%, row 2 = %%image2%%...

For example this: https://skulltronics.net/phantasialand-autoaufkleber-und-sticker
Looks like this when creating the entry:

Phantasialand Aufkleber 1978

%%image1%%

Original Größe: 11.8 cm &Oslash;

%%share1%%

Phantasialand Aufkleber 198?

%%image2%%

Original Größe: 20.3 cm Lang

%%share2%%

Phantasialand Aufkleber 198?

%%image3%%

Original Größe: 20.7 cm Lang

%%share3%%

If i now need another sticker in between i can use %%image15%% because that attachment is row 15 after adding it or i need to change them all when editing if i want it in right order.

Also with the nystudio107 way: If you create a image link then you make a text block with

Then comes the attachment and then another text block with just
 ?

So how do others handle/create/manage there content/entries?

This is a simplified example, but this is how I'd approach user-manageable page content, using a content builder. Each content type gets its own block in a matrix field:

Which allows authors to add whichever page content blocks they require, in whatever order they like:

Simply add whatever blocks your design requires.


Craft login redirecting to /web instead of /templates? I've moved my Craft directory to the below:

Templates
Public_Html
Web
etc..
etc..

My previous directory when I installed was:

Public_html > Craft-setup > Web > Templates

Now when I login from the front-end as a user, I get taken to the old directory even though it's empty,

example.com/craft-setup/web/

The actual directory it should be taking me to is

example.com/

As my index.php craft file is in public_html

What is the correct method to update the redirect to go to the correct place?

I can access my site perfectly fine and use it by going to example.com/ i'm assuming my base path is fine as the site loads and functions by going to the domain, so why is the front-end login taking me to the old directory? this is the login form I'm talking about https://docs.craftcms.com/v3/dev/examples/login-form.html

Appreciate any help

I found it, needed to change the SiteURL in .env file.


Filter order by order status I am creating a custom dashboard for delivery guys where I want to show the order list in two divs. One is Pending Orders and second is History.
Basically I want to filter my order list by order status.
Here is code:

{% set pastOrders = craft.commerce.orders.relatedTo({targetElement: currentUser, field: 'deliveryGuy'}).find() %}
{% for order in pastOrders %}
   {{order.id}}
   {{order.orderStatus.name}}
{% endfor %}

I would run two queries and then you could utilise the completed() parameter:
https://craftcommerce.com/docs/craft-commerce-orders#completed

{% set pastOrders = craft.commerce.orders.completed(true).relatedTo({targetElement: currentUser, field: 'deliveryGuy'}).find() %}
{% for order in pastOrders %}
   {{order.id}}
   {{order.orderStatus.name}}
{% endfor %}

{% set pendingOrders = craft.commerce.orders.completed(false).relatedTo({targetElement: currentUser, field: 'deliveryGuy'}).find() %}
{% for order in pendingOrders %}
   {{order.id}}
   {{order.orderStatus.name}}
{% endfor %}


How can I change status of all the entries in a channel to closed? I've looked through all the tables, and I can not find a column for status. I'd like to close all entries in channelId X. Is there a way to bulk edit entries via DB?

Grab all of the entry IDs you want from the craft_entries table, then find the rows matching those IDs in the craft_elements table and set their enabled column to 0 to disable them en masse.


Is there a way to add instructions directly on a entry index screen in the CP? I have structure entries that needs to be in a very specific order, following a pattern of horizontal and vertical images to create the right affect on the front-end. I would love a way that I could remind my client of the instructions for the right order of these entries directly on the entries index screen in the CP, sort of like how you can provide instructions for each field. Are there any plugins that would allow the injection of some instructions into the CP page like this?

I've seen option to that allow you to create entire users manuals or help sections in the CP, but that's not what I'm after. I want something that could go inline on just a single CP page.

Check out this plugin, it allows you to add text (instructions) as a field:

https://github.com/thomasthesecond/EntryInstructions


How can I add headings using the Rich Text field How can I add the functionality for my clients to make text not just bold or italic, but have h2, h3, h4 headings too?

You can modify Craft's default Redactor configs stored in craft/config/redactor or add custom config files to this directory. Then select the config of choice for each rich text field individually in the field settings.

To use "block styles" in the editor, add the formatting button to the toolbar with this config:

{
    buttons: ['formatting', 'bold', 'italic']
}

You can also modify the formatting dropdown, if you want to restrict the block styles available to your client:

{
    formattingTags: ['p', 'h2', 'h3', 'h4']
}

.

Edit:

Just noticed that you already have the button in your toolbar, it's the second one from the left :D


How can I do more complicated queries with an ElementCriteriaModel? I need to join my 3rd party table with a standard ElementCriteriaModel (ECM). I'd like to start with an ordinary ECM, so my plugin will be compatible with any element type which may exist, now or in the future.

By default, an ECM generates a query which joins multiple native tables. According to Brad in this answer...

  ... think of ElementCriteriaModel as an abstraction on top of DbCommand that makes it easy to search for Elements.

My plugin does not have either a custom Field Type or custom Element Type (which means I can't use modifyElementsQuery when retrieving the data).

How can I expand my ECM query to take additional SQL commands into account?

Once you've got your ECM, pass it off to the buildElementsQuery method...

$query = craft()->elements->buildElementsQuery($criteria);

This will convert your ECM into a DbCommand object. From there, you can make further modifications to the query... like adding a join for your 3rd party table.

$query->join('myplugintable myplugintable', 'myplugintable.id = elements.id');
$query->order('myplugintable.mysortcolumn');

return $query->queryAll();


S3 Asset uploading is hanging I have setup a barebones install, and authenticated my bucket using the root user S3 credentials (just for now). Assets do not upload. I read a similar question here where the answer was that the response was being blocked by a firewall. I have tested on other connections and the issue wasn't resolved. Craft support suggested that I could edit some code on craft/app/lib/S3.PHP around line 771 but I'm not sure how to go about solving.

The problem was that Frankfurt and London are not currently supported S3 bucket locations in Craft CMS v2.6.2956. Switching to Ireland solved my issue.


Best practice for naming fields shared across entries in CraftCMS I have a question about best-practice for naming fields; I am creating a craft site for a football club, which include the following:

club name (Global)
team names
player names

These are all plaintext fields. In the interest of being DRY, should I create one 'Name' field for all? Is this problematic - and therefore better to create different fields for each, so I have teamName, playerName, clubName handles etc?

The job of naming something is sometimes the most difficult part of a project! This is pretty subjective, but even though it seems like those three fields would share the same settings and requirements (as mentioned by @Paul Werheul), if it was me I would choose field names like clubName, teamName, and playerName.

This way the field names explicitly state what is expected to be entered or returned in your template.

My very humble two cents!


How to submit custom fields that are added in the right pane to your plugin? I'm making my first Craft plugin.

I have added custom fields to the right of an entry form with the cp.entries.edit.right-pane hook ("Share on..").

But I can't seem to find how to 'transfer' these values to my own plugin and to save them in my own table. The return value of several events I tried (ex. entries.saveEntry) are most of the time an EntryModel which do not include my custom fields.

And I guess making a custom fieldtype is a little overkill?

Thank you!

I think I found the answer, correct me if I'm wrong but you can access your post data in your plugin with:

craft()->request->getPost('fields')

Not sure if this is the recommended way.


Running Craft alongside another CMS on the same domain I've started working with a marketing team for a well established online ecommerce store.

Their site is a custom ecommerce CMS build (handled by another third party), which works well technically, but the marketing team have regularly expressed how difficult it is for them to create visually interesting and engaging pages within the site, as it's geared so much towards ecommerce.

Currently the only options the marketing team have when adding new pages from the ecommerce CMS is a textarea (single column, bold, italic, links) and a single image.

Updating the ecommerce CMS to give the marketing team greater flexibility is currently not an option (due to history and internal politics). This then led to the conversation of running 2 CMS's on the same domain - 1 for handling the ecommerce and 1 for the blog and product specific promotional landing pages. I showed them Craft, and they loved it!

The Question(s)

First off, is running 2 CMS's on the same domain possible / advisable? (I remember hearing Joel Bradbury mention running EE and WP on the same domain at EEUK)

Are there any obvious pitfalls or gotchas?

I'm assuming it would be simple enough to have Craft handle any blogs if set up on a blog URL (eg: domain.com/blogs/blog-post-name).

But what about specific landing pages (eg: domain.com/discount or domain.com/freestuff)? In theory could I create a route from the ecommerce CMS to point to the Craft generated page? Or should all marketing pages live in the same directory (eg: domain.com/marketing/discount or domain.com/marketing/freestuff)?

Ideally I'd also like to be able to dynamically insert product data (prices, images, descriptions, etc) into the blog and landing pages created in Craft from the ecommerce site. I'm assuming hooking a Craft plugin up to the ecommerce API (if there is one) would be the best option to pull in the data? (Or would scraping be an option?) We would also need to mirror the ecommerce navigation on any Craft generated pages.

The end goal is to give the marking team the freedom and flexibility to add interesting and engaging promotion pages, and have them look native and integrated into the main site.

Apologies, I know there's a lot of questions here. And some non-Craft specific, but I'm hoping this is a good place to start my investigation.

Many thanks!

You're asking a loaded question. I don't think there's a wrong answer here but if it were me, you have a couple options.
Addressing the Elephant in the Room
How good of a salesman are you? ;) You mention the e-commerce CMS isn't getting the job done but replacing it is off the table. I've gone down this road before.  Since you've got your team interested in Craft, why not consider Craft Commerce too? I know what you're thinking. It's a tough sell. But then again, so is integrating 2 CMS and making sure things don't break between them. What happens if that 3rd party CMS vendor doesn't "approve" of what you're doing and cuts support?  Not saying it'll happen but like you mentioned... politics has a way of messing with people.
I don't know how much business logic that the current e-commerce solution has that you'd have to replicate or how many products and variations you're dealing with but if anything is up for the challenge, it's Craft and Craft Commerce. Just demoing the seamless integration between the two might be enough for the sales/marketing team. Time is money for them.
If you can't go with Craft Commerce, it really depends on what the other software does and how you integrate the two.
Integrating the Two
I'm assuming both CMS will live on the same physical server? Indeed, Craft could  play alongside the other CMS. That's the easiest option. If it were me, I'd probably setup all new marketing pages within Craft and then link to the actual ordering pages in 3rd party CMS.
By default, most CMS including Craft are going to suck up any request that isn't a static file, query the database, and then return the "virtual" page from the database. The actual page doesn't really exist on the server, so Craft looks for "would-be" 404s. That's basically what the rewrite rules in a .htaccess file does—it tells Apache to send any 404 back to the application (usually index.php).
Why is this important? If you have any flexibility with the 3rd party CMS, I'd "quarantine" it to a folder on the server, like /store/ so any request within that folder (like /store/black-leather-jacket/) would go to the commerce CMS (assuming the CMS is sane and doesn't do something stupid like have absolute URLs).
Craft would handle everything else. You could quarantine "Craft" to a folder, but like you mentioned, any page you create would have a URL like /marketing/black-leather-jacket/demo/ or whatever you decide. That's sub-optimal in my opinion. As far as SEO and flexibility go, you probably want people to hit your marketing/landing pages first. People won't buy if they don't have info.
(And it's probably easier to do a 301 redirect to the already existing pages... you could setup Craft so that if it can't find a file, have it take a look if the page exists in the other CMS and redirect if it does.)
Tapping into the Data
Assuming the e-commerce database design/schema is easy to tap into, I'd write a Craft plugin to grab product data directly from the database, based on whatever parameters you need to feed a Twig template. That's beyond the scope of this question but the dev is relatively straightforward.
Craft is built on Yii, an excellent PHP framework so whatever Yii can do Craft can do as well. Craft also ships with Guzzle which would make it easy to "scrape" the actual page or as Matt P mentions building or tapping into some sort of bridge between the 2 systems.
Speaking of scraping, if the 3rd party e-commmerce solution is a hosted solution, then you might have to set that one up on another domain and let Craft handle the marketing pages. In this case, you might consider something like store.domain.com.
Again, all comes down to what the other e-commerce solution does. Craft is relatively flexible any way you slice it.


Conditional fields based on structure level I have a site that will heavily rely on the structure entry type to allow the client to publish content.

The "1st" level of the structure will always act as a table of contents for its children. The child pages will always contain the actual content (supplied via a matrix field).

- Page A (TOC)
    - Page B (Content)
    - Page C (Content)
        - Page D (Content)
- Page E (TOC)
    - Page F (Content)
    - Page G (Content)
- Page H (TOC)
    - Page I (Content)
- ...

This means that the fields visible in the control panel for level 1 entries need to be different to the fields for level 2 + entries.

Is it possible to have conditional fields based on the structure's level?

This is not possible natively to have conditional fields based on the structure's level. For the same cases as yours, I'm also using different entry types.

Maybe you could consider moving your children to a Channel and link them to their parent using an Entry field + some routing, or using one of the plugins bellow to add a bit of hack, but I would not recommend it at all:

https://plugins.craftcms.com/conditions
https://plugins.craftcms.com/cp-css


How are parent and child categories related in Craft database? I am writing an API which directly connects to Craft database and retrieves data.  I need to get the categories hierarchy.  But I can not find how parent and child categories are related in the database, therefore I can't write an SQL query to retrieve it.
Can anyone help with this?

As of Craft 2 all information about Parent - Child relations are stored in the craft_structureelements table. But it's not like a hierarchy (child has the parent id) so it can be quite confusing at the first moment.
When you take a look into the ElementService you'll see the following how the getChildren() parameter from your ElementCriteriaModel is converted into a Query

if ($criteria->descendantOf)
{
    $query->andWhere(
        array('and',
            'structureelements.lft > :descendantOf_lft',
            'structureelements.rgt < :descendantOf_rgt',
            'structureelements.root = :descendantOf_root'
        ),
        array(
            ':descendantOf_lft'  => $criteria->descendantOf->lft,
            ':descendantOf_rgt'  => $criteria->descendantOf->rgt,
            ':descendantOf_root' => $criteria->descendantOf->root
        )
    );

    if ($criteria->descendantDist)
    {
        $query->andWhere('structureelements.level <= :descendantOf_level',
            array(':descendantOf_level' => $criteria->descendantOf->level + $criteria->descendantDist)
        );
    }
}

The ancestorDist is the level of the child. If you only want to have direct children you can ignore that part. $criteria->descendantOf is actually the BaseElementModel of your current element -> $element->getChildren . $criteria->descendantOf->rgt is the value in craft_structureelements for the certain Id. Imagine element is your current element - your where could be like

WHERE [....] AND (structureelements.lft < element.lft AND structureelements.rgt > element.rgt AND structureelements.root = element.root)

And the getParent() function will be treated with

if ($criteria->ancestorOf)
{
    $query->andWhere(
        array('and',
            'structureelements.lft < :ancestorOf_lft',
            'structureelements.rgt > :ancestorOf_rgt',
            'structureelements.root = :ancestorOf_root'
        ),
        array(
            ':ancestorOf_lft'  => $criteria->ancestorOf->lft,
            ':ancestorOf_rgt'  => $criteria->ancestorOf->rgt,
            ':ancestorOf_root' => $criteria->ancestorOf->root
        )
    );

    if ($criteria->ancestorDist)
    {
        $query->andWhere('structureelements.level >= :ancestorOf_level',
            array(':ancestorOf_level' => $criteria->ancestorOf->level - $criteria->ancestorDist)
        );
    }
}


How to edit a date field in a plugin So I want to edit date type filed on entry save, but I don't know how to format it. It times out on string and don't seem to accept DateTime objects either.

Event::on(
    Elements::class,
    Elements::EVENT_AFTER_SAVE_ELEMENT,
    function(ElementEvent $event) {
        if ($event->element instanceof \craft\elements\Entry) {
            $entry = $event->element;
            if($entry->sectionId == 16){
                $entry->rangeStart = date_create_from_format('d/M/Y:H:i:s', '01/01/2019:19:00:00');
                Craft::$app->elements->saveElement($entry);
            }
        }
});

The problem you have here is you are calling saveElement from EVENT_AFTER_SAVE_ELEMENT which is causing an infinite loop.

You need to set:

$entry->propagating = true;

Before calling the saveElement method.

Dates should be a PHP DateTime class, e.g:

$entry->rangeStart = new \DateTime('2019-04-10 19:00:00');


How can we move a Craft-built website to a new web designer? We have a new website waiting to be published, and we would like to hire a new web design team, who is not a Craft Pro User...Is there anyway to get our website off of Craft or are we stuck with getting our own Pro Account? Please HELP!

The Craft Pro accounts are per domain, not per user. If you want all the features of Craft Pro, you will need your own license. (http://buildwithcraft.com/pricing)


URL Format of a nested structure with 3 or more layers I have a nested Structure with 3 layers like so:

Home
Services

Service A

Sub Service A
Sub Service B

Service B

About Us
Contact

Now I would like the nesting to be reflected in the URL like so:

http://example.com/services/service-a/sub-service-a

I used {parent.slug}/{slug} as the URL Format and this is working for two but not three layers.

How would the correct format look like?

Set the Nested Entries URL format to:

{parent.uri}/{slug}


Trouble with curly braces in Entry URL Format / renderObjectTemplate This works:

{{ craft.entries.section('products').relatedTo(object).first.uri }}/{slug}

However, in this case, I need to use the extended relatedTo property, which includes curly braces:

{{ craft.entries({relatedTo: {targetElement: object, field: 'productConfigs'}}).first.uri }}/{{ object.slug }}

Because of the way renderObjectTemplate replacement seems to happen, the braces get screwed up.

Any way to work around this?

I'd actually rather do this in PHP/plugin if possible, but I'm not sure if a relevant hook/event exists.

It's not documented so I guess not officially supported, but you can use template variables in the URL formats. For example if you had a UrlFormats plugin, you could use something like this:

<?php
namespace Craft;

class UrlFormatsVariable
{
    // Use in the URL Format box:
    //
    //  {{ craft.urlFormats.yourSectionHandle(object) }}
    public function yourSectionHandle($entry)
    {
        // Craft checks the URL format with an array "object" first, to see if there's a {slug},
        // and so whether it should be checked for uniqueness and incremented if necessary.
        if (!$entry || !($entry instanceof EntryModel))
        {
            return '{slug}';
        }

        $relation = craft()->elements->getCriteria(ElementType::Entry)
            ->relatedTo(array(
                'targetElement' => $entry,
                'field'         => 'productConfigs',
            ))->first();

        if (!$relation)
        {
            // throw an exception or default to something
        }

        return $relation->uri.'/'.$entry->slug;
    }
}

Then you can keep your URL Format and Nested URL Format inputs cleaner:

{{ craft.urlFormats.yourSectionHandle(object) }}


BaseController::returnJson & devMode interference While developing an API for a client site I recognized that there was a  tag being returned after our JSON response (generated using BaseController's returnJson method).

I copy & pasted some of the output into The Google and found a reference to the YII_DEBUG constant. I checked the value (true) and assumed it was related to devMode. I turned off devMode for this environment and the extra code went away (and YII_DEBUG===false).

I don't suspect that this extra output is expected while using the returnJson() method but I need to get around this. Can I turn off devMode outside of the config file? I really only want to make an exception when calling this method.

I had the same problem. See Brad's response here to so this without messing with devMode: Console script tags garbling up non-html output (e.g. json) when in devMode

It would be nice if this happened automatically when specifically outputting non-html, though.


Offline update then upload files to server What's the best way to update Craft offline and then upload the files to the server? Reason I'm asking is because my updates often fail because of too low PHP memory and I don't have control over the server to update the minimum value.

This is my process right now:

Backup everything (files + db)
Updating the composer.json file manually to the versions that are shown in the admin panel.
Run 'composer update --no-dev'
Upload vendor directory, composer.json and composer.lock to the server
Refresh admin panel and finish update.

Is this the way to go or am I missing something?

If you're not able to increase your server's memory_limit and/or max_execution_time settings, then your current process is a way to "manually" update Craft 3.

Alternatively, if your server has Composer installed from the command line and you have SSH access, you can perform the composer update locally, then upload your composer.json and composer.lock files, then execute composer install from your project's root.

That method should use less memory than updating from the Control Panel.


Front-End Entry (Guest) saving correct values on error I'm building a Guest Entry Form, and one of the fields is a dropdown. Everything feeds through fine, but if one of the other fields has a validation error, I can save any inputted data with the code as outlined in the Entry Form

<input id="customField" type="text" name="fields[customField]"
{%- if entry is defined %} value="{{ entry.customField }}"{% endif -%}>

But, with the dropdown, I can't get the value to stick, it always defaults to the first option (It's to grab a name title - eg, Mr. Mrs, Miss etc) on an error:

<select name="fields[honorific]">
    {% for honortitle in entry.honorific.options %}
        <option {%- if entry is defined %} value="{{ honortitle.value }}{% endif -%}">{% if entry is defined %}{{ honortitle.value }}</option>
    {% endfor %}
</select>

So, if I've already selected the option at the bottom of the list, how do I get the field to remember what I've selected if there's an error elsewhere?

Thanks, Simon

Digging into a past solution for checkboxes thanks to @bradbell, here's the answer!

 <select name="fields[honorific]">
     {% for honortitle in entry.honorific.options %}
         {% set chosen = false %}

         {% if honortitle.selected %}
             {% set chosen = true %}
         {% endif %}

         <option value="{{ honortitle.value }}"{% if chosen %} selected{% endif %}>{{ honortitle.label }}</option>
    {% endfor %}
 </select>


Has anybody integrated craft with a rewards system? Just wondered if anybody had done anything like this? Perhaps through zapier or a custom inetgration? Customers earning points or discounts through a Craft e-commerce site?

I don't think there's a plugin, but there's numerous jQuery or SaaS products that achieve this.

For a Craft Plugin, you could hook onto the after purchase event and add a set amount of score to a user field.

e.g. if our field was score, after purchase we could add +30 to the score field. Then assign discounts based on the score field. e.g. if $score > 30 assign 30% discount to products.

For integrations, you could easily just listen for the event and send some data via a PUT request to a third-party system.


Standardize Element API requests It occurred to me that in every case I was using Element API, I wanted a standardized way of requesting, as the only thing that needed to change was my transformers.

It seemed helpful to standardize the way the input requests were made, and rely solely on transformers for customization.

Here's what I came up with: https://gist.github.com/timkelty/8de8531df688b6ac08d2da0713b6ff00

This allows you to pass everything through request params, including specifying the transformer class.

Right now it looks for the transformer in the elementapi folder: plugins/elementapi/ElementApi_MyCustomThingTransformer.php

If a full-fledged CRUD API is baked into 3.0, I'm assuming this will be irrelevant by then.


Full url to image transform I'm trying to setup a page where the html will be copied into Mailchimp for a newsletter. The images need to have a full path url. How would I construct the code to provide this? So instead of "/images/something.jpg" it would be "http://domain.com/images/something.jpg".

{% set imageTransform = { width: 520, height: 240 } %}
{% for image in entry.headerPhoto %}
 <img src="{{ image.getUrl(imageTransform) }}"  alt="{{ entry.title }}" style="display:block;" >
{% endfor %}

If there is text inside rich text fields is there any way to output the full url to those images too?

Changing the Settings > Assets > Sources url fixed the problem globally. Thanks for the help, aran.


Looking for a simple way to add/update information records with CraftCMS I'm looking for a simple way to save form data to a database and be able to access that information. I'm not sure if I should use the custom fields or an entry (or a custom table) and if creating a module is the way to go or another easy way to have my form post submit handled with PHP.

I was hoping for a simple example of a module for Craft but I'm not finding it.

For the sake of an example, I'd like to add and edit books in my library:

Book Type:
BookTitle - 50 characters
BookAuthor - 50 characters
BookSummary - 300 characters
Pages - Integer

Thanks.

Based on the information in the comments I'll provide an example how to save elements in Craft. I'll just show an example with an existing element type Entry. You can see how to create a custom element type well documented in the docs

You'll create a new section in your CP and add the required fields to the layout. In your case you'll need title (Booktitle), author (BookAuthor), summary (BookSummary) and pages (Pages)

// get the section and the entrytype
// when you know your section id and entrytype id you don't
// need this. You can get the Ids by looking at the URL in the
// when you edit them
$section = Craft::$app->sections->getSectionByHandle('books');
$entryType = reset($section->getEntryTypes());
// Create an entry
$entry = new Entry([
    'sectionId' => $section->id,
    'typeId' => $entryType->id, // or insert the required type id manually
    'fieldLayoutId' => $entryType->fieldLayoutId,
    'authorId' => 1,
    'title' => 'A cool title of a book',
    'slug' => 'a-cool-title-of-a-book', // <- not required
]);

$entry->setFieldValues([
    'author' => 'Me and Myself',
    'summary' => 'it was awesome',
    'pages' => 9000
]);

// Save the entry
Craft::$app->elements->saveElement($entry);

// in case there is something wrong..
$errors = $entry->getErrors();

When you are going to create your custom element type without a field layout your code could look like this

$book = new Book([
    'title' => 'A cool title of a book',
    'author' => 'Me and Myself',
    'summary' => 'it was awesome',
    'pages' => 9000
]);
// Save the entry
Craft::$app->elements->saveElement($book);

// in case there is something wrong..
$errors = $book->getErrors();


Add Section Name to SEOmatic Title Field I have an index page for a Section which lists out the entries.

As this index template doesn't have a title field associated with it how do I get the Section name in the SEOmatic's SEO Title Source?

So you can do this via Twig as discussed here: https://github.com/nystudio107/craft-seomatic#twig-templating

...but you can also just make an Single for your Index page (this is what I usually do) and all of this will "just work" including the SEO sidebar previews in the CP.


Forcing a / with .htaccess After redirecting a website to https environment I had the difficulty that .php/ was added to the url which resulted in double content. I have been able to get past this mistake but now I need to force a /  on in the end if the url’s does not have that yet.

Example

Domainname.com/example/

and

Domainname.com/example

Are now visible in Google. I want only the one with the /

Current .htaccess is:

DirectoryIndex index.php
ErrorDocument 404 /404.html

RewriteEngine On
### START WWW & HTTPS
# ensure www.
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

# ensure https
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

### END WWW & HTTPS
RewriteBase /
RewriteRule ^([^.?]+[^.?/])$ $1/ [R=301,L]
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^(.*[^/])/?$ /$1.php [QSA,L]

RewriteRule ^index\.php$ / [R=301,L]

#1)externally redirect "/file.php" to "/file"
RewriteCond %{THE_REQUEST} /([^.]+)\.php [NC]
RewriteRule ^ /%1 [NC,L,R]
#2)Internally map "/file" back to "/file.php"
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*?)/?$ /$1.php [NC,L]

I don't think this is particularly Craft CMS specific problem. Just Apache .htaccess rules in general. I would try to search for and answer of Stack Overflow. I have a strong feeling it's been answered there already.

https://stackoverflow.com/questions/7780859/htaccess-rewrite-to-force-trailing-slash-at-the-end


How do I update a Craft website without losing data? I have an existing website built with Craft CMS. I made a few changes locally and now I want to update the 'live' website. The problem is that I added a couple of fields and sections but I can't just replace the live database with the one I am currently working with locally because the content in the live database is more up to date and I don't want to override that content.

So how can I get those new fields and sections in the live/production database without losing any data in said database?

You can always add the fields manually to the live site, works best imo if you made a limited amount of changes.

If you have made a lot of changes, a plugin like Firstborn's Migration Manager could do the trick. I have never used it personally, but it seems to do a lot of great things and uses the built-in migration system of Craft 3. Probably worth to give it a spin. There's also a Craft 2 version.


Freeform error after major update After updating from version 2.x to version 3.x with composer and terminal the plugin delivers this error:

  We’ve detected that both the new 3.x and old 2.x versions of Freeform
  are installed.

But looking in the plugin settings and composer.json, there is only one plugin visible.

How can I get rid of this conflict?

I just figured out what caused the problem.

When changing from freeform 2.x to 3.x one has to change the wording in the composer.json from "solspace/craft3-freeform" to "solspace/craft-freeform" (delete the "3".


Use Globals in email templates I’ve set up a few email notifications to be sent to customers, and in the corresponding email templates I’d like to use content from Global fields I’ve created.

But when I use the regular variable {{ globalSetHandle.fieldHandle }} nothing is outputted in the emails.

Does that means that we can’t use Globals inside email templates?

Thanks!

They aren't loaded into the twig template global scope but you can access them with:

https://craftcms.com/docs/templating/craft.globals#getSetByHandle


Trouble loading custom element action (menu option) How do you load a custom element action using getAvailableActions inside my Element Type class?

public function getAvailableActions($source = null)
{
    $customAction = craft()->elements->getAction('Custom');

    $customAction->setParams(array(
        'label' => Craft::t('Custom'),
    ));

    $actions[] = $customAction;
}

The above renders a PHP error PHP Fatal error: Call to a member function setParams() on a non-object

PluginName_CustomElementAction is my file inside the elementactions folder, inside my plugin. Which is copied directly from https://craftcms.com/docs/plugins/element-actions

Here's what it looks like:

namespace Craft;
class PluginName_CustomElementAction extends BaseElementAction
{
    public function getName()
    {
        return Craft::t('Custom');
    }

    public function isDestructive()
    {
        return true;
    }

    public function performAction(ElementCriteriaModel $criteria)
    {
        // Remove all the ingredients from the selected elements
        $elements = $criteria->find();

        foreach ($elements as $element)
        {
            craft()->cocktailRecipes->removeAllIngredientsFromElement($element);
        }

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

What is wrong with my getAvailableActions object?

I think your issue may be that the ElementsService getAction method expects the full classname for your custom ElementAction (sans the "ElementAction" suffix), i.e.

$customAction = craft()->elements->getAction('PluginName_Custom');


Multi sites: should I use Craft 2 locales, or go with Craft 3 alpha? I have a couple of imminent projects that will need some type of multi-site support. One is a large project that will need to share data between at least 3 sites. Where data is entered in one site and displayed on all. I've setup many sites in EE with MSM so I'm familiar with that method but never done this with Craft. I have read a few articles about how to set this up using the local function and modifying core files. I've also read about how this will be built into Craft 3.

So my question is - what route would any of you recommend taking? If I use the locale method will that the work be invalidated when Craft 3 comes out? Or is it advisable to go with the Craft 3 alpha hoping it's stable enough for production? I'm not sure when it will be released or if plugins will be compatible.

Brandon has stated (on the CraftCMS Slack channel, so, sadly, not easily linkable here) that custom locales will automatically translate to sites when upgrading from Craft 2 to Craft 3.

At this point, Craft 3 is still in developer preview and not recommended for production sites, so I would recommend developing in Craft 2 and updating when a stable, final version of Craft 3 is released, along with any compatible versions of plugins that you need for the site(s).

Due to the changes in Craft 3 (many of which are still in flux) plugins will need to be re-written to be compatible with it. Depending on the developer and the complexity of the plugin, this may take some time.


POSTing data into Craft I have a site set up that uses Craft as a CMS only, not used to display templates, as this is handled by React JS separately.

My site is set up so that Craft responds on /api.

I cannot for the life of me figure out how to POST data into a section!

I have a route set up, so my routes file is like:

return array(
    'post-message' => array(
        'action' => 'entries/saveEntry',
        'sectionId' => 13,
    ),
);

I am trying to test this using Rested app, posting a couple of fields into my section, but it doesn't do anything.

Rested is pointing to /api/post-message using a POST request.

I can't find any documentation that tutors a developer on how to post data into a section, so I'm completely stuck here.

If you don't want to get into plugin controllers and actions you can replicate this format here: https://craftcms.com/docs/templating/entry-form

And trick Craft into believing your data comes from an entry form.


How do I set the user password when using saveUser service method? I am saving users from an external source and able to create them in the Craft db as users. However, each user's password is set to null despite setting it on the user model prior to saving it. Is there a way to handle setting passwords during user creation? I am not requiring email verification.

foreach ($docs as $doc) {

    $user = new UserModel;

    $user->firstName    = $doc->FName;
    $user->lastName     = $doc->LName;
    $user->password     = '123456';
    $user->email        = $doc->Email;
    $user->username     = $doc->Email;

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

    if ($wasSaved) {
        $was_assigned = craft()->userGroups->assignUserToGroups($user->id, array(1));
    } else {
        printf("couldn't save: %s", $user->email);
    }

}

Use newPassword instead:

$user->newPassword = '123456';


Session destroy due to inactivity? It seems that after x amount of time (somewhere between 30-60 mins?) of inactivity on a page the session is being destroyed/cleared/etc.

I will sit on a page with an active session for an hour and make 0 calls to the PHP. The next time I make a call to my PHP the session is completely gone. I have 0 variables in my session. I'm logging in the beforeAction and the session is just an empty array.

I thought it was my custom code that was clearing the session accidentally but before my code even executes the session is gone which leads me to believe it has something to do with Craft bootstrapping up to receive the PHP request.

You're likely running into Craft's userSessionDuration config setting.  It defaults to one hour and will automatically log you out (thereby destroying your session) after reaching that period of inactivity.


How can I get the cart total item? I tried using a “length” filter but it’s not working with that I am using the craft commerce plugin and I want to fetch total qty of the cart items. I have tried the length filter but its not working. Is there any other filter that can help in it?

You can use the totalQty method to fetch total items from the cart. It’s a predefined method in the commerce plugin to get total items. Also you can find other methods like this in the documentation of the craft commerce plugin.
Right now for your answer use below totalQty method to get total item count.
{{ craft.commerce.carts.cart.totalQty }}


Using user-selectable timezones to show localized post dates In my user profiles, I have a text field where the user's timezone is set, in the standard America/New_York format.

Craft's timezone is set to New York, and the server's timezone is set to UTC.

I'm trying to use the Twig date filter to localize the times using the user profile timezone field, but it doesn't seem to be working.

For example:

{{ message.postDate | date('n/d/Y g:ia') }} outputs 12/11/2016 1:00pm

I'm hoping that for a user in the pacific timezone, this time will display as 10:00am. But this is what happens:

{{ currentUser.userTimezone }} outputs America/Los_Angeles

{{ message.postDate | date('n/d/Y g:ia', currentUser.userTimezone) }} still outputs 12/11/2016 1:00pm

I've also tried just hard-coding a different timezone in, to no avail:

{{ message.postDate | date('n/d/Y g:ia', 'America/Los_Angeles') }} still outputs 12/11/2016 1:00pm

Am I doing something wrong? Or is there a different way to do this?

It is possible to work around the Craft 2 bug, by converting the Craft DateTime object to a native one.

{% set craftDateTime = entry.postDate %}
{% set nativeDateTime = date(craftDateTime|date('c')) %}

{{ nativeDateTime|date('n/d/Y g:ia', 'America/Los_Angeles') }}


Can't login after restoring production DB locally I'm attempting to restore a postgres DB backup on to my local dev environment but I encounter an error when trying to login as the admin user (the salient parts being):

SQLSTATE[23502]: Not null violation: 7 ERROR:  null value in column "id" violates not-null constraint

and

The SQL being executed was: INSERT INTO "sessions"

So it seems as though it correctly authenticates my username and password and then tries to create a new entry in the sessions table but fails to do so because the session service is returning a null value.

Is this interpretation correct?

I'm using redis for my session storage, so I tried clearing the keys from there but it doesn't fix the issue.

I'm really blocked on this one and would appreciate any thoughts!

kind regards,

piaras hoban

The id primary key column in the sessions table (and nearly all Craft tables) is set to be auto-incrementing (if you're on MySQL).  It should look something like:

CREATE TABLE `sessions`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userId` int(11) NOT NULL,
  `token` char(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `dateCreated` datetime(0) NOT NULL,
  `dateUpdated` datetime(0) NOT NULL,
  `uid` char(36) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `sessions_uid_idx`(`uid`) USING BTREE,
  INDEX `sessions_token_idx`(`token`) USING BTREE,
  INDEX `sessions_dateUpdated_idx`(`dateUpdated`) USING BTREE,
  INDEX `sessions_userId_idx`(`userId`) USING BTREE,
  CONSTRAINT `sessions_userId_fk` FOREIGN KEY (`userId`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

It sounds to me like that table is missing it's AUTO_INCREMENT on the id column.  Craft assumes it's there and that the database will automatically insert it.


frontend account edits I have an account page for all my users, however i'm running into a small issue with being able to update passwords / emails on the frontend. Any advice on how to do this? I read that updating either of those fields would require checking and verifying the change in your email.

Thanks

A user changing sensitive fields like passwords and email addresses requires a "elevated session" to do so, which requires them to enter their current password.

You can see the template code to do that here for both Craft 2 and 3: https://craftcms.stackexchange.com/a/4715/57

You can configure the duration of the elevated session with the elevatedSessionDuration config setting.


How can I use the Courier plugin to notify a user when an entry is enabled? Moderation scenario:

Registered user publishes an entry using a front-end form that sets the entry to disabled.
Moderator receives email re new entry and changes status from disabled to enabled in the CP.
User receives email informing them that the entry has been enabled.

I’ve got steps 2 & 3 working using both the Courier & Postmaster plugins independently. However, when the user edits their entry via another front-end-form, they also receive an email notification.

How can the user be notified only when the entry has been edited and the entry's status has been changed from disabled to enabled?

Courier blueprints:

Step 2: Triggers: entries.onSaveEntry and Conditions: {{ entry.sectionId == '3' and isNewEntry ? 'true' : 'false' }}

Step 3: Triggers: entries.onSaveEntry and Conditions: {{ entry.sectionId == '3' ? 'true' : 'false' }}

In your Courier Blueprint listen to entry.beforeSaveEntry events and use this code for the Trigger Condition:

{% set oldEntry = craft.entries({
    id: entry.id,
    status: null,
}).first() %}

{%- set wasDisabled = oldEntry.status == 'disabled' %}
{%- set isEnabled = entry.status == 'live' %}

{{- wasDisabled and isEnabled ? 'true' : 'false' }}


Using elements-api, how do i create a geojson structure with Features within a FeatureCollections I am trying to output, from a single request, a geojson structure like so:

    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "properties": {},
            "geometry": {
                "type": "MultiLineString",
                "coordinates": [
                    [
                        [-1.102108, 52.671813],
                        [-1.142189,52.620366]
                    ],
                    [
                        [-1.102108, 52.671813],
                        [-1.447277, 52.939653]
                    ],
                    [
                        [-1.102108, 52.671813],
                        [-1.447277, 52.914816]
                    ],
                    [
                        [-1.102108, 52.671813],
                        [-1.884783, 52.509112]
                    ]
                ]
            }
        },
        {
            "type": "Feature",
            "properties": {},
            "geometry": {
                "type": "MultiPoint",
                "coordinates": [
                    [-1.102108, 52.671813],
                    [-1.142189, 52.620366],
                    [-1.447277, 52.939653],
                    [-1.447277, 52.914816],
                    [-1.884783, 52.509112]
                ]
            }
        }
    ]

I have the multilinestring part sorted, and i know how to get the data for the multipoint part, bit i cant find a way, from the single elements api endpoint, how to add the multipoint feature onto the end of the returned array / json.

Here is my elements api endpoint :

    'geojson' => function() {

        function getCoordinates(UserModel $user){
            $return = array();
            foreach ($user->connections as $connection) {
                $return[] = array(array($user->longitude,$user->latitude),array($connection->longitude,$connection->latitude));
            }
            return $return;
        }

        return [
            'elementType' => ElementType::User,
            'paginate' => false,
            'transformer' => function(UserModel $user) {
                return [
                        "type" => "Feature",
                        "geometry" => array("type" => "MultiLineString", "coordinates" => getCoordinates($user)),
                        "properties" => array("name" => "Test")
                ];
            },
        ];
    },

I know i can probably do this using two requests, but i want to do it in one.

If anyone stumbles onto this, i gave up looking for a solution and created my own plugin, to get you started, someone else with the same problem posted some sample code here that returns json from a db query : With Element API, can I combine two entry types into a JSON object, keyed by type?


How can I change CP language in Craft 3 after installation? I saw how I can change system language (CP) after installation in Craft 2, but I can't find how to do it in Craft 3.

The language of CP depends on user. Therefore, you have to set Users -> admin -> Preferences and set prefered language.


Help with tags input field on a front-end entry form I need to make a "keywords" field on a front-end entry form that can create tags in the cms (Craft 2).  I am fully aware of existing tickets regarding this issue like Brandon Kelly's but they're a little too ambiguous for me.

This is the classic tag field where you type a word, press spacebar, and a new tag appears, etc.  I am aware that when my form submits, despite what's visual on the page, the submitted html needs to look something like this:

<input type="hidden" name="fields[fieldName]">
<input type="hidden" name="fields[fieldName][]" value="{tag 1 id}">
<input type="hidden" name="fields[fieldName][]" value="{tag 2 id}">
<input type="hidden" name="fields[fieldName][]" value="{tag 3 id}">
// etc

I've looked into many jquery plugins and they don't output this html pattern. Instead, they all basically create a single hidden input field with all your tags entered in the value attribute separated by commas like value="tag1, tag2, tag3, etc", (tag-it is one exception but it is outdated, buggy, and it always prints the tag's text in the value).

I'm not entirely sure how this all should work, but I'm guessing I need to write custom ajax so that when a tag is created, an ajax call uses the createTag action to create the tag in the database before the form submits, since the saveEntry form submission itself won't create the tag but merely link an existing tag to that entry.

Then, just as it's shown in Brandon's original answer, my js adds the hidden input formatted correctly in the successful response. If the user deletes a tag, I have to use the jquery plugin's removeTag callback (or whatever the callback is) to then remove that hidden input.

However, where I'm getting confused is on these points:

When a user deletes a tag on the front-end (let's say they made a typo), the js deletes the hidden input in the html, but the tag is already created in the database. Do I need to then somehow delete that tag in the database via ajax or just let my db rack up a bunch of unusable tags?
Is it better to just do away with the hidden input approach, use a plugin to accept the comma-separated tags from one hidden input and do all the creating/checking for existing tags/etc on a entries.onBeforeSaveEntry as Ben seems to suggest in this ticket?

Can anyone offer up actual examples of what they did to handle tags on the front end? Maybe also some suggestions of solid jquery plugins in 2018 (many seem janky and not up to date)?  And is my process of thinking outlined above incorrect in any way (I have very little idea what I'm doing)?

Current examples online are either for listing out existing tags the user can choose from with checkboxes or a multiselect (which is usually not the case on a form), or just showing some basic ajax. Any help and clarification would be greatly appreciated (and hopefully help someone else down the line).

First of all generally it's a really good idea to check how Pixel and Tonic has handled all the things. I know many people tend to dislike this hint but it's the best thing you can do. The developers are really good, they make good and useful comments and - at least for Craft 3 - they take care of the PHP Doc (in Craft 2 too but not as well)

When I run into issues/trouble the first thing I usually do is do dig into the well documented source code and check what they did.
As far as I can see in your question you already started to do that too which is great.

Maybe I'm just too paranoid but you should never delete or insert something without checking it and of course you should not leave tags in your DB either. Your page could become slow if you don't remove them. The best thing to do: check if the tag is used in your controller and delete it if it has no relations/uses after the jQuery remove callback. That leads me to my next hint: many people try to avoid a custom controller but mostly it's so much easier to use Crafts/Yiis power instead of trying to avoid work.

Like you already stated you could spend multiple hours to search for a good jQuery plugin to avoid 2-3 lines of php code or you can just extend the EntriesController, copy the save function and include a few lines to deserialize the tag input. I don't really use jQuery (only angular) so I can't suggest you a plugin for that but as soon as you create a custom controller you are free enough to use the plugin you like and not the one that avoids php.

However - what I would suggest is the following.

Find a jQuery plugin that has the following callbacks afterInsert to upload the tag via ajax, afterRemove so you can delete tags and maybe something that allows autocomplete
Create a function to search for tags in your controller, this is for autocomplete. You'll want to return an array of possible tags that match your users input
Create a saveTag function in your controller, check if the tag already exists, if so return the ID if not create a new one and return the ID. If the tag is created via autocomplete you won't need an additional Ajax request since you'll fetch the ID with the tag name
Insert the ID in a hidden input
Create a deleteTag function and check if the tag is used somewhere. This part is mostly copy paste. You want to take a look how Pixel and Tonic did it and copy the functionality with minor changes here and there to fit your needs
Copy the entries save function and insert it in your controller. At the beginning of this function you could explode the single, comma sparated hidden input into an array and that's basically it.

That's the way I handled it the last time - only with angularjs instead of jQuery


How do I "register" a service in a Craft 3 plugin? In Craft 2, services were auto-loaded when using the craft()->plugin_serviceName->myMethodName() signature, but it seems like there's a catch in Craft 3, when using the new MyPlugin::getInstance()->myServiceName->myMethod().

I'm working on a business-logic plugin using a local path repository in my project's composer.json, and there are a rash of problems that come of this, mainly to do with creating + renaming services, as the service locator seems to cache them pretty aggressively.

How can I ensure these changes are picked up right away?

It turns out there's a handy method for manually registering your services, or in Yii2 parlance, just "components":

namespace example\myplugin;

use example\myplugin\services\Example as ExampleService;

use Craft;
use craft\base\Plugin as BasePlugin;

class MyPlugin extends BasePlugin
{
    public static $plugin;

    public function init()
    {
        parent::init();
        self::$plugin = $this;

        $this->setComponents([
            'example' => ExampleService::class
        ]);
    }
}

Then, somewhere else in your plugin, your service is immediately available as:

MyPlugin::$plugin->example->myMethod();

…where example is the key in the hash of classes you passed to $this->setComponents().


Bulk moving asset folders, from one source to another I'm moving all of my assets from a local folder to Amazon S3. I've got my S3 source all set up, and I've been migrating folders over to it by dragging & dropping.

The problem is, I have thousands of asset folders. I did the math, and it'll take me 4+ hours to drag & drop each of them.

Is there some way to bulk move asset folders?

If it's not possible in the CP, I'm open to plugin suggestions as well.

I did this with grunt, using the grunt-aws-s3 task. It worked beautifully. If you are a gulp person, I'm sure there is something similar for gulp.


How do I set the value of a custom entries order field from a plugin? I'm trying to set the value of a custom field on an order when saving an entry. I found an example of how to do this for a simple text field, but the field I'm trying to set is an entries field, not just a text field. I've attempted to set the value using the following code in my entries.saveEntry event. I'm assuming I'm doing this wrong since this is an entries field, not a simple text field, but I don't know the syntax for setting content on an entries field.

$cart = craft()->commerce_cart->getCart();
$cart->setContentFromPost(['entriesFieldHandle' => $entry->id]);

I was close. I was correct in assuming my syntax was incorrect for setting the value of an entries field.

Since an entries field is an array of elements, not just a single element, I just needed to set the value of the field as an array instead of a string.

Changing

$cart->setContentFromPost(['entriesFieldHandle' => $entry->id]);

to

$cart->setContentFromPost(['entriesFieldHandle' => [$entry->id]]);

seemed to do the trick.

To zoom in a little more, the value needs to be set with 'entriesFieldHandle' => [$entry->id] instead of 'entriesFieldHandle' => $entry->id.


Element API Fetch Entries URL Within Matrix I have a matrix with a field to set a Entries URL. Unfortunately the entry is not being returned, only an empty object.

Here are my field settings below and element api code.

See below for the response within the json. I get an empty object?

Why is no data coming through?

I'm fetching the data within a function like so:

Here is the code from my Element API:

function panelsMatrix($array) {
    $panelBlocks = [];
    foreach ($array as $block) {
        switch ($block->type->handle) {
            case 'panel':
                $panelBlocks[] = [
                    'heading' => (string) $block->heading,
                    'text' => (string) $block->text,
                    'image' => $block->image[0]->url,
                    'imagePosition' => $block->imagePosition,
                    'textBaseColour' => $block->textBaseColour,
                    'textHorizontalAlignment' => $block->textHorizontalAlignment,
                    'textVerticalAlignment' => $block->textVerticalAlignment,
                    'imageOffsetX' =>$block->imageOffsetX,
                    'imageOffsetY' =>$block->imageOffsetY,
                    'backgroundColour' => $block->backgroundColour,
                    'subPageDirect' => $block->subPageDirect->first()
                ];
            break;
        }
    }
    return $panelBlocks;
}

That's because you don't actually fetch the entry. In order to receive the entry you have to execute your ElementCriteriaModel with first() or find() otherwise Craft tries to json encode a query

 $block->subPageDirect->first()

You should read the docs about relations and the Element Criteria Model

Btw stack exchange has a wonderful syntax highlighting please add your code directly the next time and not in a screenshot

Edit:

function panelsMatrix($array) {
    $panelBlocks = [];
    foreach ($array as $block) {
        switch ($block->type->handle) {
            case 'panel':
                $relatedEntries =  $block->subPageDirect->first();
                $attributes = $relatedEntries? $relatedEntries->getAttributes() : [];

                $panelBlocks[] = [
                    'heading' => (string) $block->heading,
                    'text' => (string) $block->text,
                    'image' => $block->image[0]->url,
                    'imagePosition' => $block->imagePosition,
                    'textBaseColour' => $block->textBaseColour,
                    'textHorizontalAlignment' => $block->textHorizontalAlignment,
                    'textVerticalAlignment' => $block->textVerticalAlignment,
                    'imageOffsetX' =>$block->imageOffsetX,
                    'imageOffsetY' =>$block->imageOffsetY,
                    'backgroundColour' => $block->backgroundColour,
                    'subPageDirect' => $attributes
                ];
            break;
        }
    }
    return $panelBlocks;
}


How to get current locale in the controller I'm struggling to get current locale code from the controller, I would use craft.locale in the template, but craft()->locale does not do the trick.

Any help would be appreciated.

craft.locale from a template goes to the locale() method of the CraftVariable class, which just calls craft()->language from PHP, which you could use.


MySQL 5.6 backup to MySQL 5.7... what to do I just changed my db server, and I managed to import a db dump to the new system.
What troubles me is that, once done, I noticed I have now MySQL 5.7.32, while the previous database server was 5.6.48.
I checked the project from the browser and so far it seems to work as expected, without errors.
Should I care about this? Was I supposed to somehow migrate the dump before actually load it?
I searched Craft CMS docs but I did not find any detail on this.
Thanks in advance!

You're fine. An export and subsequent import would have highlighted any incompatibilities.
Different story going to MySQL 8 though, that was a whole world of pain last time I tried it. Yii may have been updated since then, though.


Help understanding hooks I need to build a plugin or module that hooks into the Sprout form upload file function so I can add text programmatically to the user uploaded filename.  I've had input before that I should work with the hooks that Sprout provides.  However, I am newish to how Craft 3 functions and I am not familiar with how hooks work.  Can anyone please direct me to any tutorials or education sources that explain how hooks work?  Are they a basic, inherent process of plugin development?  I've only been able to find a tiny bit of documentation on hooks regarding Craft 2.

First I think it helps to clear up some terminology... I've seen a few devs (myself included sometimes!) using the word "hooks" when they really mean "events". For me at least this is a hangover from Craft 2 (and also ExpressionEngine), where "hooks" were used to inject custom back end code.
In Craft 3 however, everything is driven by events. Plugins/modules listen for these events and take action accordingly. ("Hooks" in Craft 3 are something different - more specifically, "Template Hooks" simply give you a chance to alter Craft's control panel templates and inject your own front end code).
Craft and the underlying Yii framework both fire hundreds of different events before and after every conceivable thing that happens, and likewise, plugins can do the same.
So to code a plugin/module that listens for events from Sprout Forms, you'd approach this in exactly the same way as a regular Craft plugin/module. Here's the general syntax for listening to Sprout's events: https://sprout.barrelstrengthdesign.com/docs/forms/events-and-hooks.html#events - in your case you'd probably want to listen for Sprout's EVENT_BEFORE_SAVE event and amend the POST data accordingly.


Output image in template I am new to Craft CMS. I am building my first industrial design portfolio site and am facing a brick wall.. The problem is that I have three image handlers that I set up in field. thumbnail, projectBanner and projectThumbnail that I want to display in project section. I found this code snippet and made changes to it to match one of my image handler.

{% for asset in entry.projectBanner %}
    <img src="{{ asset.getUrl(thumb) }}" alt="{{ asset.title }}" />
{% endfor %}

I made sure that I have upload the image (projectBanner) to a entry and refreshed the browser. The image does not show up but the title does. Could anyone please tell me what I did wrong and what the correct method to achieve outputting images into entries?

When you are working with an asset field you are actually looking at the object so you need to call {{asset.url}} in order to actually output the path to the image or whatever asset you are working with.

{% for asset in entry.projectBanner %}

    <img src="{{asset.url}}>

{% endfor %}

As some additional information I would checkout eager-loading in craft as it can drastically help performance as your website grows!

https://craftcms.com/docs/templating/eager-loading-elements


Filter entries by month I'm trying to make a archive page for a blog sorted by months. I tried to consult the solution from Linking and showing archive by month, but I can't get it to work like it should. The code I have now just displays all entries regardless of their post date.

{% set catch = year ~ '-' ~ month ~ '-01' %}
{% set firstDay = catch | date_modify('first day of ', month ~ year ~ ' 00:00:00') %}
{% set lastDay = catch | date_modify('last day of ', month ~ year ~ ' 23:59:59') %}
{% set archive  = craft.entries.section('blog').postDate('and', '>= ' ~ firstDay.date, '<= ' ~ lastDay.date) %}
{% for entry in archive %}

{{ entry.title }}

{% endfor %}

I had to add ".date" behind "firstDay" and "lastDay", or I get an error (Object of class DateTime could not be converted to string) If I remove the "and" from "archive" like this:

{% set archive  = craft.entries.section('blog').postDate('>= ' ~ firstDay.date, '<= ' ~ lastDay.date) %}

then it sorts my entries according to "firstDay", but completely ignores "lastDay". I tried to threw an and into the middle of the string, but that didn't to anything.

I also tried to use .after and .before, but then I just get what seems like a random set of entries...

{% set archive = craft.entries.section('blog').limit(null).after(firstDay).before(lastDay) %}

The value you need to set the postDate parameter to is quite complex. If you define a dedicated variable for it, it makes the code more readable and you can more easily debug the value using the dump() function.

For the problem itself, you were on the right track. The main problem is a syntax mistake, you are passing in the 'and', '>= ', ... values without wrapping them as an array.

Some other changes I’d suggest is to use the < operator in combination with a relative time of 'first day of next month', so every entry before 00:00 of that day (see documentation of relative date/time formats).

And instead of the .date property, I'd rather use the date filter to output the DateTime object as a string in the right format. Which can be 'Y-m-d' to omit the time completely (Craft sets it back to 00:00), or one of the characters that output a full date with time 'c' or 'U' (see documentation of date format parameter).

{% set firstDay = date(year ~ '-' ~ month ~ '-01') %}
{% set lastDay = firstDay|date_modify('first day of next month') %}

{% set postDateParam = ['and', '>= ' ~ firstDay|date('c'), '< ' ~ lastDay|date('c')] %}

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

{% set archive = craft.entries({
    section: 'blog',
    postDate: postDateParam,
}) %}


Asset file/folder permissions issue Craft seems to create asset files and folders with permissions 775 and 664. My host has restrictions in place to not serve folders/files with these permissions.

Where can I change this?

Of course as soon as I post this, I find the answer.

  /app/etc/config/defaults/general.php

  'defaultFilePermissions' => 0664,

  'defaultFolderPermissions' => 0775,

The default settings are there, I just need to add them to my own config.


Caching and Memory problems. What is best caching method I'm working on a website for a music / artist agency.
On the homepage we need al the artist entries. More than 200.

Each artist profile has an image, an image color extruder picker, some tags, relation, etc etc.

Without caching I have a lot of queries. But the page can render.
If I enable cache, the server runs out of memory sometimes. And when I enable an entry, or edit an entry, the whole cache with the artist loop gets cleared.

This is my code.

{% block content %}
    {% cache for 1 week %}
        {% set cases = craft.entries({
            section: 'artist',
            order: 'title',
            limit: null
        }) %}

                {% for entry in cases %}

                        {% set tags = entry.genre %}
                        {% set agent = entry.agent %}
                        {% set image = entry.introFoto.first() %}

                        ...
                        ...
                        etc etc

                {% endfor %}
    {% endcache %}
{% endblock %}

So can I cache individual entries? Like so? When someone edits an entry, only that entry cache get cleared?

{% block content %}

        {% set cases = craft.entries({
            section: 'artist',
            order: 'title',
            limit: null
        }) %}

            {% for entry in cases %}
                {% cache for 1 week %}

                        {% set tags = entry.genre %}
                        {% set agent = entry.agent %}
                        {% set image = entry.introFoto.first() %}

                        ...
                        ...
                        etc etc

                {% endcache %}
            {% endfor %}

{% endblock %}

Sure. In my experience it's often better to cache individual entries, rather than whole pages, if the entries have a lot of relations to other elements. It's very resource intensive in Craft to figure out for instance if an image or entry relationship exists. And the more relations you have, the more frequent the cache would break.

The project I'm currently working on has a lot of different landing pages with entry items that have a ton of different images and relations. So I have A LOT of this going on for every single entry in a landing page:

{% if article.commentator | length %}
  {% if article.commentator.first().profileImage | length %}
    {% set listImage = article.commentator.first().profileImage.first() %}
    ...
  {% endif %}
{% endif %}

I found that when I cached the whole page, it would break often, resulting in a serious performance hit. I changed my code to cache individual entries. The difference in load of the page as a whole was small, but the actual impact in percieved performance was huge. In a positive way. :)

I also use the same generated HTML on a lot of different pages, so I also made the caching of these items globally. I create a key that is unique for the different options the block could have. The final cache tag looks something like this:

{% cache globally using key ("article-grid-item-" ~ article.id ~ "-" ~ gridType ~ "-" ~ modifier ~ "-" ~ craft.config.environment) for 3 hours unless craft.config.templateCacheDisabled %}
...
{% endcache %}

But the only way to figure out which would be better is to test it on your project. All builds are different, and as far as caching is concerned, there are no simple answers. ;)

And... I also wish P&T would make this easier/less resource consuming: {% if entry.image | length %} :)


Can I "translate" static URL's? I'm wondering if there's some build in function in Craft that can "translate" a URL the same as a string?

For example when I want to translate a static string I'll use the "t" Twig filer like so:

{{ "String"|t }}

Let's say I want to do the same, but with my localized URL's. Imaging this:

{{ url('a-url-slug')|t }}

Then in my translation file I can add different URL's that's localized (but loading the same template, I'm solving this using Routes).

Not sure if this is a good idea, but it does work. You simply got the syntax wrong, it should be:

{{ url('a-url-slug'|t) }}


If user has no access to email how to give them a temp password? In Craft 2.3 admins aren't able to edit users passwords. So I'm wondering if they have no access to email how can we give them a temporary password?

You can "Copy password reset URL" and give it to them via some other means (IM, etc.).


Best way to create tags under new EntryModel? As best I can tell entries have to be created, tags have to be created, a relationship created and then an update to the original entry. Is this correct or is there a simpler way to do this?

There is a similar question here which address how to create a tags but I feel like how to relate the new tag(s) to the entry could use some elaboration.

To relate the tags, all you'd have to do is feed the entry's tag field an array containing tag IDs.

So, after creating (or finding existing) tags, you should end up with an array with one or more tag IDs.

Then, if it's a new entry, you would do:

$myTagIds = array(1,2,3,4); // your tag IDs
$entry = new EntryModel();
$entry->setContentFromPost(array(
    // ...
    'tagFieldHandle' => $myTagIds,
));

craft()->entries->saveEntry($entry);


Greetings - about cookies? I'm not a web developer but I seem to have taken over our business website.

It uses
apnexus
doubleclick and
google analytics

I need to make sure we are prepared for the GDPR and seek consent from any new visitor.

Can someone point me in the right direction?  Are these built into all Craft CMS sites?  Will they be updated to follow the new regulations?

thank you ...

As Ryan has said in the comments, there currently isn't a native cookie consent feature within Craft CMS.

You'll need to either install a plugin (Cookie Consent plugin for Craft CMS is good) or use a service like Silk Tide Cookie Consent.

Both options require you to have access to your website via FTP.

For the plugin, you'll upload it to the /craft/plugins/ directory and activate it via the Craft CMS control panel.

The Silk Tide method requires you to add some code between the <head></head> tags.

If you need help with this, there are lots of developers on here (including myself) that can help.


Replace quotes in an array I'm trying to use a charting library within a Craft template.

The chart expects an array of numbers that I'm building up from a table but I'm getting an array of strings instead.

{% set donutData = [] %}
{% for p in block.donutValues %}
    {% set donutData = donutData|merge([
        p.value
    ]) %}
{% endfor %}

and then if I do {{ donutData|json_encode }} I get an array of strings returned that my chart library can't interpret.

value is set to be a number field in the Craft table column so not sure why I'm getting a string returned.

So it seems that even although the Craft field is set to number it doesn't actually define a number.

I changed the field from a regular Craft table field to a Super Table field and my {{ donutData|json_encode }} corrects spits out an array of numbers.


How to get related entries from a Matrix block itself related to another section 3 sections:

Works
Discography
Interpretes

In "Discography"

Matrix block calling entries from "Interpretes"

In "Works"

Relational field pulling entries from "Discography"

In that Work template I need to display the related entry title from Discography (first part of the code below: working) and the related Interpretes selected in Discography (second part of the code: not working)

Is that possible?

{# This first part displays correctly: #}

{% set relatedRecords = craft.entries.section('contenuDiscographie').relatedTo(entry) %}
{% for record in relatedRecords %}

{{ record.title }}

{# And trying to display the related entries from "Interpretes". That's where I'm stuck: #}

    {% for block in entry.compDiscographie %}

        {% set relatedPerformers = craft.entries.section('interpretes').relatedTo(block) %}
        {% for performer in relatedPerformers %}
            {{ performer.title }}
        {% endfor %}

    {% endfor %}

{% endfor %}

Tried to be as clear as possible...
Thanks

You access the wrong variable to get to you "compDiscographie" Matrix field. It should be:

{% for block in record.compDiscographie %}

Another thing to change here is to add the type parameter, as you probably have other Matrix block types in that field (if not, why did you choose Matrix?):

{% for block in record.compDiscographie.type('myPerformersBlockTypeName') %}

Then you should be good. Oh, and you better have that <ul> outside your loop!


How can I populate some records after my plugin is installed? When I install the plugin, I need to automatically create a few records. How can I have my plugin automatically create those records when it is installed?

On the main MyPluginPlugin class, there is a method you can override called onAfterInstall(). Which will run after your plugin is installed.

To create those records, you can place the following code into the method:

public function onAfterInstall()
{
    $record = new MyPlugin_ExampleRecord;
    $record->setAttribute('attributeName', 'value');
    $record->save();

    $record2 = new MyPlugin_ExampleRecord;
    $record2->setAttribute('attributeName', 'value2');
    $record2->save();
}


Execute code before plugins are executed I'm looking for a way to execute some code before the whole system loads, more precisely right before plugins are loaded/executed.

Use case

I want to instanciate a custom object, that I need to interact with in my plugin, but I cannot declare it INSIDE my plugin. This object should actually be available in all plugins if needed.

Where should I put such code so it is reusable ?
Thanks a lot !

You could put that code in index.php, before the require_once line. That’s about as early in the request as you can get ;)


User Registration Form with Sprout Forms I try to implement a User Registration Form with Sprout Forms for hours, but it doesn't work ...

I have replaced the value for the action from "sproutForms/entries/saveEntry" to "users/saveUser".

How should I create the fields (username, password, email, first name, last name), that the user are stored.

In a further step, I will add custom fields for the users.

You don't need to use Sprout Forms to create users on your website. Take a look at the Craft documentation for an example.


Can You Make a Custom Field with multiple columns? I have a custom field where I'm defining AttributeType::Mixed in order to achieve the affect of saving multiple pieces of data for a single field. The data gets stored as JSON as expected. Quick example shown below:

public function defineContentAttribute()
{

    return AttributeType::Mixed;

}

I was wondering though, is it possible to define multiple columns for a single field? If so will the field then require its own table? Not sure where to begin with this one.

Thanks for any assistance.

If your custom field needs more than the default column to store it's data you can create your own custom table (or tables) and store your data however you need to.

This involves a few things:

Create a Record that defines your database table
Save the data to the custom table
Retrieve the data from the custom table

Create a Record that defines your database table

To create a Record, take a look at the Craft Records documentation.  The Record defines the columns in your database table and that custom table will get created when you install your plugin, and removed when you uninstall your plugin. So, after you create your Record, go ahead and re-install your plugin to get the database table to appear in the database and ensure it's the schema you need.

Save the data to the custom table

Now that you have your custom table, you can save data to it.  In your Fieldtype Class CustomPlugin_CustomFieldType.php you can do so using the onAfterElementSave() method.

public function onAfterElementSave()
{
  // $this->element will give you access access to the Element Model
  // your field is associated with (For example, EntryModel, CategoryModel, etc).

  // $this->model will give you access access to the FieldModel
  // your field is associated with.

  // craft()->request->post will give you access to the post data
  // submitted on the request.

  // Once you have retrieved and modified the data you want to save,
  // you can go ahead and save it to your custom table
}

Retrieve the data from the custom table

To populate your field, you'll retrieve your data from your custom tables in the getInputHtml() method.  In the example below, I'm using calling the getCustomFieldValues() method from the service layer which would query the database and give me back the data I need to hand off to my template to display:

public function getInputHtml($name, $value)
{
    $values = craft()->customPlugin->getCustomFieldValues();

    return craft()->templates->render('customplugin/fields/input', array(
        'name'       => $name,
        'values'     => $values
    ));
}


Rotate image according to EXIF orientation not working from a plugin I am using a front-end form to upload images and store them as assets on an amazon S3 bucket.

My server has imagick installed an uses it and in my config I have "rotateImagesOnUploadByExifData" set to true.

When uploading an image I use this code to get the image and store it as an asset:

$file = UploadedFile::getInstanceByName('file');
$tempFilePath = $file->getTempName();
$folder = craft()->assets->findFolder(array(
    'sourceId' => craft()->config->get('assetSourceId', 'myPlugin'),
    'id'       => craft()->config->get('assetFolderId', 'myPlugin')
));

// Turn the file into a managed asset within that folder
$response = craft()->assets->insertFileByLocalPath(
    $tempFilePath,
    $file->getName(),
    $folder->id,
    AssetConflictResolution::KeepBoth
);

Everything is working as expected, an asset is created, files get transferred to Amazon S3 bucket, but when transforming the image it shows rotated.

So I investigated:
The function 'insertFileByLocalPath' calls the function 'insertFileByPath'

In its turn this function performs the following check:

if (IOHelper::getFileKind(IOHelper::getExtension($localFilePath)) == 'image'
            && ImageHelper::isImageManipulatable(IOHelper::getExtension($localFilePath))
)
{
    craft()->images->cleanImage($localFilePath);
}

The cleanImage function should rotate the image and strip the exif data afterwards.

But since these functions work with the temporary file name (which is e.g. "/tmp/phpZB1A8y") this does not pass the test in the previous code. (it is not recognized as an image filename since it has no extension)

Any idea how I could work around this issue?

The best way to do this would be to follow the same flow that Craft does - clean the filename, move to a temporary location, operate from there and afterwards delete the temporary file.

Craft has an example in it's codebase to help you out. Just remember to delete the temp file afterwards.


Find matching asset (image) for category What would be the best approach to have a list of categories (brands in my case.) and if an asset (image) exists that matches that brand name show that asset or instead show a placeholder image.

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

{% endfor %}

I would add the brand category field to the assets field set. This way you can add brands to images and use .relatedTo to find them.

  {% for category in craft.categories.group( 'brands' ) %}
    // This will give you the first image that relates to the category, you could use .find() to get all images and then loop through them.
    {% set image = craft.assets.relatedTo( category ).first() %}

        {% if image|length %}

        {% else %}

        {% endif %}

  {% endfor %}