Craft entries won't save (new or edits) So I am trying to create a new entry, but every time I click save, nothing is actually saved. (see gif)

THINGS I HAVE TRIED:

Overwriting the app folder with a freshly downloaded one (I am already on the latest stable build)
Increasing max_input_vars and post_max_size in my php config

THINGS I HAVE NOTICED

It works if I leave the rich text field blank, or with minimal content (like maybe 2 sentences)
Nothing ever makes it to the database, _entryversions remains unchanged
I don't see anything weird in my log, e.g. no [error] tags

Craft Version: 2.6.2990

Thanks in advance for your help!

For anyone experiencing this issue, what solved it for me was deleting the craft application files and replacing them with the ones from the same release version.

It seems one of them got corrupted at some point.


Order entries based on last string of title I would like to get the last string of a entry title and order entries based on that. Basically the people title are their full names and I am trying to find their last name and filter based on that, instead of their first name.

{% set entries = craft.entries.section('people').order('title').limit(0) %}

similar to this entry.title|split(' ')|last

Another option is to use the Preparse plugin to automatically parse out and store last names in a hidden field.

Install the Preparse plugin
Create a new “Last Name” field using the Preparse field type
Set the field’s Twig template setting to this:

{{ entry.title|split(' ')|last }}

Edit the People section’s entry type settings, and add the Last Name field to its field layout.
Edit the People section’s main settings - just re-save them, so that all of your existing entries get updated.

Now when your People entries are saved, the last word in their Title will be copied over to a hidden “Last Name” field, and you can sort by that in your template:

{% set entries = craft.entries.section('people').order('lastName asc').limit(0) %}


Is it possible to hide certain entries in the Content SEO section of SEO Matic? I would like to "hide" Certain Pages or entries from the Content SEO Section as they are never seen by the end user and are not used in the XML sitemap. Is there a way to do this ?

A Section only appear in Content SEO if it has public URLs. If it has public URLs, that means that Google and users will be able to find it eventually.

There is a setting to disable the sitemap for a section via Content SEO, however.

Can you elaborate on what you're trying to accomplish?

Also we got into detail on sitemaps for a while on the devMode.fm episode SEO for Web Developers: The Silence of the Chickens which might be useful to you.


Minimum database privileges for Craft front-end? I'm wondering if it's possible to reduce the database user privileges required by Craft, to run just the front-end of the site.

Currently, the requirements docs indicate that the MySQL user must have CREATE, ALTER, DROP privileges, etc. This makes sense when using the CP to update content, etc. (or if the site needs to accept user input form submission, member login, etc.)

However, I'd like to disable the CP on the site front-end and create a multi-environment config using a DB connection with a much less privileged MySQL user.

Does Craft require more than basic database 'read' permissions to simply serve up content?

Any reason I couldn't create two subdomains, one for serving content and one for managing content via the CP and provide different DB users (with separate privileges)?

Thanks!

Short answer, no. You'll want to make sure that your DB user has all of the necessary privileges.

Just because you're not entering your data into the database doesn't mean that Craft isn't writing its own data into the database. There are several tables responsible for handling data which is automatically generated by Craft, and not managed directly by admins.

For example:

craft_sessions records user sessions, to know who is currently logged in.
craft_assettransformindex saves any image transforms which have already been triggered.
craft_templatecaches, craft_templatecachecriteria, and craft_templatecacheelements store data from templates which use the {% cache %} tag.

And there are probably others that I'm missing.

Bottom line... Craft needs to be able to write to the database just as much as you do.


Missing Users tab in CMS I seem to be missing the users panel in the CMS. Any idea where it could have gone? For adding new users, groups etc.

Am a bit confused, and new to craft. So, sorry if this is painfully obvious.

Thank-you

Based on your screenshot, you're using the Personal version of Craft, which only allows for one user, which is why you won't see a Users section in the sidebar or the Settings screen. If you upgrade your install to Client or Pro you'll see those Users sections appear

Also worth a note, in Craft 3 and the latest version of Craft 2, the editions have been renamed to Solo and Pro. Solo is just like Personal: only one user allowed, whereas Pro allows for more than one user.


How to get the unverifiedEmail value of a user after a change email request? The currentUser.unverifiedEmail variable, which is public, is always empty on front end even after email change.

I thought it was a bug. I contacted Craft support about this, and here is Brad's answer:

  That's expected behavior... the default UserQuery (which is what {{
  currentUser }} is) only grabs a small subset of columns in it's select
  to avoid exposing potentially sensitive user account information
  throughout the system.
  https://github.com/craftcms/cms/blob/develop/src/elements/db/UserQuery.php#L310-L325

  If you want anything outside of that, you'll have to query for the
  data directly.

I tried this custom query:
{{ craft.users.id(currentUser.id).one().unverifiedEmail }}.
But even after requesting an email change, the value remain empty.

Any idea how to make this query from Twig?

You need to select the value

{% set user = craft.users
    .id(currentUser.id)
    .addSelect(['users.unverifiedEmail'])
    .one()
%}
{{ user.unverifiedEmail }}


Display Stores by Region with relations I need display Stores by Region, by example:

Alabama

Store X
Store Y

Idaho

Store A
Store B

So:

I create two channels Stores and Regions.
In the channel Stores I create a entries field type called storesRegion and check Regions source.

So great! I can create new stores and select where the store is located.

I can display the Regions like this:

{% set relatedRegions = craft.entries.section('regions').relatedTo({
    sourceElement: stores,
    field: 'storesRegion'
}) %}

{% for region in relatedRegions %}
    {{ region }}
{% endfor %}

good but now I need display all the Stores from each Region

this is a good example of what I need: https://www.apple.com/retail/storelist/

this is something related with reverse relations?

You could loop all regions and select their corresponding stores

{# you can as well include eager loading here #}
{% for region in craft.entries.section('regions').storesRegion(':notempty:').all() %}
    {% set storesForRegion = craft.entries.section('stores').relatedTo({
        targetElement: region,
        field: 'storesRegion'
    }).all() %}
    {{ region.title }}
    {% for store in storesForRegion %}
        {{ store.title }}
    {% endfor %}
{% endfor %}

If you want to increase your performance you can use eager loading at this point and include with(['storesRegion']) to your region Query


Craft console app within windows batch script I try to create a simple deployment batch script that would work on windows.

To do that, I need to interact with Craft console app. How do I pass multiple commands to it to perform installation?

I tried this:

(echo mysql && echo localhost)|craft setup

This in theory should answer two first questions that craft console asks during installation. Unfortunetly it just caused console program to be stuck in some kind of loop when first question about the database is repeated infinitely.

In Windows' cmd, commands are joined by two ampersands like you specified (cd foo && dir), however in PowerShell (which Microsoft is pushing to replace cmd), commands are joined by semicolons: cd foo; dir.

Also, it looks like you have an orphan closing parentheses ) in your code. Is that supposed to be there?


Remove Quotes from Text Fields My client needs to input apostrophes in text fields for staff names, such as ’ or just the plain ' and as you can imagine, it is causing issues.

I have tried this replace({'\'',''}) and this replace({'\&rsquo;',''}) but to no success. Thoughts?

As it happens, this solved my issue: {{ personfirstandlastname|replace({'\'':''}) }}

EDIT

To clarify, this isn't a valid Twig object:

{'\'',''}

... while this is:

{'\'':''}


Unable to backup the database or apply migrations I'm running CraftCMS via 3 Docker containers in 1 Docker network:

Container 1 - MySQL
Container 2 - Nginx
Container 3 - PHP:7.4-fpm

When I run php craft update craft from container 3 and choose to backup the db, I get this error:
Backup the database? (yes|no) [yes]:yes
Backing up the database ... error: The shell command "mysqldump --defaults-extra-file="/tmp/hvncbmcornry.cnf" --add-drop-table --comments --create-options --dump-date --no-autocommit --routines --default-character-set=utf8 --set-charset --triggers --no-tablespaces --single-transaction --no-data --result-file="/app/storage/backups/my-site--2021-05-26-052145--v3.6.15.sql" craftcms && mysqldump --defaults-extra-file="/tmp/hvncbmcornry.cnf" --add-drop-table --comments --create-options --dump-date --no-autocommit --routines --default-character-set=utf8 --set-charset --triggers --no-tablespaces --no-create-info --ignore-table=craftcms.assetindexdata --ignore-table=craftcms.assettransformindex --ignore-table=craftcms.sessions --ignore-table=craftcms.templatecaches --ignore-table=craftcms.templatecachequeries --ignore-table=craftcms.templatecacheelements --ignore-table=craftcms.cache --ignore-table=craftcms.templatecachecriteria craftcms >> "/app/storage/backups/my-site--2021-05-26-052145--v3.6.15.sql"" failed with exit code 127: sh: 1: mysqldump: not found

It looks like the mysqldump command doesn't exist in Container 3 as I don't get a result when running: which mysqldump. Running this which command from container 1 does however return: /usr/bin/mysqldump. But in this container, I don't have access to my project.

Sounds like your php-fpm container 3 needs to install the MySQL client tools in it, so that mysqldump is available in the container similar to https://github.com/craftcms/docker/blob/main/7.4/dev.Dockerfile#L18


How can I access or set a Task's properties inside a class or method? How am I able to get or set additional properties on a Task model inside a plugin.
Eventually I would like to influence the Totalsteps of a task.

$task = craft()->tasks->createTask('Reroute', 'Importing routes', array(
    'files' => $files,
    'steps' => count($files)
));

class RerouteTask extends BaseTask
{
    public function getTotalSteps()
    {
        return $this->getSettings()->steps;
    }

Is resulting in Craft\TaskModel.steps is not defined.
What am I missing here?

Have you defined the settings and their type in your Task file?

I've had success using the array of things passed to the task to set the total steps like so:

class RerouteTask extends BaseTask
{

  protected function defineSettings()
  {
    // Files passed from controller
      return array(
        'files' => AttributeType::Mixed,
      );
  }

  public function getTotalSteps()
  {
    return count( $this->getSettings()->files );
  }

Then inside a controller you create the task.

$task = craft()->tasks->createTask('Reroute', 'Importing routes', array(
  'files' => $files
));


if entry has same url segment I have a Structure that has the URL setup like this..

Top-Level Entries - {slug}
Nested Entries - {parent.uri}/{slug}

How do I list all entries that have the same segment1 of their URL as to what is on the current page the user is on.

i.e if I am on page  http://example.com/vacation

I want to list all structure entries that have 'vacation' as the first segment of the URL.

i.e

/vacation/snow
/vacation/coastal

but it would not show any entries from the structure that are like this:

/advice/what-to-bring
/advice/weather-warnings
/contact

So basically I want to do this...

if segment1 = entry url segment1 display entries.

Since you already have an entry in the same structure, the simplest method is probably to use the parent and descendants properties of the EntryModel.

{% set entries = entry.parent.descendants %}

    {% for entry in entries %}

{{ entry.title }}

    {% endfor %}

A more round about way would be to get the segment through craft.request.segment, use that to get the entry, and use descendants to get the children.

{% set segment = craft.request.segment(1) %}
{% set entries = craft.entries.section('myStructureHandle').slug(segment).first.descendants %}

    {% for entry in entries %}

{{ entry.title }}

    {% endfor %}

Or, if you only want the siblings without the current entry, you could use:

{% set entries = entry.siblings %}


How do I configure Varnish to work with Craft? Has anyone successfully used Varnish with a Craft build? I'm trying to set up Varnish on my server but I'm very new at this. Can anyone share their config file or point me in the right direction? We have this build on an EC2 instance and so far it works great but we'd like to optimize it further.

Ok, Carlo, I'll get in this improved answer tonight, anyway, probably cut down and informate the other answer in morning here, so comments stay. I've got a sick animal here house-sitting for brother & family, why I'm a little slow.

To accelerate what you have, it really depends on the content - whether you have logins or other personalization among your high ten-thousands of daily hits. If you don't, it may be possible to get some quick improvement, and then move up through the other things. Throughout this I'm going to be thinking of a big sports site I've seen you have, thinking it may have timely content updates while not personalization; but I don't remember it with assurance on that detail.

Digging into CloudFlare, since you do have it there on EC2, I find I was mistaken about what it does before you may configure it. This also explains some things I thought I saw in earlier brief shakedown tests myself.
With automatic, stock configuration, CloudFlare only edge caches media referred to, like jpgs, js, css etc. -- not html of any kind, to keep things safe for first users. There are three further levels of caching possible, which includes the ability to do whole pages. You use PageRules to enable this, and can for a whole site depending on the match filter. If you don't have personalization, I think you could get a huge benefit right away by setting this up, rather than using Railgun. Or for some pages, anyway? So this is what I'd look into first, if the content fits. CloudFlare doc link here. You can set time to live, so as to have essential static pages which still update regularly if you have timely but not personalized content.
If you have personalization of pages, then you do indeed need server-side caching to rein in such large page demands, I would agree. Railgun working as intended is only going to help with cutting out handshake latency, compressing, and so forth. This is great, but it still requires that you run the (Craft) CMS each time someone requests a page, in order to see if there is a delta Railgun would send.

The next stage then I would think would be to enable Craft's own caching, to cut  Craft's overhead way down, as this is very effective, targetable to what should and shouldn't be cached in your site, and can use EC2's ElastiCache, w/doc link here, to get you memory-resident caching's speed. Craft's /app/etc/config/defaults has scripts for both Redis and Memcache(d) setup, which I think you just copy into your /craft/config folder once the facility is up on your EC2 machine.

With fortune, this could be an easy solution to deal with, again if you need to have personalized or otherwise dynamic content, and you can try it out for gain before any ElastiCache by just turning it on in the file or db modes, for which there are also default scripts in the same location.

I'd read very carefully the information that's in Victor In's link reference, as it gives quite a bit of information straight from Brandon (and with others' interpreting) compared to present doc. I agree with what he says about effectiveness of  using db caching from experience before, as databases tend to have very efficient caching for their own operation, including sorting out high numbers of requests. What he says about the db as basis for the great effectiveness of Craft's detailed cache breaking with content updates is also very astute, and one of those things which makes Craft very intelligent with how it handles your content.

What about Varnish, then? Well, it does look very powerful and proven; also requiring the most detail of any speedup to configure. Setting it up in the first place is simple; you just set your webserver to run on a non-visible port, and tell Varnish where to find it while arranging Varnish to handle your visible standard http and possibly https ports. That installs the engine, as in their pretty good-looking Varnish doc with a kind of guide on this link.

I don't remember if EC2 comes with a C compiler installed, but easy to do, and this will be necessary to compile the VCL scripts you configure Varnish with to know your page requirements. VCL itself? Again, there's good doc, but you are really going to want to know exactly what your pages need, if they need personalized results. This is really about the site design, not anything about Craft itself, and here we are considering the original question directly.

In summary, I think that depending on your content, you have three levels you can go through here to reduce load and increase apparent speed for your site.

If you are so fortunate as to have non-login and otherwise non-personalized content, you can probably do the large arrangement by configuring CloudFlare to actually edge-cache the html pages as well as media content. This will give you essentially static site page speed, also hosted out near many visitors (if you're lucky on CloudFlare sites), plus having off-loaded your page request handling out to those edge sites. Using embedded monitoring may keep you lucky on getting enough access data to satisfy the client.
If your client needs logins or personalization of other kinds, then one of the levels of Craft caching (and selection of what to cache) is going to help a lot. This would really take advantage of Railgun, while feeding it the information it needs very efficiently for your EC2 instance(s). This might be enough, and might see Railgun operating as you'd expect it to reliability-wise. Again, you could start with a file- or db- level Craft cache configuration, and then after working up redis or memcached on a staging server probably, fitting that in for even higher efficiency and speed.
Varnish itself, then. I seem to feel this would be the most effort to configure, but if needed, give the highest effectiveness, if you need to go that far. The configuration itself is about your static vs. dynamic page content design, not Craft itself, so you can use such sources as stackoverflow's varnish tag to get hints or questions answered on it. Here's a link to an interesting start for that, mentioning relationships between varnish and memcached in the frame as I've put some thoughts here. ElastiCache-driven native Craft caching will give you the highest performance for necessary dynamic content here, and it looks like Railgun will improve on Varnish alone, by getting that fast-resolved dynamic content out to the edges in much less time than a standard internet request would do so.

Carlo, hope it's been helpful to have another head looking at this, and that possibly these stages in some form may give you ideas to do a useful rapid response, then refine. Craft community advancing on many fronts at the moment, anyway ;)


Non-default web port I'm running Nginx on port 8888 locally. fastcgi_params is sending SERVER_PORT to PHP-FPM, which I am able to verify with phpinfo() output and craft/storage/runtime/logs/craft.log. I'm also able to navigate all of the admin pages with the port number intact.

Unless I change General Settings > Site URL to include ":8888", I've noticed that all rendered links (homepage, sample "Recent News" block) do not include the different port. I am new to Craft; am I correct to assume that the Site URL must include the port number manually specified, despite the code having getServerPort() in the core code?

Edit: I added the following to general.php:

'siteUrl'  => 'http://'.$_SERVER['SERVER_NAME'].':'.$_SERVER['SERVER_PORT'].'/',

This seems sub-optimal; is there a better way to do this? What do others do who run Craft on ports other than 80/443?

For HTTP the default port is 80 and for HTTPS it's 443,
obviously.
If port is omitted in the site URL, then the default
one is used.
If you want to use a different port, you must
specify a different port in the URL.

So, the logical conclusion is that the port must be present in the URL. When building URLs to entries, for example, the site URL is fetched to generate the final URL. So, unless that URL has port specified in it, you'll get URLs with the wrong port. That's exactly how it should work.

The best way to approach this, however, would be to use Craft multi-environment settings to set it up. That way you won't have to dig into the config files whenever you deploy your site.


SEOMatic using the pages title SEOmatic for some reason isn't picking up any 'Title' fields from the entries, which leaves it displaying '| SiteName' within the browser tab. Currently my 'Site SEO Title' is empty, but can this accept Craft variables to inject the page title?

Have you created a new SEOMatic Meta fieldType?

I don't know whether there is another/better way of doing it, but what I do is create a new field of type SEOMatic Meta, then assign this field to the entry types of the pages you want the title to be made available to SEOMatic. There are all sorts of options within this field, but one of them allows you to select which field the title is pulled from.

More info on the SEOMatic Meta field can be found in the docs.


Foreign key constraint sql error from entries/saveEntry when adding entry I am getting a foreign key constraint sql error when trying to add an entry through a front end form.

<form method="post" accept-charset="UTF-8">
  {{ getCsrfInput() }}
  <input type="hidden" name="action" value="entries/saveEntry">
  <input type="hidden" name="entryId" value="{{ entry.id }}">
  <select name="fields[vendor][]">
    {% for v in craft.entries.section('vendors') %}
      <option value="v.id">{{v.title}}</option>
    {% endfor %}
  </select>
  <input type="submit" value="Submit"/>
</form>

vendor is an Entries fieldtype, for unlimited entries from the vendors channel. Very similar code for adding a category works fine.

The error (complete with back-ticks):

  CDbCommand failed to execute the SQL statement: SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (metro.craft_relations, CONSTRAINT craft_relations_targetId_fk FOREIGN KEY (targetId) REFERENCES craft_elements (id) ON DELETE CASCADE). The SQL statement executed was: INSERT INTO craft_relations (fieldId, sourceId, sourceLocale, targetId, sortOrder, dateCreated, dateUpdated, uid) VALUES (:row0_col0, :row0_col1, NULL, :row0_col3, :row0_col4, :row0_col5, :row0_col6, :row0_col7). Bound with :row0_col0='13', :row0_col1='39', :row0_col3='v.id', :row0_col4=1, :row0_col5='2016-02-13 08:28:03', :row0_col6='2016-02-13 08:28:03', :row0_col7='e455a06e-8f9d-4299-ad57-93577907f9a0'

I think the problem is this:

<option value="v.id">{{v.title}}</option>

Try changing it to:

<option value="{{ v.id }}">{{v.title}}</option>


Why is /blog not displaying /blog/index.html? So basically, my url is mysite.com/blog which should apparently lead to /blog/index.html which is stored under templates/blog/index.html. As far as I can see I don't need to set up any routes to make it work and it should be happening as standard. I'm working in a multisite environment, and may have done some damage there? I basically need to know where the error will be coming from, .htaccess/index.php etc...

Thanks!

Check for a blog.html file in the root of templates, craft would go to that first then check for a subfolder.

You can read more about the process that Craft follows when deciding how to handle a request.


Plugin: Fill Record with data (auto generated form) Is there a way to generate a form based on my record-attributes ? Like a quick and dirty CRUD-Interface to get started ?

And otherwise: where would I create such forms ? Are those Controllers ?

I believe what you're asking is if there is any built-in scaffolding support in Craft.

If that's the case, then no... you'd have to manually build out the forms and CRUD support.

Yii does ship with a component called gii that enables scaffolding, but it's currently not compatible with Craft and we don't support it.


What would cause an Internal Server Error on saving entry When I try to save a new entry as a child under a Structure entry, I get the following error:

  Internal Server Error

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

I also get the same error when I tried to move it out to it's own Channel instead, so I am not sure what could be causing it.

I have several fields in this entry, most notably the cause would be an Entries field and Tags field. Both seem to select the correct values fine.

I have solved the problem myself while debugging.

I had the Entry Type "Title" field set to {relatedFieldName} Post which was causing the error. When I changed it to a plain string or other non-object field name, it no longer errors out.

I was unclear about how the Title field works exactly.


Comparison with an integer from a dropdown list not working I'm not sure if this is a bug or not, but there is something weird going on if I try to compare an integer form a dropdown field to an integer in the template. In short, it doesn't work.

I'm working with a dropdown level field for users from 1 to 15 and use conditionals for content:

{% set integer = 7 %}
{% set mylevel = currentUser.level %}

My level: {{mylevel}}

Number: {{integer}}

{% if mylevel >= integer %}
    {{mylevel}} bigger than or equals {{integer}}
{% else %}
    {{mylevel}} smaller than {{integer}}
{% endif %}

This outputs:

My level: 8

Number: 7

8 smaller than 7

HOWEVER if I replace the code "currentUser.level" with 8 like:

{% set integer = 7 %}
{% set mylevel = 8 %}

My level: {{mylevel}}

Number: {{integer}}

{% if mylevel >= integer %}
    {{mylevel}} bigger than or equals {{integer}}
{% else %}
    {{mylevel}} smaller than {{integer}}
{% endif %}

Then the output is:

My level: 8
Number: 7
8 bigger than or equals 7

I checked the database and reinserted all numbers, but nothing changes.

Database had this:

{"options":[{"label":"SG1","value":"1","default":""},{"label":"SG2","value":"2","default":""},{"label":"SG3","value":"3","default":""},{"label":"SG4","value":"4","default":""},{"label":"SG5","value":"5","default":""},{"label":"SG6","value":"6","default":""},{"label":"SG7","value":"7","default":""},{"label":"SG8","value":"8","default":""},{"label":"SG9","value":"9","default":""},{"label":"SG10","value":"10","default":""},{"label":"SG11","value":"11","default":""},{"label":"SG12","value":"12","default":""},{"label":"TG01","value":"13","default":""},{"label":"TG02","value":"14","default":""},{"label":"TG03","value":"15","default":""},{"label":"TG04","value":"16","default":""}]}

You'll want to use:

{% set mylevel = currentUser.level.value %}

If you just use currentUser.level and assign it to a variable, then what you'll get back is a MultiOptionsFieldData class, instead of the value you are expecting.

There is a note on the bottom of the page here that describes it.


Ajax request returns code instead of result of the query (solved) I'm trying to answer my own question in this post Basically, I have a bunch of checkboxes in multiple categories and when clicked, I want to use Ajax to filter the results and show them on the same screen.  I'm building up to that incrementally, and starting out by just trying to get the Ajax to work right with a single category filter.
My Ajax looks like this:
$('#filters input').change(function() {
  var value = $(this).val();

  $.ajax("ajax.twig?search=" + value, {
    type: 'get',
    dataType: 'html',
    success : function(html) {
      $("#ajaxresults").html(html)
    },
    error: function(xhr, status, error) {
      alert(xhr.responseText);
    }
  });
});

ajax.twig look like this:
{% set searchTerm = craft.request.getParam('search') %}

{%  set galleries = craft.entries.section("gallery").colors(searchTerm) %}
{% if galleries|length %}

    {% for gallery in galleries.all() %}

{{ gallery.title }}

    {% endfor %}

{% endif %}

If I visit ajax.twig?color=red manually in the browser, it works as expected and I see the rendered result.  However, the page with the filters using ajax just returns the code inside ajax.twig rather than the result of the query.  I've also tried using .load() and .get() and had the same result.
Does anyone know what I'm doing wrong? I've been stuck for days. Thanks in advance.

The path to the ajax file was wrong. I had it as:
$.ajax("templates/ajax?search=" + value, {

when it should have been
$.ajax("ajax?search=" + value, {


Setting a variable assets field, depending on the URL? How can I set different assets fields depending on the URL?

I tried:

{% if craft.request.getSegment(1) == 'special' %}
   {% set assetfield = variantfield1 %}
{% endif %}

{% for asset in entry.assetfield %}
     ...
{% endfor %}

But that doen't change entry.assetfield?

I'd probably do it like so:

{% if craft.request.getSegment(1) == 'special' %}
    {% set assets = entry.assetfield_1 %}
{% else %}
    {% set assets = entry.assetfield_2 %}
{% endif %}

{% for asset in assets %}
    ...
{% endfor %}


Comparing date field object with global variable "now" gives unexpected result The goal is to show a word when date field qualifies for tomorrow or today instead of numeric date.

Setting and calling variables:

{% set deliveryDate = order.deliveryDate %}
{% set tomorrow = now|date_modify("+ 1 day") %}

{% if deliveryDate == tomorrow %}
  {% set deliveryDate = "tomorrow" %}
{% elseif deliveryDate == now %}
  {% set deliveryDate = "today" %}
{% else %}
  {% set deliveryDate = deliveryDate|date("d.m.Y") %}
{% endif %}

My date field has selected value of tomorrow whereas the first statement should be truthy.

So I think I'm comparing two objects with the same values but different classes?
I had figured it out by formatting the date objects to strings using day() filter.

But why is THAT happening on the first place?

now represents the current DateTime so unless you specify exactly the correct time in your field the condition deliveryDate == now will never become true. If the user visits the page one second earlier or one second later the condition will fail.

For example: if your date is 2018-06-13 12:00:00 and now is 2018-06-13 12:00:01 both of your conditions will always fail. now|date_modify("+ 1 day") will result in 2018-06-14 12:00:01 and 12:00:00 is not 12:00:01

you'll need to equalize the time or format it differently

{% if deliveryDate.modify('midnight') == tomorrow.modify('midnight') %}

or

{% if deliveryDate.format('Y.m.d') == tomorrow.format('Y.m.d') %}

You can read more about it in the docs


Commerce Subscription Prices I need to be able to output the price of a subscription after the user has subscribed. I'm using the Stripe Gateway. This post indicates to use {{ subscriptionPlanData.plan.amount }} but that doesn't seem to work for Commerce 3.
Commerce 2 Subscription Prices
The code below works but only after you refresh the payment history for the subscription in the admin, which seems to be a manual task.
{% set payments = subscription.getAllPayments() %}
      {% if payments %}
           {% for payment in payments %}
                ${{ payment.paymentAmount|number_format(2, '.', ',') }}
           {% endfor %}
      {% endif %}

Any idea how to get that payment history to automatically refresh after a subscription? Since that includes taxes, etc. that might be the best solution?

You can use
{{ subscription.subscriptionData.plan.amount }}

to get the price of the plan the customer subscribed to.
That returns in cents so you'll need to convert and format it.
{{ (subscription.subscriptionData.plan.amount / 100) | currency('USD', stripZeros=true) }}


Multi-page form with Yii in a Craft site? I have a Craft-based website and need to make a complex multi-'page' form on one page. The form isn't related to any Craft Entries etc, and doesn't need to save the submitted data to Craft's database (it's sent to a different database).

Having looked at a few form-related Craft plugins, I think I'll be best writing this from scratch. I'm experienced with PHP, but not Yii and I'm not quite sure how best to structure this within a page that will be generated by Craft (an Entry).

I'm guessing I could write a plugin and a variable in it is used in the Craft template to generate the form. Given that, some questions:

Should I create a series of Yii forms, one per 'page' of the form, and use the one indicated by a hidden 'step' form field?
Is there any issue with saving data to Yii sessions (for each form step's inputs) within a Craft site?
I could have templates for the different form 'pages' in my plugin. How would I pass data from the form (fields, submitted data, error messages) to the template?

I guess I'm also looking for general responses of either "This looks like a sensible route to explore" or "OMG don't go that way, there are monsters!" :)

EDIT: I think I should be using the plugin's Controllers to handle form submission, passing data to templates etc. Rather than having a plugin variable in a Craft Entry's template. Maybe I can integrate Yii forms with those Controllers?

I wouldn't worry going so far outside of Craft and using Yii's forms.

Sounds like all you need is a Craft plugin.  Use normal HTML <form>s from  your template and have them post to your plugin's Controller.  Each step in the form can be another action on the controller.  You can persist data between form steps by saving to Craft's HttpSessionService, which is just a thin wrapper for PHP's global $_SESSION variable.

craft()->httpSession->add($key, $value)

and:

craft()->httpSession->get($key)


Add style on every third entry Trying to add entries in a visual array on my homepage.
Problem is that I need a special class on the last item in every row.
col_last

Trying to get my head around how to automate this, in order to avoid "special entries" for these.

Any ideas?

{% for item in craft.entries.section('services').orderBy('postDate asc').all() %}

{{ item.title }}

{{ item.serviceTagline }}

{% endfor %}

You can cycle your loop.index0 property if you really need to add a class

{{ cycle(['first', 'second', 'last'], loop.index0) }}

If the other elements don't need a class insert an empty value ''

You can as well check for a specific value of your loop.index0

However if you just want to add certain style attributes you can use the nth selector


How to append / prepend into a rich text field I have a rich text field, e.g. for defining an image caption. Now in my template I would like to prepend some text to the content of the rich text field, e.g. Figure 1: [rich text]. Is this possible? The content of the paragraph-tag of the rich text field should include the prepended text.

If you want to prepend another paragraph you could to this:

{% set paragraphs = entry.body|split('
') %}
{% for paragraph in paragraphs %}
  {% if loop.index == 1%}

Prepended Custom Text

  {% endif %}
    {{paragraph|raw}}
{% endfor %}

If you want to display a custom string in the first paragraph itself you could do this:

{% set paragraphs = entry.body|split('
') %}
{% for paragraph in paragraphs %}
  {% if loop.index == 1%}
    {% set paragraph = paragraph|replace({'
': '
My custom prepended Text '}) %}
  {% endif %}
    {{paragraph|raw}}
{% endfor %}

This looks a little bit hacky tough there are probably prettier ways to do so.


Apache vs IIS - reasons for either Question: I am at early stages of setting up Craft.  I plan on installing on Apache & IIS to compare.  Anything I should be thinking about as I do this? Reasons one platform is better or worse than the other? Thanks!

Apache is generally hosted on Linux which the vast majority of web hosting services use. IIS is Microsofts platform and is much more difficult to set up as well as less common with hosting providers.

Just use Apache.


Craft CMS with local and flywheel setup? I have been using this blog https://medium.com/@madebyraygun/a-quick-and-easy-local-environment-for-craft-3-4fd7c7ff5815 as a reference but I cannot seem to connect to my database and get Craft working? The .dev connection gives me an error and when I click on start site I get a 503? Please help me.

The .dev connection gives me an error

Don't know if it'll solve all of your problems, but .dev is no longer a valid TLD you can use for local testing since Google made it public: https://domains.google/tld/dev/

Change it over to something like .test instead.


Relating a Category Entry to a Categories Field Type I've been trying to get this working but can't seem to find a solution.

I have two different types of Categories in a commerce project.

Level One
Level Two

Examples

Level One would be Mens, Ladies, Kids etc
Level Two would be T-Shirts, Jumpers, Shoes etc

When I click on 'Mens' on the navigation, it brings me to the Mens page, I then get a sub navigation on that page which shows me any Level Two categories that are related to the Level One category (Mens).

These are related by using the categories field type.

This is got easily by the following:

{% for subCat in craft.categories.group('levelTwo').relatedTo(category) %}

The problem that I encounter now, is when you click on one of the Level Two categories on that sub nav (T-Shirts for example), it brings me to the t-shirt category page.  I want to be able to display the same sub nav that is on Level One (Mens), on the Level Two (T-shirts) page.

{% for subCat in craft.categories.group('levelTwo') %}

The above snippet shows me all the categories in Level Two, which is wrong.

I need to be able to show all the categories in Level Two, that have have the same categories field type.  The handle of this categories field type is topLevelConnection.

Any suggestions would be greatly appreciated!

Turns out I was overthinking it, I was able to connect it with the following piece of code.

{% set levelOne = category.topLevelConnection %}
{% for subCat in craft.categories.group('levelTwo').relatedTo(levelOne) %}


Placid plugin - limit returned results I'm trying to limit the results to 5, but its returning all of the results instead. I am using the below code:

{% set options = {
  cache : false,
  query : {
    limit : 5
  }
} %}

{% set timeline = craft.placid.request('projectsLatestTrending', options ) %}

{% for tweet in timeline.data %}

{{ tweet.name }}

{% endfor %}

Thanks in advance for any help.

Not a true answer, but a work around:

{% for tweet in timeline.data %}
    {% if loop.index <= 5 %}
        ...
    {% endif %}
{% endfor %}


Calls to /actions return 400 Bad Request I'm trying to use jquery ( and/or VueJS with axios) to delete an asset from a frontend form (user is logged in and they have permissions to delete assets from this volume)

I have an HTML element that contains the fileID of the asset in question:

Delete

I have the following jQuery click action:

$('.deleteAsset').click(function() {
    window.csrfTokenName = "{{ craft.app.config.general.csrfTokenName|e('js') }}";
    window.csrfTokenValue = "{{ craft.app.request.csrfToken|e('js') }}";

    var assetID = $(this).attr("data-fileID");
    var data = {};

    data[csrfTokenName] = csrfTokenValue;
    data['assetId'] = assetID;
    data['dataType'] = 'json';
    data['action'] = '/actions/assets/delete-asset';

    $.post('/', data, function(response, textStatus, jqXHR) {
      console.log('clickResponse', response);
    });
});

However I keep getting the following error in the console when I click the "Delete" button:

POST https://website.com/ 404 (Not Found)

I have tried having the action URL in the $.post() call, but it has the same effect.
Anyone have any suggestions?

You're close. Just a couple minor syntax things:

remove the colon (:) before :data-fileID
$.post has 4 parameters, the dataType (in this case 'json') goes as the last parameter.
Set the url parameter to the action.

This worked for me:

Delete


Why do some entries generate a template error on get next or previous post when others do not? I have setup chevrons to links to the previous and next posts.  It seems to work for all but a handful of posts.  Those posts generate the following template error:

  Impossible to access an attribute ("url") on a null variable

            {% set prev = entry.getPrev( 'posts' ) %}
            {% set next = entry.getNext( 'posts' ) %}

        {{ entry.postDate | date('F d, Y') }}

The specific line the template error references is

There are previous entries to access.

Thanks

First – you're passing a string value ('posts') to the getNext() and getPrev() methods, which will produce unreliable results.

The getNext() and getPrev() methods actually expect either an ElementCriteriaModel instance, or an object representing an ElementCriteriaModel's attributes (i.e. a query like { section: 'posts' } – not a string, number or any other, non-iterable value.

I'm guessing 'posts' is a section handle, but Craft won't know that and it will just ignore the string and return any element matching the current element's type - so if you call entry.getNext('posts'), you're probably going to get an entry back, but it won't reliably be an entry from the 'posts' section; it could be an entry from any section in your system.

So here's how your code probably should look:

{% set criteria = { section: 'posts' } %}
{% set prev = entry.getPrev(criteria) %}
{% set next = entry.getNext(criteria) %}
...

If this code is in an entry template, you could even do something like this:

{% set criteria = { section: entry.section } %}
{% set prev = entry.getPrev(criteria) %}
...

An additional tidbit: The only instance where it's ok to call getNext() and getPrev() without passing an ECM (or pass an invalid value, like a string), is whenever your entry variable is already part of an element result set – for instance, whenever you're looping on the result of a craft.entries query:

{% for entry in craft.entries.section('posts') %}
    ...
    {% set next = entry.getNext() %}
    {% if next %}
        {{ next.title }}
    {% endif %}
{% endfor %}

As for the error message you're seeing:

The getNext() and getPrev() methods should always be wrapped in a conditional, because they won't realibly, always return an element (i.e., there might not be a "next" or "previous" entry in your current context):

{% set prev = entry.getNext(criteria) %}
{% set next = entry.getPrev(criteria) %}

{% if prev %}
    {{ prev.title }}
{% endif %}

{% if next %}
    {{ next.title }}
{% endif %}

The error message you're getting, is simply stating that there is no url attribute for one of your next or prev variables – meaning that those variables don't actually refer to valid elements, because the getNext() and/or getPrev() methods returned a NULL value. Simply wrap your code in conditionals, and the error will go away.

If you want to make sure that you're always displaying both a "next" and a "previous" link, you can make the links "loop" by having them point to the first and last entries respectively, whenever there isn't a next or previous entry in the set:

{% set criteria = craft.entries.section('posts') %}
...
{% set next = entry.getNext(criteria) ?? criteria.first() %}
{% set prev = entry.getPrev(criteria) ?? criteria.last() %}
...
{% if next %}
    {{ next.title }}
{% endif %}


Get next 3 upcoming entries I'm working on a new website for my student radio station but I've stumbled into a few key bugs which are stopping us from advertising the new site.

It's live right now over on Stormfm.com, you'll be able to see the problems for yourselves there.

The up coming shows section is supposed to display the next 3 shows, however there's a bug with it's limit, to get the section to display at least 3 shows I had to raise the limit to 30, this then means up to 30 shows display. I've copied the code below.

{% for entry in craft.entries.section('shows').order('showTime').limit(30)
    if entry.showDay.contains('now'|date('N')) and entry.showTime > 'now'|date('H:i') %}

{{ entry.showTime }} - {{ entry.showLength }}

{{ entry.Title }}

With {{ entry.hostname.first().title }}

&gt;

{% endfor %}

Also I want to display what the current show on air is, originally I was going to use a similar code to the above, limit it to 1 and have it minus an hour but I can't seem to work out how to do that. For the short term I can flip the greater than to less than, however this then displays only the closest show and I can't else out into a default display if nothing is currently timetabled as on air.

I hope this all makes sense and would appreciate any help you might be able to provide!

Tom

What you do, is this:

Get 30 items from the database, ordered by showTime
Then, you filter them with the if-attribute in the for-statement

This means, that you could get anywhere from 0 to 30 results. What you want to do, is make sure the filtering happens within the element query. I did not test this (not sure about the time criteria part), but something like this should work:

{% for entry in craft.entries
    .section('shows')
    .order('showTime')
    .search('showDay:*' ~ now |date('N') ~ '*')
    .showTime('>= ' ~ now |date('H:i'))
    .limit(3) %}


How to create single lines from a plain text field with line breaks Building on this question here: Create line breaks from text field

What approach would be best for breaking a multi line plain text field into multiple single lines to be used as:

{{ textfield.lineOne }}
{{ textfield.lineTwo }}
{{ textfield.lineThree }}

At the moment, my approach is to use a Matrix for the user to be able to add individual lines, but I'd much rather I was able to present the client with a multiline text field and rework them in the template.

I've made a little macro for this:

{% macro splitText(text) %}
  {% set text = text|nl2br|raw %}
  {% set text = '' ~ text|replace('
', ' ') ~ '' %}
  {{ text|raw }}
{% endmacro %}

You may need to tweak it a bit, but this is what worked for me.


Get random entries from a section but keep the order of these when splitting the array So I want to get 9 random entries from a section and I do this like so:

{% set artists = craft.entries
  .section('artists')
  .artistImage(':notempty:')
  .with(['artistImage'])
  .orderBy('RAND()')
  .limit(9) %}

Now I want to split these entries into a row of 4 and a row of 5. I am doing this like so:

  {% for entry in artists|slice(0, 4) %}

      {% include '_includes/_components/image.twig' with {
        image: entry.artistImage[0],
        alt: 'Artists',
        transform: 'square',
        classes:'w-full',
        sizes:'(min-width:576px), 100px, 25vw',
        widthEnd: 800
      } %}
      {{ entry.title }}

  {% endfor %}

  {% for entry in artists|slice(4) %}

      {% include '_includes/_components/image.twig' with {
        image: entry.artistImage[0],
        alt: 'Artists',
        transform: 'square',
        classes:'w-full',
        sizes:'(min-width:576px), 100px, 20vw',
        widthEnd: 800
      } %}
      {{ entry.title }}

  {% endfor %}

However, this seems to randomise the each split and sometimes I get duplicate entries in each split.

Ideally, I want to get 9 random items and then keep this order and split this into to separate rows.

How can I achieve this?

One way I have achieved this is like so:

{% for entry in artists %}
  {% if loop.first %}

  {% endif %}
  {% if loop.index == 5 %}

  {% endif %}

    {% include '_includes/_components/image.twig' with {
      image: entry.artistImage[0],
      alt: 'Artists',
      transform: 'square',
      classes:'w-full',
      sizes:'(min-width:576px), 100px, 25vw',
      widthEnd: 800
    } %}

  {% if loop.last %}

  {% endif %}
{% endfor %}

But I think this circumvents the issue rather than solves the question.


Inline and multiline comments in Craft? How do comments work in Craft? I mean inline and multiline comments, like:

HTML: <!--xxx--> m
  JS:   /*xxx*/  m   //xxx i
 PHP:   /*xxx*/  m   //xxx i   #xxx i

There's only one comment syntax for Craft / Twig:

{# ... #}

Anything in between won't be parsed by Twig, so you can comment out multiple lines of Twig and HTML like so:

{#
    {% set var = value %}
    {% for item in seq %}

{{ item }}

    {% endfor %}
#}

As with many other languages you can't nest comments! So if you want to comment out some lines of code that already have comments, you can't do that like so:

{#
    {#
     # Lots of comments going on here
     #}
    {% set var = value %}

    {# I warned you #}
    {% for item in seq %}

{{ item }}

    {% endfor %}
#}

The best workaround I found is to use HTML comments in combination with Twigs verbatim tags (disables Twig parsing).
I added a snippet to my editor for this and use it regularly since:

{% verbatim %}

{% endverbatim %}


Is there a way to query for a list of values belonging to a specific field in a queryset? For instance, if I wanted an array of all the titles belonging to a subset of entries that I wish to query. The way I know how to do this currently is like so:
  {% set titleList = [] %}
  {% articleQuery = craft.entries().section('articles') %}
  {% for article in articleQuery.all() %}
    {% set titleList = titleList|merge([article.title]) %}
  {% endfor %}

The other way I can think of to do this operation is with the map twig filter, but I'm wondering if there is a way to query for such a field-value list straight away and avoid spending computational time on iterations.

Yep! It's not super well documented, but there's a little information about it down in the Advanced Element Queries section of the docs. It would look something like:
  {% set titleList = craft.entries.section('articles').select('title').column() %}

One thing to note, if you're selecting a field value instead of the title, the select parameter will look something like select('field_fieldHandle')


Custom template location First Craft install so please excuse me if this is a newbie Q.

Templates are in /craft/templates. Is it possible to move those to a different location? Our other sites (EE) have templates stored with the UI theme source files so everything to do with the the site look and feel is in one place.

Thanks.

The default template path can be changed by setting the CRAFT_TEMPLATES_PATH PHP constant in your index.php file:

define('CRAFT_TEMPLATES_PATH', "path/to/templates");

I would recommend, however, that you start with the default path locations, until you are more comfortable with the app. There is a logical system in place which works really well once you get used to it. And you'll notice that the craft app folder (and all the plug-ins) are organized the same way, so once you start building your own sites and plugins it will all feel very integrated. Keep in mind the folder names also match the names of the controller classes, service classes, method names, etc. throughout the system which makes it easier to find your way around.

Another thing to keep in mind is that placing your Craft templates in your web root would make the raw template files publicly accessible from a web browser. So if you decide to go this route, be sure to place a .htaccess file in your templates folder with this:

Deny from all

That will tell Apache to protect the files from direct HTTP traffic, even though they live within the web root.


Form input not being disabled In the plugin I'm creating I've got a form that has inputs which are set as disabled if they are overridden in a conifg file.

The problem that is occurring is that disabled class is added to the input but the disabled attribute is not.

This is what I've got:

{% import "_includes/forms" as forms %}
{% set configSettings = craft.config.get('settings', 'myPlugin') %}
{% for paramKey, paramValue in array %}
       {% set disabled = (configSettings[paramKey] is defined) %}
       {# other variable sets here #}
       {{ forms.textField({
            label: paramLabel,
            name: inputName,
            value : paramValue,
            disabled: disabled,
            required: required
            }) }}

{% endfor %}

When I navigate to the page, the input field is greyed out but I can still input data to the input field.

This is the HTML that I see when I inspect the element:

<input class="text disabled fullwidth" type="text" name="settings[abcd]" value="abc" autocomplete="off">

I tried disabled: true and disabled: 1 in the code above to test and the same html is returned.

I copied your markup, setting and name and label manually and it added the disabled property if I used disabled: true

{{ forms.textField({
label: 'Example Label',
name: 'Example Name',
value : 'Example Value',
disabled: true,
required: true
}) }}

Perhaps you could try manually defining the field (as I did) without reading from the variables and confirm that it works.

If that fails, I suggest you enable dev mode and then use twig's dump() function to check that you don't have any errors and that the field is given correct values.

Is there anything in your log file?


Order by reverse relationship count It feels like I’m trying to do the impossible, but I can’t imagine this problem is unique to my project. Hoping someone here has figured it out before!
I have two channels, creators and products, and I can assign any number of products to a creator through a related entries field: creatorProducts.
How do I display the top 10 most popular products? Or, in other words, how do I sort the products by the number of creators they’ve been assigned to?
Haven’t been able to find the answer anywhere. Welp.

If you don't have tons and tons of creators, you could do that by querying creators and re-arranging the results:
{# Get all creators and eager-load the products #}
{% set creators = craft.entries()
    .section('creators')
    .with('products')
    .all()
%}

{# Declare an array to store all related product ID #}
{% set products = [] %}

{# Build an array of all product ID occurences #}
{% for item in creators %}
    {% for product in item.products %}
        {% set products = products | merge([product.id]) %}
    {% endfor %}
{% endfor %}

{# Group by product ID #}
{% set groupedProducts = products | group(v => v) %}

{# Sort by occurence count #}
{% set sortedGroupedProducts = groupedProducts | sort((a, b) => b <=> a)  %}

{# Now you can get: Product ID | Occurences #}
{% for c in sortedGroupedProducts | slice(0,10)%}
    Product ID: {{ c[0] }} | Occurences: {{ c|length }}

{% endfor %}

{# To fetch the products, extract the keys from the above and flatten to a comma seperated list of product IDs #}
{% set productIds = sortedGroupedProducts|keys|join(',') %}

{# Query #}
{% set products = craft.entries()
    .section('products')
    .id(productIds)
    .fixedOrder()
    .limit(10)
    .all() %}

{% for item in products %}
    {{ item.title }} ({{ sortedGroupedProducts[item.id] | length }})

{% endfor %}

This could probably be improved or even moved to PHP but if you have to do in Twig, it should work.


Displaying the optional note from a versioned entry I want to use the note that is optional when saving a versioned entry as part of an activity feed -- like a git commit message.

Is there an entry model property for this?

Indeed... EntryModel->revisionNotes is what you're looking for.

Through PHP, that's:

$entry->revisionNotes

Through a template, that's:

{{ entry.revisionNotes }}


Why is $DEFAULT_SITE_URL appearing in entries URL? I have an entry loop on my homepage that uses {{ entry.url }} that links to the full entry. When I click on the entry, the url looks like this
mydomain.com/$DEFAULT_SITE_URL/the-entrys-slug
Even though my section settings just has the Entry URI Format set to {slug}
Here's my entry loop if you need it
{% set aBetterPost = craft.entries.section('aBetterPost').limit('6').all() %}
{% for entry in aBetterPost %}

            Entry Stuff...

{% endfor %}

How can I get rid of the $DEFAULT_SITE_URL ?

You probably have a misconfiguration in your environment variables - First go to the control panel and check what you have under Settings > Sites > [choose site] > Base URL. If it's set to an env variable (i.e. it begins with a dollar sign), go to wherever you store your environment variables (e.g. the .env file, or maybe server env vars if you're on the remote), and check that you have a variable there with the expected value.


How to fire a custom event from another plugin? I have some questions about events. I want to fire a custom event from another plugin. The event handler is in MyHelpers_PostService.php (plugin A).

public function onSavePost(Event $event)
{
    $this->raiseEvent('onSavePost', $event);
}

My init() method (plugin B):

public function init()
{
    craft()->on('myHelpers_Post.savePost', function(Event $event)
    {
       // delete a cache key
       craft()->pluginB->clearCache('forum-home-desktop');
    });
}

This is my first time working on Craft events, so please bear with me. I tested this by saving a new Helpers Post on the front-end and nothing happens.

The clearCache() method is just using Craft's deleteCachesByKey();

Is myHelpers_Post.savePost correct?
What else do I need to make this work?
How do I test this properly? Can I use Craft::dd() inside the handler?

myHelpers_Post.savePost was wrong. It should have been myHelpers_post.savePost. It's okay to delete this question.


Creating environment variable from JSON file Brand new to Craft here. I'm trying to port across my gulp workflow to Craft and basically everything has gone super smooth. Just one last obstacle due to my lack of knowledge of the Twig templating engine and some of the internal workings of Craft.

Basically, for production, I run gulp with a --production flag. This appends a string of numbers and letters to the asset's file name (as well as removing source maps etc.), such as main-5449f384.css, to help with caching. A list of the resulting asset filenames is stored in a JSON file at public/dist/assets.json. The contents of the file is akin to:

{
  "main.css": "main-5449f384.css",
  "modernizr.js": "modernizr-45f0e1f4.js",
  "jquery.js": "jquery-e735354d.js",
  "main.js": "main-b7e504b0.js"
}

Separately, in my general.php config file, I've set up environment variables so I can use local asset paths in local and dev environments and a CDN based path in production:

return array(
    '*' => array(
        'appId' => 'example',
        'omitScriptNameInUrls' => true,
    ),

    'example.com' => array(
        'devMode' => false,
        'assetUrl' => 'https://cdn.example.com/',
    ),

    'craft' => array(
        'devMode' => true,
        'local' => true,
        'assetUrl' => 'http://craft:8888/',
    )
);

I had figured that to finalise the whole workflow, my head section within craft/templates/_layout.html would look something like (using a if statement to get the current environment):

Local

<script src="{{ craft.config.assetUrl }}dist/scripts/main.js"></script>

Live (pseudocode)

<script src="{{ craft.config.assetUrl }}dist/scripts/{{ assets.json.main.js }}"></script>

Is there a way to either set an environment variable based on the contents of the JSON file or to access to JSON file contents directly from within the template file? Or perhaps there's a much better way of doing this altogether (I'd quite like to keep the currently gulp workflow as is if possible)!

You could write some PHP at the top of your general.php file that reads the JSON manifest in your public root directory, and add its keys/values to the config array. I wouldn't use environment variables here, personally – just add the manifest to the returned array in general.php:

// In general.php:

$assetsManifest = @json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'].'/assets/assets.json')) ?: [];

return array(
    '*' => array(
        ...
        'assets' => (array)$assetsManifest,
    ),
);

...and in your template:

<script src="{{ craft.config.assets['main.js'] ?? 'main.js' }}"></script>

Be advised that the null-coalescing operator (??) was just added in Craft 2.6 – if you haven't updated yet, you can use the default filter instead:

<script src="{{ craft.config.assets['main.js']|default('main.js') }}"></script>

Another approach for getting revved asset filenames in templates, is to use a plugin which adds either a custom template variable method or Twig filter/function to Craft. For an example of the latter, see Viget Labs' Gulp Rev Craft plugin, which is bundled with their awesome Gulp Starter repo. Here's how revving works using this particular plugin:

<script src="{{ 'main.js'|gulp_rev }}"></script>

For me, individual asset filenames in the config feels a bit off and the custom filter option seems a lot cleaner, so I'm personally going with that approach.


Display additional fields (and sort by) in Entries in Control Panel I have created a Calendar channel in the Control Panel.
I have added a field Calendar Date.

Is it possible to add that field to the Entries list and sort by it?

If I use the post date as the calendar date it will not display if it is in the future?

Not at the moment. Sorting by custom field in the back end entries screen is not yet implemented although I know it is definitely possible in the future based on the way the code is currently laid out.

I would create a front end method to list and sort the entries with links into edit with cpEditUrl

http://buildwithcraft.com/docs/templating/categorymodel#cpEditUrl


Limit the for loop returns with an if statement I've got a for loop working perfect with a limit of 5. Then I throw in the if statement to filter those entries that correspond with a global variable I have set. The problem is the if statement is after the for loop with the limit and only doing it's thing to the 5 entries and not all of the entries.\

I want to use the if statement on all the entries to return the ones I want, then limit it to 5. In another DIV I have and offset(5), so the rest go there. I hope that makes sense.

{% for entry in craft.entries.section('news').order('articleOrder desc').limit(5).find() %}

    {% if entry.currentYear2 == currentEdition.currentYear2 and currentEdition.currentMonth2 in entry.currentMonth2 %}

{{ entry.title }}

{{ entry.body }}

    {% endif %}

{% endfor %}

If I'm following you correct, you can use a conditional in a for loop to do what you want.

So in your case, it would be something like:

{% for entry in craft.entries.section('news').order('articleOrder desc').limit(5).find() if entry.currentYear2 == currentEdition.currentYear2 and currentEdition.currentMonth2 in entry.currentMonth2 %}
   ...
{% endfor %}


Get entry ID within plugin controller I'm creating a FieldType plugin, but I need the entry's ID in the front-end, I suppose I can get it within the controller, something like

craft()->entryId

$entryId = IN HERE;

$options = array(
    'coreUrl' => getenv('ENV_CORE_HOST'),
    'newEntry' => false,
    'entryId' => $entryId
);

craft()->templates->includeJs("$('#{$namespacedId}-field').whatever('" . json_encode($options) . "');");

I can get the ID in the URL with Regex and stuff, but I wouldn't like to rely on that.

And suggestion?

A field in Craft can belong to any element (entry, tag, category, user, etc.).

If you want to get the ID of the element the field may or may not be currently attached to, you can do this from your Field Type class:

$elementId = isset($this->element) ? $this->element->id : null;

if ($elementId)
{
    ...
}


AuthorizeNet CIM gateway in Commerce 1 Is there any barrier to using AuthorizeNet CIM gateway in Commerce 1? The vendor/omnipay/authorizenet folder has a CIMGateway class but there doesn't appear to be a corresponding AuthorizeNet_CIM_GatewayAdapter. I'm wondering why it's not supported by default, and how difficult it would be to implement it for a client.

This Authorize.Net Accept.js gateway for Craft Commerce might be a good place to start: https://github.com/marionnewlevant/craft-acceptjs


Search not working with extra field I have a search form that contains a dropdown based on categories and a text field to search by title. This works the way it should. Now I need to add an extra text field to search by location as well but when I do that the search form doesn't work anymore.

What I have is:

{# defaults #}
    {% set queryParams = {
      section: 'klanten',
      order: 'title asc',
    } %}

    {# Build a category array beginning with 'and' and add targetElement objects with selected categories Ids to it #}
    {% set categoriesArray = ['and'] %}

    {% set searchCat = craft.request.getParam('cat') %}
    {% if searchCat is not empty %}
      {% set searchThemeCat = craft.categories.slug(searchCat).ids() %}
      {% set categoriesArray = categoriesArray|merge([{
        targetElement: searchThemeCat,
      }]) %}
    {% endif %}

    {% if categoriesArray|length > 1 %}

      {% set queryParams = queryParams|merge({
        relatedTo: categoriesArray
      }) %}

    {% endif %}

    {# search #}
    {% set searchQ = craft.request.getParam('q') %}
    {% if searchQ is not empty %}
      {% set queryParams = queryParams|merge({
        search: {
          query: 'title:' ~ searchQ,
          subLeft: true,
          subRight: true,
        }
      }) %}
    {% endif %}

{% set klantEntries = craft.entries(queryParams) %}

Now I thought adding the following would allow me to search by location as well but instead it says 'no results are found for ""' which means that it search query is empty, I guess?

{% set searchL = craft.request.getParam('loc') %}
    {% if searchL is not empty %}
      {% set queryParams = queryParams|merge({
        search: {
          query: 'klantLocation:' ~ searchL,
          subLeft: true,
          subRight: true,
        }
      }) %}
    {% endif %}

I don't really know how to fix it, I've been looking through a lot of examples but I can't get it to work, any help would be appreciated

I found the problem, which is pretty ridiculous but something that probably happens to other developers who are using multiple languages.. (I hope).

In

query: 'klantLocation:' ~ searchL,

I had to replace klantLocation with klantLocatie

Pretty dumb mistake but hopefully someone else will find some help in my mistake


Display parent category with nested child categories and related entries I'm struggling to loop through level 1 categories
and display as a category title
and then show nested level 2 categories (via a category title) under which I want to nest related categories
to achieve:
PARENT CATEGORY

CHILD CATEGORY

related entry

related entry

related entry

CHILD CATEGORY

related entry

related entry

related entry

although the content and order is correct, I have divs closing in the wrong place so can't control which content is positioned by flexbox using this code:
{% for category in craft.categories.group('team') %}

{% if category.level == 1 %}

{{ category.title }} LEVEL 1

     {% endif %}

               {% if category.level == 2 %}

               {{ category.title }} LEVEL 2

               {% for entry in craft.entries.section('team').relatedTo(category).all() %}

{{entry.title}}

{{entry.positionTitle}}

{{entry.emailAddress}}

Tel: {{entry.telephoneNumber}}

Mob: {{entry.mobileNumber}}

               {% endfor %}

               {% endif %}

{% endfor %}

This won't be super efficient if you have a loads of teams/people as it will run an entry query per subteam (and it won't check for empty teams either) but it should get you started.
{% set categories = craft
    .categories()
    .group('team')
    .level(1)
    .with('children')
    .all() %}

{% for category in categories %}

{{ category.title }}

    {% for child in category.children %}

            {{ child.title }}

        {% for entry in craft.entries.section('team').relatedTo(child).all() %}

{{entry.title}}

{{entry.positionTitle}}

{{entry.emailAddress}}

Tel: {{entry.telephoneNumber}}

Mob: {{entry.mobileNumber}}

        {% endfor %}
    {% endfor %}

{% endfor %}


How to license Craft for my customer? As a web design shop we would like to license Craft not for ourselves but for our customers who run and own the future websites. How do we do that?

Who "owns" a Craft license is very loosely defined as far as Pixel & Tonic (the creators of Craft) is concerned.

A Craft purchase/edition is tied to the craft/config/license.key file that is in place at the time a purchase is made and wherever that file goes, the purchase/edition will follow.

In addition to that, a license.key file can only ever be tied to one public domain at a time.

As long as you give your client that license.key file and don't use it for other clients or projects, they "own" it.

How the license gets paid for is more up to you and your client.  i.e. either you purchase it and bill the client as a line-item on an invoice or have them purchase it directly.

Some relevant reading:

https://craftcms.com/support/license-key-info

https://craftcms.com/support/license-enforcement


Lightspeed retail POS integration with Craft Commerce Does anyone know of a plugin to integrate Lightspeed retail and Craft Commerce?

I'm not aware of a plugin that does this integration and a quick Google and Plugin Store search isn't coming up with anything, so it looks like it would need to be custom developed.


How to get name of template that was chosen for request? For convenience it would be rather useful if there was a way for me to achieve the following inside my main layout template:

<body class="template--{{ getNameOfPageTemplateHere|replace({ '/':'-', '_':'' }) }}">

Such that a page rendered using the template "blog/_entry" would have the following body tag:

<body class="template--blog-entry">

Is this possible?

Maybe not the solution you was looking for, but here is an alternative solution I'm using.

Put a Twig block in your "master template" (_layout.html?) like this:

<body class="{% block bodyClass %}{% endblock bodyClass %}">

And from my templates I can add classes to the body tag like this:

{% block bodyClass %}{{ parent() }} news-index anotherclass{% endblock bodyClass %}

Or replace the classes by omitting the parent() like this:

{% block bodyClass %}news-index anotherclass{% endblock bodyClass %}


Which string identifiers for field types do exist? There are several enum classes containing constants such as the SectionType class which I can use to create sections:

//  …
$section = new SectionModel();
$section->type = SectionType::Single;
//  …

But what about creating fields? Currently I create fields like so:

//  …
$field = new FieldModel();
$field->type = 'PlainText';
//  …

Is there any enum class containing valid identifiers I could use to create a field? Like in the following way?

//  …
$field = new FieldModel();
$field->type = FieldType::PlainText;     // Does something like this exist?
//  …

I can't find such a class or any other listing of existing field types, where do I?

Unfortunately, a list of string identifiers is missing on the guide for plugin development and field types. The list of field types only tells me which field types exist but not what identifiers they have.

I don't know if any enum exists (couldn't find it in source), but you could have a look at the contents of the craft/app/fieldtypes folder (and ignore BaseFieldtypes, DataModels and interfaces) to find the identifiers:

UsersFieldType.php
TagsFieldType.php
TableFieldType.php
RichTextFieldType.php
RadioButtonsFieldType.php
PositionSelectFieldType.php
PlainTextFieldType.php
NumberFieldType.php
MultiSelectFieldType.php
MatrixFieldType.php
LightswitchFieldType.php
EntriesFieldType.php
DropdownFieldType.php
DateFieldType.php
ColorFieldType.php
CheckboxesFieldType.php
CategoriesFieldType.php
AssetsFieldType.php

String identifiers correspond to the file names (without "FieldType.php", obviously).


Unable to create a "Single" entry I haven't made a new single in a few years, it seems. Now when I try to create one, there is no option to do so. Normally, the New Entry button seems to be split, with the left part directly creating a new entry in the currently selected channel or structure, and the right part giving a drop-down with the various channels and structures available. However the drop-down does not include Singles, and if I have Singles highlighted, then the New Entry button doesn't have the left part, just the drop-down.

Also, if I try to edit an existing single, there is no option to save as a new entry or save and add another. Any thoughts?

You should create a new single in the "Section" area of the settings page. It should just create the single after you have created the section.


How to load entries data in the General Configuration file? I'm trying to set dynamic paths for values such as activateAccountSuccessPath.

This kind of code below from my routes.php file works very well:

use craft\elements\Entry;

$myAccount = Entry::find()->section('myAccount');

return [
    $myAccount->type('user')->one()->uri . '/<id>-<slug>' => ['template' => '_myAccount/user']
];

But it seems that craft\elements\Entry can't be used at the top of general.php (which make sense...).

Any idea of a simple workaround to load Entry data at this time? Like this, I could set dynamic paths depending of the context and language.

I know I could already set paths like this:

'activateAccountSuccessPath' => array(
     'fr' => 'mon-compte',
     'nl' => 'mijn-account'
),

But this is not enough, I would like the path match dynamically another existing URI in a Structure.

When you take a look at the Docs you'll see

  See craft\helpers\ConfigHelper::localizedValue() for a list of supported value types.

And that contains

  $value (mixed) – The config setting value. This can be specified in one of the following forms:
  A scalar value or null: represents the desired value directly, and will be returned verbatim.
  An associative array: represents the desired values across all sites, indexed by site handles. If a matching site handle isn’t listed, the first value will be returned.
  A PHP callable: either an anonymous function or an array representing a class method ([$class or $object, $method]). The callable will be passed the site handle if known, and should return the desired config value.
  $siteHandle (string, null) – The site handle the value should be defined for. Defaults to the current site.
  Returns

The interesting thing is a function

'activateAccountSuccessPath' => function(){
    return Entry::find()->section('myAccount')..... // do your thing
}


setContent() vs $entry->getContent()->foo I'm a bit confused about the usage of these two. Let's say I want to create a new entry from a controller. For me, the nicer option would be to user something like this:

$entry = new EntryModel();
$entry->sectionId = 4;
$entry->typeId = 4;

$entry->setContent([
    'foo' => 'bar',
    'xyz' => '456',
]);

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

Somehow this is not working for me. Instead, I have to use the uglier version like this:

$entry = new EntryModel();
$entry->sectionId = 4;
$entry->typeId = 4;

$entry->getContent()->foo = 'bar';
$entry->getContent()->xyz = '123';

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

Any ideas why the first example might be failing? Especially when working with more than two attributes, the first example would be way more easy to handle.

You should be using setContentFromPost() rather than setContent(), so that field types have a chance to prep the values that you are passing in.

See “What is getContent() / the ContentModel, and how do I use it to get and set custom field values?” for more info on how this stuff works.


Apply custom filter on the entries in admin control panel using custom plugin in craft cms 3.5 I was referring to Filter entries in the CP based on custom permission and Filter entries in the CP based on custom permission
It seems onBuildElementsQuery was available only in 2.x.
Is there any alternative for craft 3.x?

Found it!!! Used ElementQuery::EVENT_AFTER_PREPARE


Check number against 2 seperate fields and return the entry that matches I have imported entries, each with 2 fields that comprise a range of numbers... numberStart and numberEnd. e.g. 3000 - 3006, in some instances both are the same number e.g. 8001 - 8001 The user will be inputting a single number and I need to return the single entry where the inputted number lands between (or is equal to) the start and (or) end number.

This is what I have so far...

{% set userInputtedNumber = 3000 %}

{% set entries = craft.entries({
    section: 'section',
    numberStart: '>=' ~ userInputtedNumber,
    numberEnd: '<=' ~ userInputtedNumber,
}) %}

This just returns nothing as the operators clash.

Any ideas will be welcomed!

Think you've just got a logic error in your Twig code.  This should work:

{% set userInputtedNumber = 3000 %}

{% set entries = craft.entries({
    section: 'channel',
    numStart: '<=' ~ userInputtedNumber,
    numEnd: '>=' ~ userInputtedNumber,
}) %}


plugin dev with vendor packages I haven't seen any answers specifically addressing this. While I did find a workaround, there's a bit of a gap in knowledge or guidance on this one, it seems.

I'm developing a plugin as prescribed in the Craft Docs, where my plugins folder is outside of my Craft folder:

  "minimum-stability": "dev",
  "prefer-stable": true,
  "repositories": [
    {
      "type": "path",
      "url": "../dev/craft-campaignmonitor-transactional"
    }
  ]

This is working great! After seeing a bunch of code work I ran composer require in my plugin to add a required package there, and it installed in my vendor directory for my plugin.

No matter what I tried, though, I kept getting "Class not found" errors for that package's class when I tried to use it in my plugin code.

Only when I ran composer require on the package in my Craft directory did it work in my plugin.

I can understand why this is happening...but should I be able to work on a plugin outside the Craft directory and keep vendor packages out of the Craft directory until I'm ready to install it? Or is this a necessary workaround while in development?

You should not do that at all. The entire process to install plugins via composer instead of the old way is to avoid this conflict. Imagine two of your plugins require the same class/library so you'll end up with a class already declared exception. Instead you can insert your requirements into the composer json of your plugin, run the composer update command for your Craft composer json and you are fine.

All dependencies will be loaded into the correct vendor folder.


Issues with Updating Is a backup needed before updating? Will installing new updates have any affect on the pages already saved or the existing structure?

Is a backup needed before updating?

It's definitely recommended.

Regardless of it is an auto-update or a manual update, Craft will attempt to perform a database backup if the backupDbOnUpdate config setting is set to true (it is by default).

If that is set to false you'd want to perform your own backup before doing a Craft update.

  Will installing new updates have any affect on the pages already saved or the existing structure?

Updates should not make breaking changes to the front-end of your site.  The ones that do will be advertised as so, such as the Craft 2 => 3 update process.

You can see the steps that Craft goes through to make sure updating is done safely here: How safe is auto-updating?


I want to get the HTML/text contents of the Redactor editor I'm building a plugin for Craft CMS. This plugin will load on the edit/content page, where the standard Redactor WYSIWYG editor will be loaded too (by CraftCMS).
I want to get the HTML/text contents of the Redactor editor.

For example tinymce.activeEditor.getContent() will get the HTML contents of the TinyMCE editor in WordPress.

How do I achieve this in Craft CMS?

The API documentation says var text = this.clean.getPlainText(html);.
But how do I know reference to this.

I'm not 100% sure I follow, but I think this is what you are looking for.

In your javascript file, you'll want code.set

API Reference

...

$('#yourTextArea').redactor('code.set', your.data);


Copy of Craft instance generates "An unknown error occurred" for login I needed to create a second instance of a craft 2.0 instance and so I copied the current instance to a new instance. I followed the directions found here: https://craftcms.com/guides/duplicating-a-craft-site

The structure is like this:

/var/www/html/my_site (original - contains the craft and public folders)

copied to:

/var/www/html/new_folder/my_site (this contains the craft and public folders)

There is a reverse proxy (Apache) that handles routing of the URL's.  The website comes up with no problems.  But, I cannot sign into the site to administer the site.  All I see is "An unknown error occurred."  There is nothing in the craft.log in the instance that indicates what the unknown error is.

Is there a value in the database tables that might be incorrect?  I have scanned for references to the original path and I don't find anything.  The document root in the Apache config files for the instance is correct.  There was a recommendation to delete the runtime folder after copying a Craft install and I have done that but I still get the error and there are no errors in the craft.log file.

One last interesting observation.  When I try the admin URL for the copied site e.g. http://copy.mysite.com/admin the login page for the original site is  displayed e.g http://orig.mysite.com/admin/login.  So, somewhere there is a reference lurking to the old site I copied.  I have changed general.php, db.php and search for references to the old host name but found nothing.

So I am going to answer my own question here: The solution was that something, I don't know what, what messed up in the DB. So I dropped the DB and then copied it over again from the original. That fixed it.  I never got an indication in the logs that the DB was the issue I just decided to start with replacing it and then work backward if necessary.

Thanks for the tips. At least it eliminated the obvious issues.


How do I enable redactor rich text editor in a front-end form? I have a front-end form for registered users to submit entries, however I'd like to have a WYSIWYG editor like the dashboard. How would I get redactor working with this form?

My form:

<form method="post" action="j" accept-charset="UTF-8">
        <input type="hidden" name="action" value="entries/saveEntry">
        <input type="hidden" name="redirect" value="/">
        <input type="hidden" name="sectionId" value="3">
        <input type="hidden" name="enabled" value="1">

        Title
        <input id="title" type="text" name="title">

         {% set jobTypeDropdown = craft.fields.getFieldbyHandle('jobType') %}
        Job Type
        <select name="fields[jobType]">
            {% for option in jobTypeDropdown.settings.options %}
                <option value="{{ option.value }}">{{ option.label }}</option>
            {% endfor %}
        </select>

        {% set jobCategoryDropdown = craft.fields.getFieldbyHandle('jobCategory') %}
        Job Category
        <select name="fields[jobCategory]">
            {% for option in jobCategoryDropdown.settings.options %}
                <option value="{{ option.value }}">{{ option.label }}</option>
            {% endfor %}
        </select>

        {% set jobStateDropdown = craft.fields.getFieldbyHandle('jobState') %}
        Job State
        <select name="fields[jobState]">
            {% for option in jobStateDropdown.settings.options %}
                <option value="{{ option.value }}">{{ option.label }}</option>
            {% endfor %}
        </select>

        Job City
        <input type="text" name="fields[jobCity]">

        Job Overview
        <textarea id="jobOverview" name="fields[jobOverview]"></textarea>

        Job Description
        <textarea id="jobDescription" name="fields[jobDescription]"></textarea>

        How to Apply
        <textarea id="howToApply" name="fields[howToApply]"></textarea>

         <button class="button login-btn" type="submit">Post Job</button>
    </form>

It’s technically possible to include Craft’s copy of Redactor on the front end:

{% includeJsResource "lib/redactor/redactor.js" %}
{% includeCssResource "lib/redactor/redactor.css" %}

<textarea id="jobOverview" name="fields[jobOverview]"></textarea>
{% includeJs "$('#jobOverview').redactor();" %}
...

But it’s not recommended. Redactor’s API and config settings frequently change, and we generally try to keep it updated with each new Craft version. If you started including Craft’s version of Redactor, you’re going to have to start testing your website to make sure your front-end Redactor fields are still working properly each time you update Craft to a new version.

(I’m also not sure about the legal implications. Craft comes with a Developer license of Redactor which gives us unlimited use of it, but whether or not end users of Craft are allowed to use it is a gray area you should check with Imperavi on.)

You’ll be better off in the long run by grabbing your own copy of Redactor and installing it yourself for the front end site.

Update:

We checked with Imperavi and the Developer license we purchased for Craft is allowed to be used on the front and back-end of Craft, although we still don't recommend it for the reasons listed above.


Is there documentation on Craft.AdminTable? My plugin has a many-to-many relationship and I would like to build a "associate" form with search/sort, and an icon to save selected record in the assoication table.   It would be great to leverage the Craft AdminTable feature, but I need to extend the 'deleteIcon' action.

Any suggestions?

None of Craft's JavaScript is documented.  Your best bet is going to be to look at the source itself in craft/app/resources/js.


Paginate performance issue I was wondering if anyone else has experienced a serious performance hit when implementing pagination?

By just using Safari's timeline, I can see my page takes 500ms to generate.  After introducing JUST the paginate tag (not including any loops etc), it now takes 1.5s!

Is this normal behaviour?  If not, what should I be doing to improve the performance?

Thanks

EDIT:  Thanks for the suggestions regarding caching.  I am aware of the cache tag however, the paginated entries are the results of a search query with various filters so I'm concerned that the caching will have little effect.  Or am I wrong?

Add the following tags around your {% pagination %}

{% cache %}
{% endcache %}

Those tags will refresh every time the content changes, and when the content hasn't changed, it'll reduce your database queries significantly.

For more info see:

The craft docs
What are the best practices for using the cache tag


Tag Localization: how to create a tag without translation fallback version? I'm dealing with tag localization on an English/Spanish site and have figured out that if I create a new tag, both En and Es elements are created by default, which would be O.K. if I never had to filter tags for locale.

I discovered that if I manually delete the duplicate element from the other locale, they do only show in their respective locales, which is ideal for this. Is there a way to do this via the admin UI?

I have made the tags field on my entries non-translatable, but what would stop Craft from creating duplicate elements for the other locale?

EDIT: Also, if I update a tag, the other locale version that I deleted is recreated automatically :/

OK, so this isn't quite how i expected it to work, but it does so far. I won't post code, because you just need the right process:

Assuming you're creating tags for a dual locale site of English (en) and Spanish (es)

Create a TagModel for first locale (en)
Set attributes and content for first en version
Save it
Load a new instance of a TagModel by loading the tag you just saved by id, but specify the other locale.

$tag_es = craft()->tags->getTagById($tag_en->id, "es")

Assign the es title, content and attributes (regenerate the slug, too!)
Save the es tag with

tags->saveTag($tag_es)

Now, Tag Manager should keep them separated by locale, and you can query them by locale, too.

The bottom line is, you have to create alternate locale versions by essentially cloning the original Tag Model while specifying the new locale string, then reassign the content and just save it. Again, not what I expected.

EDIT: Check your results in the database. Don't believe the Tag Manager — it only shows data from one locale for some reason.


How to set selected elements when creating modal with "createElementSelectorModal()"? I'm showing a modal using "createElementSelectorModal()"

In some cases I need to pass ids of elements which should be selected right after the modal is created. Is it possible?

If I'm interpreting 'craft.js' correctly, there doesn't seem to be any way to do this, at least not via craft methods. Apart from passing in the initial settings parameter, everything else looks like protected methods.

You could potentially do it manually through javascript however by triggering a 'click' event on the elements directly. You would have to wait until the elements are loaded first however.

$('.elements tr[data-id="2201"]').trigger('click');


How to output a Rich Text Link to an Entry as a tooltip? I have a Glossary channel on my site, with Term and Definition fields. I would like Terms to display their definitions throughout the site...whenever so assigned by the content editor.

I currently have Rich Text fields allowing editors to create links from Terms to their Definitions by using Link to an Entry. This is not great in terms of UX as it forces sends site visitors to the main Glossary index page to view the Definitions; I'd like to implement a hover text for the Terms that shows the Definition right there, wherever the visitor is reading.

How can I filter these rich text fields in the templates to check for links to Glossary entries and output a hover text instead of a link? I haven't written any custom plugins or filters (yet), so I'm looking for pointers in the right direction.

Any other approaches that might solve my problem are welcome.

Thanks in advance for your help.

Not really a craft solution — but easiest might be jquery/ajax. Since you know the base URI, you can just create a selector for the route, and work from there.

$("a[href*='route/to/definitions/']").each(function(){
    var $element = $(this);

    // ajax load content and place content in DOM somewhere
    $.get( $element.attr('href'), function(data) {
        $element.attr('data-definition') = data;
    });

    // click handler to prevent default link behavior
    $element.on('click', function(event){
        event.preventDefault()
    });

    // hover handler to display/hide definition
    $element.hover(displayDefinition, hideDefinition);
});

You could also potentially do a search/replace in twig, but it is not nearly as easy to manipulate as in js.


Adding 301 permanent redirections in Craft CMS I am not able to redirect any dead page. Although I have added the redirection but it is not getting reflected. Please help.

Not sure how you're trying to do the redirect, but the common ways in Craft are:

1) From .htaccess if you're using Apache: https://httpd.apache.org/docs/2.4/rewrite/remapping.html

2) Using a plugin that lets you set up redirects from the Craft control panel: https://plugins.craftcms.com/search?q=redirect


Calling template from controller redirects to dashboard How can I call a template with variable from a controller method? I tried following but it redirects to dashboard:

public function actionsetDate() {
        return craft()->templates->render('index');
    }

You will need to include your plugin handle, like:

$this->renderTemplate('myPluginHandle/index', array());


Fetching "Pending" Users Related To Entry Within Plugin This works (but only obtains the active users):

// get entry
$entry = craft()->entries->getEntryById($entryId);

// get existing users in field
$entry->customUserField->ids();

So in attempting to get the non-active users I've switched to using the ElementCriteriaModel but have been unsuccessful:

// get entry
$entry = craft()->entries->getEntryById($entryId);

// get field model
$field = craft()->fields->getFieldByHandle('customUserField');

// get all users for entry+field
$getUsers = craft()->elements->getCriteria(ElementType::User);
$getUsers->relatedTo([
    'targetElement' => $entry,
    'field' => $field,
    'status' => null  // user status null
]);

$users = $getUsers->find();

I'm certain I'm doing something wrong within my relatedTo parameters. Help!

As always, spent hours trying to figure this out and came upon the answer within an hour after posting the question on Stack.

Here's the working code:

    // get entry
    $entry = craft()->entries->getEntryById($entryId);

    // get ALL users related to entry
    $users = craft()->elements->getCriteria(ElementType::User);
    $users->status = null;
    $users->relatedTo = [$entry];
    $userIds = $users->ids();


Guest Entries - How I can send message to user after saving form information I use Guest Entries plugin to add information, and I need to send some message to user who filled the form to email. Can you show me an example of how I can do this?

You could do this with a small plugin that listened to the Guest Entries afterSaveEntry event.

The logic would look something like this:

use craft\guestentries\controllers\SaveController;
use craft\guestentries\events\SaveEvent;
use yii\base\Event;

// ...

Event::on(SaveController::class, SaveController::EVENT_AFTER_SAVE_ENTRY, function(SaveEvent $e) {
    // Grab the entry
    $entry = $e->entry;

    // Assuming `toEmail` is a custom field on the entry.
    Craft::$app->getMailer()->compose()
        ->setSubject('Thanks for your submission!')
        ->setTextBody('You are amazing.')
        ->setTo($entry->toEmail)
        ->send();
});

You can generate Craft 3 boilerplate plugin code using https://pluginfactory.io/ and the official Craft 3 Plugin docs are here: https://docs.craftcms.com/v3/extend/plugin-guide.html


Extending the Users section of the admin panel Is it possible to add additional tab views that aren't related to user fields?

We would like to show a summary of user account activity that includes details of purchases they have made. A plugin would work obviously but we would want all of this information in the existing user area rather than in a new area for the plugin.

Right now you're best bet is going to be with a plugin that has its own, separate section for displaying the purchase information.


form submission with checkbox list I have multiple checkboxs in a form

<input type="checkbox" name="Classification[]" value="Hub Zone">Hub Zone
<input type="checkbox" name="Classification[]" value="Not Applicable">Not

After submit Get info is:

 'Classification' =>
  array (
    0 => 'Hub',
    1 => 'Not Applicable',
  ),

and I get error : array to string conversion on below code

 'Classification'  => array(AttributeType::Mixed, 'required' => true, 'label' => 'Classification')

stack Trace:

PHP notice
Array to string conversion

/home/www/html/www3/craft/storage/runtime/compiled_templates/3d/3df3f71b6051f05e907988ee087f2136f9ad04870a88d4a66539df50db139f6d.php(39)

27         }
28         // line 6
29         if ((array_key_exists("fields", $context) && twig_length_filter($this->env, (isset($context["fields"]) ? $context["fields"] : $this->getContext($context, "fields"))))) {
30             // line 7
31             echo "    ";
32             $context['_parent'] = $context;
33             $context['_seq'] = twig_ensure_traversable((isset($context["fields"]) ? $context["fields"] : $this->getContext($context, "fields")));
34             foreach ($context['_seq'] as $context["_key"] => $context["field"]) {
35                 // line 8
36                 echo "        ";
37                 echo twig_escape_filter($this->env, $this->getAttribute($context["field"], "label", array()), "html", null, true);
38                 echo ": ";
39                 echo twig_escape_filter($this->env, $this->getAttribute($context["field"], "value", array()), "html", null, true);
40                 echo "
41
42     ";
43             }
44             $_parent = $context['_parent'];
45             unset($context['_seq'], $context['_iterated'], $context['_key'], $context['field'], $context['_parent'], $context['loop']);
46             $context = array_intersect_key($context, $_parent) + $_parent;
47         }
48         // line 12
49         if ((array_key_exists("footer", $context) && twig_length_filter($this->env, (isset($context["footer"]) ? $context["footer"] : $this->getContext($context, "footer"))))) {
50             // line 13
51             echo "

I think your checkboxes need to be as follows:

<input type="checkbox" name="fields[Classification][]" value="Hub Zone">Hub Zone
<input type="checkbox" name="fields[Classification][]" value="Not Applicable">Not