Change custom element Index title via getTableAttributeHtml? I want to change the title in the index of an custom element.

public function getTableAttributeHtml(BaseElementModel $element, $attribute)
{
    switch ($attribute)
    {
        case 'title' :
        {
            return $element->attribute . 'blabla';
        }

        ...
    }
}

But whatever I try, the title field didn't change. Other fields are no problem.
How can i do this?

I finally found the answer to this question.

From BaseElementType defineAvailableTableAttributes() docs,

  The first item that this array returns will just identify the database
  column name, and the table column’s header, but will not have any
  effect on what shows up in the table’s body. That’s because the first
  column is reserved for displaying whatever your element model’s
  __toString() method returns (the string representation of the element).

So all you need to do is add a __toString() method in your model and return the string representation of your element:

For example:

public function __toString()
{
   return $this->id;
}

Result:


Display images from Structure I have a Structure section (galeriesPhotos) with two Entry Types:

Albums - the categories on the index.html page
Photos - the the actual gallery on the entry.html

I'm trying to display the images related to the "Albums" on entry.html like this:

{% set entries = craft.entries.section('galeriesPhotos').getEntryType('Photos') %}

{% for image in entries %}
  <img src="{{ image.getUrl }}">
{% endfor %}

Nothing happens. I get a blank page without any errors. What I am doing wrong?

In the example code above, the query is retrieving a list of Entries and setting it to the variable entries.  Then, you are trying to loop through those Entries and treat them like they are a list of Assets.

As noted in the comments, this was complicating the situation.

It appears that, on the entry.html page, the entry variable was already available, as Craft makes that entry variable to all individual entry pages in Sections that have URLs.

This makes accessing the Assets field on that page as simple as accessing a field, rather than needing to create a separate query to find the data.  From the comments above, the solution was to just access the appropriate Assets field on the Entry Page template and loop through them:

{% for asset in entry.entryFieldHandle %}
    <img src="{{ asset.url }}">
{% endfor %}


Get random entry tagged with Looking to get a random entry from my database which is tagged with 'featured', is this possible at all? I've seen randomised by just the entry loop but nothing else.

You could try customizing the order parameter. MySQL allows ordering randomly by using .. ORDER BY rand(). So you could try the following:

craft.entries.section('featured').order('rand()').first()


Checking for first time an entry is "published" i.e. saved with a Live status Is there a way, via an Event or otherwise, to catch the first time a post is saved and isn't in disabled mode? I want to send out an email alert to users when a new entry is published, but I want it to be possible to work on it in disabled mode first.

If I use the entries.onSaveEntry event, it comes with the a param for isNewEntry, but I can't use this because it's only true the very first time an entry is saved, even if it's saved in disabled status. After that it will always return false.

It wouldn't be difficult to add an additional field to the entry that would track whether or not emails were sent, but I was wondering if there's a more straightforward way to handle it.

There isn't an "event" that gets fired when an entry goes live, but you should be able to listen to the onSaveEntry event, then check the same criteria that Craft uses to determine if an entry is live or not.

As far as tracking if it's the first time the entry had a live status or not, it's kind of lame, but your plugin could have a Record/table that kept track of the entry ID and status so you'd know if it was the first time an entry ID had a status of Live or not.


Query for entry related to current entry in section URI settings My entries within specific section can be related to each other using "Entries" field.

If entry1 "Entries" field is filled with entry2, i want to entry2 url look like this:

entry1/entry2

How can this be acomplished?

Your will need to set up a route for the entry1 section.

For example, if your entry1 uri is looke like entry1section/{slug}, and your template is like "_entry1section/index" then the route would be

entry1section/{slug}/* to "_entry1section/index"

Then in the template, using

{% set lastSegment = craft.request.getLastSegment() %}
{% set all_slug_in_entry1_section = someFunctionToRetrieveSlug() %}
{% set all_slug_in_entry2_section = someFunctionToRetrieveSlug() %}

{% if lastSegment in all_slug_in_entry1_section %}

  {# means your request url is {siteUrl}entry1section/{slug} #}
  {# display the content from entry1 #}

{% elseif lastSegment in all_slug_in_entry2_section %}

  {# means your request url is {siteUrl}entry1section/{entry1-slug}/{entry2-slug} #}
  {# display the content from entry2 #}

{% else %}

  {% redirect '404.html' %}

{% endif %}


Change plugin title in main side nav I'm creating a plugin but want to simplify the title that appears in the CMS' left-hand main navigation for my client. I understand that by default it pulls from the getName method but I want to choose something different than what's set there. Is it possible to do this?

Yes, it's possible. It will require two steps:

Create a setting in your plugin for pluginNameOverride
Use that setting in place of the default name of your plugin when loading your plugin

This does not change the name of the URL slug for your plugin in the admin URL and has different behavior in the UI in Craft 2 and Craft 3.

Craft 2

1) Add a new setting following the instructions in the docs: https://docs.craftcms.com/v2/plugins/plugin-settings.html#settings-page

2) Once you have your setting working. You can do this in the getName method of your primary plugin file:

public function getName()
{
    $pluginName = Craft::t('Your plugin name');
    $pluginNameOverride = $this->getSettings()->pluginNameOverride;

    return $pluginNameOverride ? $pluginNameOverride : $pluginName;
}

Note: While this changes the name in the nav, it also changes the name in several other places, such as the list of plugins on the plugin page. If a user changes it to something odd, it may not be obvious to you or someone else debugging that the website has your plugin installed.

Craft 3

1) Add a new setting following the instructions in the docs:
https://docs.craftcms.com/v3/extend/plugin-settings.html

2) Override the parent label value in the getCpNavItem method

public function getCpNavItem()
{
    $parent = parent::getCpNavItem();

    // Allow user to override plugin name in sidebar
    if ($this->getSettings()->pluginNameOverride)
    {
        $parent['label'] = $this->getSettings()->pluginNameOverride;
    }

    return array_merge($parent,[
        'subnav' => [
            'sectionName' => [
                'label' => Craft::t('your-plugin', 'Tab Name'),
                'url'   => 'your-plugin/section-name'
            ]
        ]
    ]);
}

Note: This just changes your plugin name in the sidebar URL. Your plugin will continue to use its original name in the settings area.


Element API throws 404 when not logged into CP My element API endpoint throws a 404 when I'm logged out of the CP, but works fine when I'm logged in.

When logged out it throws a regular 404 with stack trace exactly as any other non-existing url, when logged in it spits out JSON as it should be.

HTTP 404 – Not Found – yii\web\NotFoundHttpException
Template not found: news.json

Notably the front-end of the page works fine always..this just affects the element API.

I tried clearing craft caches + all cookies, still the same.
Found nothing suspicious in web.log, phperrors.log or web-404.log
I tried it with a very simple element-api.php and it still produces the same issue.

For example, even this element-api.php does not work:

<?php

use craft\elements\Entry;

return [
    'endpoints' => [
        'news.json' => function() {
            return [
                'elementType' => Entry::class,
                'criteria' => ['section' => 'news'],
                'transformer' => function(Entry $entry) {
                    return [
                        'title' => $entry->title,
                    ];
                },
            ];
        },
    ]
];

(copied straight from the docs. The section "news" exists in my DB and has valid entries.)

Any idea what could be the cause of this or where to further investigate?

This is on Craft 3.1.12.

The issue ended up being related to the yii debug toolbar failing to execute correctly. Disabling it in app.php fixed it.


setPasswordPath being ignored Any idea why the following would be ignored following a frontend new password form? The user group does not have access to the control panel.

'setPasswordPath' => 'account/login/password/new',

The following success path on the next line works fine:

'setPasswordSuccessPath' => 'account/login/password/done',

The user workflow:

Start on frontend Register form with firstname, lastname, email and password.
Account created and user is logged-in. No email confirmation needed.
User logs out.
User completes Forgotten Password form and email is sent.
User clicks password link in email and sees the Craft CMS password form.

I've tried this with and without the email address having a pre-existing Craft Commerce order associated with it. The result is the same.

Picking this up with another project, it looks like the problem was me not specifying a template path as the 'setPasswordPath' config setting. Instead, I was passing a route. I was doing this because I wanted to use the same password template to handle everything to do with passwords. This isn't possible, by the looks of it, because the controller is looking for the existence of a file (as opposed to a template being returned from a route or URI).

As soon as I changed it to a strict template path everything worked fine, and the following line in UsersController.php no longer returns false:

if (craft()->templates->doesTemplateExist($templatePath))

So this is solved.


How to check which DB craft is using? I'm having a weird issue trying to figure out which database my staging site (staging.domain.com) is connecting too. On my staging site, craft is up-to-date, but does not show the latest changes I made (added a new section and updated craft), which makes me think it's using the live database. However, if it's using the live DB, it should show craft as needing updates? All the other changes on the staging site are working fine (ie. tmpl & css updates).

So to troubleshoot, I added devMode to my staging site array to see if my keys were working properly. This added the devMode strip to the top of the CP. Next, I double checked both database on the server to make sure they were different. The staging DB has the new section I just added. Lastly, I cleared the cache to see if that made a difference.

Am I totally missing something here?

general.php:

return array(
    '*' => array(
        'cpTrigger' => 'cp-admin',
        'omitScriptNameInUrls' => true,
        'environmentVariables' => array(
            'basePath' => $base_path,
            'baseUrl'  => $base_url
        )
    ),
    '.dev' => array(
        'devMode' => true,
    ),
    'stage.' => array(
        'devMode' => true,
    ),
    '.com' => array(
        'cooldownDuration' => 0,
    )
);

db.php:

return array(

    '*' => array(
        'tablePrefix' => 'craft',
    ),

    '.dev' => array(
        'server' => 'localhost',
        'user' => 'root',
        'password' => 'root',
        'database' => '***pa_craft',
    ),

    'stage.' => array(
        'server' => 'localhost',
        'user' => '***pa',
        'password' => '***',
        'database' => '***pa_craft',
    ),

    '.com' => array(
        'server' => 'localhost',
        'user' => '***pa',
        'password' => '***',
        'database' => '***pa_craft_live',
    ),

);

Update

I just switched my local setup (dev) to point to the remote staging DB which connects and shows the updates. I also added a new entry to check to see if was writing to the correct DB.

If your domain name is actually staging.somedomain.com and your multi-environment config is searching for stage., then they won't match up.

What will match, however, is the .com key directly underneath it, which is probably what you're thinking is only for the live site.

Being more explicit with your matching multi-environment config keys will probably clear up the confusion.


Fixing Craft\HttpException Error Recently moved site to a new server.

Attempting to edit a post created before migration fails. The edit page reloads with the changes removed. Note: 1) this happens for only SOME, but not ALL of entries in the same channel. 2) the entries that fail and those that succeed are set to use the same templates.

Utilities - Logs shows this error message:

Level     error

Category  exception.Craft\HttpException.404

Message   Craft\HttpException in
  /home/method/craft/app/controllers/TemplatesController.php:72

That's it. mod_security is on by default and a rule is getting triggered. Turned it off and now the entry can be modified and saved. Thank you Brad!


Help with understanding how to structurally build a sermon catalogue I'm currently working on a website for a church and I thought that Craft would be perfect for the project and a great way to learn it. However, I'm having a hard time wrapping my head around how to structurally build sermons into a craft cms site.

I want it to look something like this.

Sermons > Series > Series Title, Series Artwork, Series Bio, Message Title, Date, short Bio, artwork, links to watch, links to listen, social links,

Similar to this website. https://newspring.cc/sermons

Could anyone provide any insight into what ways they'd build this? I guess I'm getting hung up on if I have to create 2 channels to make this work? One for Sermons, and one for each series?

Edit: I want to be able to add a sermon series as and entry. And then go in and add each week's message as a separate entry under that particular sermon series. Does that make sense?

There is probably no best answer. There are a number of ways to structure craft to support this, and any answer is going to be highly subjective. A lot will depend on the relationships between the elements, and what the requirements of the different elements are (i.e. how complex, etc).

One option to get the desired uri pattern (i.e. /sermons/series-name/sermon-name) would be to do something like this:

Create a single called sermons that would be the landing page for the sermons section.
In the sermons template you would display the sermons overview content, and retrieve and display the 'series' (perhaps ordered by date, or category, or whatever).
Create a structure to house 'series', with at least 2 levels, with the series collection at the root and the individual series items (a.k.a. sermons), beneath. The series collection and series items would each have a different Entry Type so that fields could be unique for collection vs. items, and you can display a different template depending on the Entry Type.
Set the uri for the 'series' structure to be 'sermons/{slug}' and for nested entries to be {parent.uri}/{slug}.
You could also create additional levels for video, artwork, etc. which would get added to the uri automatically (where each level or type of content might get assigned its own Entry Type based on the type of content your working with) (i.e. /sermons/series-name/sermon-name/videos/video-name).

There are lots of other options and considerations also, but this might be an easier one to deal with, without having to create your own custom routes to get the uri pattern you are looking for.

This assumes of course that an individual series item (or sermon) belongs to only one series. If not, then you may want to consider other options, such as creating a channel for 'series' and a channel for 'sermons' and then relate the two using an entries FieldType.

You can even take the structure concept further and map the whole site using a single structure, with different entry types for the different types of pages. This makes the nav very easy to build and the sections/pages can all be moved around easily. And you can always pull in other content into those pages from other channels as needed. OR create a structure for the rest of the site and structure for the series, where the uri's match up nicely.

Basically. Lot's of options.


Output error of the current password correctly In the Setting of an account on front-end I've added the possibility to change the password. Please enter your current password, then the new

<form id="userform" class="" method="post" accept-charset="UTF-8">

    <input type="hidden" name="action" value="users/saveUser">
    <input type="hidden" name="redirect" value="">
    <input type="hidden" name="userId" value="{{ user.id }}">

    {% macro errorList(errors) %}
        {% if errors %}

                {% for error in errors %}

{{ error }}

                {% endfor %}

        {% endif %}
    {% endmacro %}

    <input id="password" type="password" autocomplete="off" name="password" class="input-list password" value="">
    <input id="newPassword" type="password" autocomplete="off" name="newPassword" class="input-list password" value="">

    {% if account is defined %}
        {{ errorList(account.getErrors('password')) }} //Current password
        {{ errorList(account.getErrors('password')) }}
        {{ errorList(account.getErrors('newPassword')) }} //New password
        {{ errorList(account.getErrors('newPassword')) }}
    {% endif %}

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

Mistakes new password displayed and the error of the current password is not displayed, for example if it is wrong page just reboot and the data will not be saved. How to be

Change:

{{ errorList(account.getErrors('password')) }} //Current password

To:

{{ errorList(account.getErrors('currentPassword')) }} //Current password


Target first and last items and append if greater than 2 I am trying to loop through a list of categories to add some text to the page. If it is the last item I want to replace the ',' with the words 'and' but only adda a ',' if there are more than 2 categories.

{% set categories = craft.categories.group('products') %}
{% for category in categories %}
    {{ loop.last ? 'and ' }}{{ category.title }}{{ loop.index > 2 ? ', ' }}
{% endfor %}

if there is only category it would output:
hello

So if there are two categories it would output:
hello and world

if there are 3 or more it would output:
hello, world and space

My current code looks like this. but isn't quite working correctly.
Anyone able to help? or point in the right direction?

Thanks.

The way I would think of it is: I print the category title, then if this is not the last category I print the separator (and or ,). I would use the loop variable revindex to distinguish the next-to-last category (which gets the and) from the others (which get the ,). loop.revindex is like loop.index except that it counts the number of iterations from the end. So your code starts to look like this:

{% for category in categories %}
  {{category.title}}
  {% if not loop.last %}
    {{ loop.revindex == 2 ? ' and' : ',' }}
  {% endif %}
{% endfor %}

That code will leave a space before the ,, which you can fix by sticking everything on one line:

{% for category in categories %}
  {{category.title}}{% if not loop.last %}{{ loop.revindex == 2 ? ' and' : ',' }}{% endif %}
{% endfor %}


Load more images in matrix block I have a matrix block called team that has an assets field within it that has all of the companies headshots. However, there are more than 30 images, but the design is to only have 6 showing on load, and then on click of a load more button the next 6 will show, etc.

However, I'm not sure how to achieve this within a matrix block as all the examples I've seen elsewhere are for pages and sections. But I just need to load the images from within the matrix block.

Below is my code for the images. Can someone help?

{% for headshot in block.headshots %}

  {% if headshot | length %}
  {% set transformedImages = craft.imager.transformImage(headshot,
      [
          { width: 180, ratio: 4/5 },
      ],
      {
          format: 'jpg',
          allowUpscale: false,
          mode: 'crop',
          jpegQuality: 80,
          position: headshot.focalPoint,
          interlace: true
      }
  ) %}
  {% set tabletl = craft.imager.transformImage(headshot,
      [
          { width: 142, ratio: 4/5 },
      ],
      {
          format: 'jpg',
          allowUpscale: false,
          mode: 'crop',
          jpegQuality: 80,
          position: headshot.focalPoint,
          interlace: true
      }
  ) %}
  {% set tabletp = craft.imager.transformImage(headshot,
      [
          { width: 230, ratio: 4/5 },
      ],
      {
          format: 'jpg',
          allowUpscale: false,
          mode: 'crop',
          jpegQuality: 80,
          position: headshot.focalPoint,
          interlace: true
      }
  ) %}
  {% set mobile = craft.imager.transformImage(headshot,
      [
          { width: 360, ratio: 4/5, jpegQuality: 65 },
      ],
      {
          format: 'jpg',
          allowUpscale: false,
          mode: 'crop',
          position: headshot.focalPoint,
          interlace: true
      }
  ) %}
  <picture>
  <source srcset="{{ craft.imager.srcset(mobile) }}" media="(max-width: 767px)">
  <source srcset="{{ craft.imager.srcset(tabletp) }}" media="(min-width: 768px) and (max-width: 991px)">
  <source srcset="{{ craft.imager.srcset(tabletl) }}" media="(min-width: 992px) and (max-width: 1199px)">

  </picture>
  {% endif %}

{{ headshot.title }}

{{ headshot.jobTitle }}

{% endfor %}

Your block.headshots is not an array of all images, you have to understand what craft does in order to work properly with it.

block.headshots and all other relations (Matrix elements, images, category links...) are all elementCriteriaModels so instead of having an array of objects - your block.headshots is just a single object that has an iterator interface.

So when you execute {% for headshot in block.headshots %} it performs the .find() function and returns an array.
Unfortunately I'm not on my computer currently so I can't provide the exact code so maybe the syntax of something of the following might be wrong, but if you know how to search entries with craft.entries.find() click you can correct it, here you have more examples elementCriteriaModel. Your code should look like

{% for headshot in block.headshots.find({limit: 10}) %}

It does not matter if you are searching pages (entries), assets, matrix blocks, sections, categories or whatever.. Craft does always the same, building an elementCriteriaModel that is executed as soon as you loop through it.

edit: your controller to load the assets could look like this

public function actionLoadAssets(){
    $this->requireAjaxRequest();
    $response = array(
        'success'   => false,
        'message'   => ''
    );

    // config how many entries should be loaded
    $config = craft()->globals->getSetByHandle('config');
    $limit = $config['countReloadImages'];
    // offset.. how many did we load already
    $offset = craft()->request->getPost('offset');
    // which block is it
    $matrixIndex = craft()->request->getPost('matrixIndex');
    // entryId
    $entryId = craft()->request->getPost('entryId');

    if($entry = craft()->elements->getElementById($entryId)){
        // search for the correct field -> we just insert an offset
        // this is untested, maybe you have to play around with the correct number
        // I'm not sure if you can just send the id of the matrixfield and use 'id' => $matrixIndex
        // you could to try it out...
        $matrix = $entry->team->find([
            'offset'    => $matrixIndex
        ]);
        $html = '';
        if($matrix && ($assets = $matrix->headshot->find(['offset' => $offset, 'limit' => $limit]))){
            // build a template to render the images, you'll return the html
            $html = $this->renderTemplate('some tempalte here', array(
                'asset' => $assets
            ));
        }
        // you could include your logic if you found less entries than configured ($limit) and return a "hide reload button"
        $response['html'] = $html;
        $response['success'] = true;
    }else{
        $response['message'] = Craft::t('could not find entry with Id ' . $entryId);
    }

    return $response;
}

Edit2: I found a better solution:

public function actionLoadMore(){
    $criteria = craft()->elements->getCriteria(ElementType::Asset);
    // id of your field headtshot
    $field = craft()->fields->getFieldById(5);

    $criteria->relatedTo = array(
        'sourceElement' => //your matrix ID,
        'field'         => $field->id
    );
    $criteria->offset = //your offset;
    $criteria->limit = //your limit;
    $assets = $criteria->find();

    // render template -> return html look at the first example
}


Craft backup "mysqldump: not found..." I'm getting an error message when trying to back up the Craft DB.

2019-09-04 10:21:09 [-][1][6eba342acf082a62ea47300d68faddf4][error][yii\base\Exception] yii\base\Exception: Could not create backup: The shell command "mysqldump --defaults-extra-file="/var/www/html/storage/runtime/temp/my.cnf" --add-drop-table --comments --create-options --dump-date --no-autocommit --routines --set-charset --triggers --single-transaction --no-data --result-file="/var/www/html/storage/backups/client-name_190904_172109_fnrhjpwxac_v3.2.10.sql" craft && mysqldump --defaults-extra-file="/var/www/html/storage/runtime/temp/my.cnf" --add-drop-table --comments --create-options --dump-date --no-autocommit --routines --set-charset --triggers --no-create-info --ignore-table=craft.assetindexdata --ignore-table=craft.assettransformindex --ignore-table=craft.sessions --ignore-table=craft.templatecaches --ignore-table=craft.templatecachequeries --ignore-table=craft.templatecacheelements --ignore-table=craft.cache --ignore-table=craft.templatecachecriteria craft >> "/var/www/html/storage/backups/client-name_190904_172109_fnrhjpwxac_v3.2.10.sql"" failed with exit code 127: sh: 1: mysqldump: not found in /var/www/html/vendor/craftcms/cms/src/controllers/UtilitiesController.php:343

I'm not sure where to look to solve this. How may I get the DB to back up?

Your server seems to be missing the shell command mysqldump, contact your IT-Specialist and tell him you need that to be installed you can backup your website.

Or if you plan on installing it yourself, this should do the trick.

Excerpt  from there:

sudo apt-get install mysql-client-5.7

If it's not able to find the package, try entering the statement till the mysql part and then hold tab it should then show you all available versions which you can install.


Deploying and syncing project.yaml I have a Craft CMS site set up that deploys through TeamCity and am trying to set up a build step to auto run "./craft project-config/sync".

I keep getting an error saying the file can't be found, I've changed the paths a dozen times to try and get it right but no luck.
Has anyone had experience with this or able to advise how to set this up?

Got this working with help from Udo's answer.
For anyone using TeamCity who would find this useful I'll share my setup for it.

First I deploy the site from a Git VCS root and use the 'SSH Upload' runner type

Then I was trying to set up the sync command through an 'SSH Exec' runner but that didn't seem to work, not sure what the issue was with it so might be able to set it up that way still.
The working method is the 'Command Line' runner, set it to run a custom script with the code provided by Udo, ssh {user}@{host} {file_path}/craft project-config/sync the command line is run from the TeamCity agent server not the production server like the SSH Exec runner is meant to.

Additional note to make sure the craft file is executable, if not you will need to do chmod a+x craft


Create order programmatically in Craft Commerce I want to create order via code in Craft Commerce. How can I achieve that?

Thanks in advance.

First of all, it's important to know what version(s) of Craft and Commerce you're referring to. The code used in this answer applies to Craft 3, with Commerce 2-beta. Code for Craft 2 and Commerce 1 would look different, but the logic is similar.

I would start by looking at Commerce's codebase on Github (or in your plugins folder, if it's Craft 2), and more specifically the OrdersController, and even more specifically the actionSaveOrder and _setOrderFromPost methods.

It looks to me like you need to do two things:

Get an Order model:

// Find an existing order by ID
$order = Commerce::getInstance()->orders->getOrderById($orderId);

// ... Or create a new one
$order = new Order; # Don't forget to place use craft\commerce\elements\Order above your class

Populate the model (untested)

If you have an order model, you have to populate all the fields that matter. Status, addresses, I think you'd best start on an individual order page in the admin to see what fields are needed.

$order->isCompleted = true;
$order->billingAddressId = 4;
$order->gatewayId = 7;
... etc (includes creating and adding line items for your order)

Save the order and show why it doesn't work magically the first time around ;)

This is where the fun starts, which might depend on your definition of fun.

if (!Craft::$app->getElements()->saveElement($order)) {
    var_dump($order->errors);
}


Send activation email only for users created over the Control Panel We have a website that allows users to register themselves with a front-end registration form, and are automatically logged-in once they're done (thanks to autoLoginAfterAccountActivation).

But we also need to create users directly from the Control Panel on a regular basis.
Since autoLogin doesn't work with the "Verify email addresses?" user setting, I'm looking for a way to send the activation email only to the users that we have manually created over the Control Panel, so they're able to set a password.

Is there any way to send the verification email only to users created over the Control Panel?

You'll need to create a small custom plugin to do this. You can create the scaffolding for a plugin using the excellent Plugin Factory site. You'll just need to create a basic plugin, with none of the component options selected.

What you need to do is to use Craft's events to detect when a new user is created using the Control Panel.

The specific event you need to listen for is the users.onActivateUser event.

You'll need something like this in your plugin's init() method:

/**
 * @return mixed
 */
public function init()
{
    // When creating new users through the control panel, send them a password reset email.
    craft()->on('users.activateUser', function(Event $event) {

        // only fire if this is a CP request
        if (craft()->request->isCpRequest()) {

            // retrieve the userModel from the event
            $user = $event->params['user'];

            // send password reset email
            craft()->users->sendPasswordResetEmail($user);
        }
    });
}


Format keys in Element API plugin 'criteria' => [
    'section' => 'news',
    'date' => craft()->request->getPost('date')
],

How to make that worked like this:

'criteria' => [
    'section' => 'news',
    'date->format("Y-m-d")' => craft()->request->getPost('date')
],

Something like this should work just for selecting a "day".

'criteria' => [
    'section' => 'news',
    'customDateFieldHandle' => ['and', '>='.DateTime::createFromString(craft()->request->getPost('date'))->format("Y-m-d").' 00:00:00', '<='.$DateTime::createFromString(craft()->request->getPost('date'))->format("Y-m-d").' 23:59:59')];
],


How to tell if user exists I am automatically creating users in a service, is there a way to check if user exists?

I want to log in id user exist or save a new user if it doesn't, I have the following so far which will add a user:

public function add($user)
{
    craft()->users->saveUser($user);

    $user = craft()->users->getUserByUsernameOrEmail($username);
    craft()->userSession->loginByUserId($user->attributes['id']);
}

Something like this should work:

public function add($user)
{
    $existingUser = craft()->users->getUserByUsernameOrEmail($user->username);

    if ($existingUser)
    {
        // They exist... log them in.
        craft()->userSession->loginByUserId($existingUser->id);
    }
    else
    {
        // They don't exist... create them.
        craft()->users->saveUser($user);
    }
}


Can a plugin manually raise another plugin's Event? I have created an Adjuster which is attached to commerce_lineItems.onPopulateLineItem.

The discount criteria is based on validation of a completely separate coupon API, so I created a permission-less user group in order to allow my client to continue using the Commerce Discounts UI. In my adjuster, I had to override the the matchLineItem() method in order to bypass the $discount->allGroups check. I'm using Craft's httpSession to persist the criteria through the checkout process.

Everything works fine, however if the user adds a product to the cart and THEN authenticates, the discount doesn't get applied until they either a.) update the cart or b.) raise the commerce_lineItems.onPopulateLineItem event again.

I've tried adding craft()->commerce_orders->saveOrder($cart) at the end of a successful API call, however that doesn't seem to trigger the event.
Is there another event I can use that will also update the cart or can I somehow raise an already declared CEvent? I've tried everything I know including hitting actionUpdateCart() with Guzzle!

I know this is a very edge case situation, so just to (briefly) illustrate I've added a portion of my base plugin below.

public function init()
{
    require_once __DIR__ .'/vendor/autoload.php';
    $this->check_membership();
    /*
     Load Premium Member Adjusters if $is_premium_member is true
    */
    craft()->on('commerce_lineItems.onPopulateLineItem', function($event){

        $lineItem    = $event->params['lineItem'];

        if ($lineItem->purchasable instanceof Commerce_VariantModel){
            if ($this->is_premium_member) {
                $this->adjusters = [
                  599 => new WorkshopAdjuster
                ];
            }
        }
    });
}

I've built a plugin which uses it's own events before, I guess the way to do it would be the same for separate plugins, however this is untested for your use case.

This should go in your plugin service

// Import the event from the other plugin
Craft::import('plugins.otherPluginHandle.events.OtherPluginEvent');

/Initialise the plugins event and pass whatever is required to it.
$event = new OtherPluginEvent($this, array('request' => $request));

// Raise it.
$this->raiseEvent('OtherPluginEvent', $event);

Again I haven't tried this from the context of calling another plugins event, but that is what I do from a plugins own event...


Is it possible to route to www.site.com/username? So what I'd like is:

If URI would look like {username}, load _thisTemplate.

Couldn't find the way without solid point like author ID.

I would not particularly advise creating a uri pattern that was just 'www.site.com/username' because usernames can essentially be anything which might cause routing conflicts (i.e. if the username is 'index' for example). You could however use something like 'www.site.com/members/username' or 'www.site.com/u/username'.

One way to do this would be to add a route using a 'subpattern'. For more info check out the routing docs on accessing subpatterns in your templates.

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

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

You could essentially do the same thing but with a 'username' variable.

'u/(?P<username>[^\/]+)' => '_thisTemplate',

You can then use the 'username' variable in your template to retrieve the corresponding user.

{% set user = craft.users.username(username).first() %}
{% if user %}
    {{ user.firstName }}
    ...
{% else %}
    {% redirect 404 %}
{% endif %}


Update User Profile with Plugin I'm trying to create a plugin to create/update users' profile data. I figured out how to create a user but updating... not so much.

Here is the code I'm using:

$user = craft()->userSession->getUser();
$user->setContent(array('middleName' => "Dave"));
craft()->users->saveUser($user);

From what I understand the "saveUser" method is used for both creating and updating user data. Whenever I run the code I get the following error:

CDbCommand failed to execute the SQL statement: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1-en_us' for key 'craft_content_elementId_locale_unq_idx'

If "saveUser" is truly used for creating and updating what am I doing wrong?

I'm not sure if this is causing your error, but it's recommended to use setContentFromPost() or getContent()->setAttributes() so that craft has a chance to prep the field values, as discussed in this answer, setContent() vs $entry->getContent()->foo, and What is getContent()?.

$user = craft()->userSession->getUser();
$user->getContent()->setAttributes(array(
    'middleName' => "Dave",
));
craft()->users->saveUser($user);

Although with that error it's possible that something else is going on in your plugin.


Why is news/_entry not extending _layout? I'm quite sure the problem is my paths to .css files in the _layout.html file but just can't get my head around it.

I've got this in my _layout.html. It works for home page and news page.

{% includeCssFile "css/material.css" %}
{% includeCssFile "css/main.css" %}

But then I get the unstyled page when viewing a specific news entry. _entry.html is not extending _layout.html

My CSS files are on the same level as my templates. What should these paths be?

News/_entry should definitely be extending _layout (or any layout you want to use). That's how it's setup when you download a fresh copy of Craft as well.

{% extends "_layout" %}

The CSS file should not be in the templates folder (that's only for twig templates), but in your web root which is the same folder as index.php. In your case that would probably be something like public/css/material.css and public/css/main.css Also make sure that any assets used in these CSS files are located in that folder instead of the templates folder.

Unless these CSS files are specific to the news entry template I'd also include them in the layout file.


Change how the PDF filename is formatted? In the Commerce plugin, there are several ways to download a PDF of a specific order.

However, the default formatting of the PDF filename isn't very helpful...

  Order-14ef9b78dae6893cd2ca75ec047ed9a0.pdf

Is there any way to control the formatting of PDF receipt filenames?

There's currently not a native way to change this format, but it is planned for a future release.

In the meantime as a workaround, you can listen to the onBeforeSaveOrder event and change the order number to whatever format you want.  A by-product of that is that the PDF receipt filename should change to your format as well.


Lookup element by URL I'm trying to get an element from it's URL.

For example, say we have a url of http://craft.dev/blog/article1. Is there a function I can call within a plugin and pass over blog/article1 that will return a corresponding element, if one exists, for that specific URL? I'm sure there is a way to do this with the router, I'm just not sure what it is.

Try using ElementsService:

$entry = craft()->elements->getElementByUri( 'blog/article1' );


GIF animations garbled and static When I upload animated gif assets to a Craft site, they end up static and corrupted, as so:

(Original here.)

My guess is that what's displayed is the last frame of the animation (which only contains pixels changed from the penultimate frame).

Other image resizing functions work. The site is hosted on a dedicated Ubuntu box with PHP 5.3.10. Here's what phpinfo() says about my ImageMagick/Imagick install.

imagick module version => 3.1.0RC1
imagick classes => Imagick, ImagickDraw, ImagickPixel, ImagickPixelIterator
ImageMagick version => ImageMagick 6.6.9-7 2014-03-06 Q16 http://www.imagemagick.org

Calling convert source.gif -resize 123x123 dest.gif works on the server—the issue seems to lie in the PHP call to ImageMagick rather than in the installation itself. Answers to this question indicate that GIF issues disappear with the proper configuration, but I fail to see what's lacking in this particular setup.

Updating PHP on the server to at least 5.4 fixed the issue. This is apparently a known Imagick issue with PHP 5.3.


Processing Business Logic on user.saveUser I have the following code in my plugin.

public function init()
{
    parent::init();

    craft()->on('users.saveUser', function(Event $event) {

    // only fire if new user
    if ($event->params['isNewUser']) {

        // business logic
        // how do i save result to custom user fields etc...

    }
 });
}

I guess my question is whether the userRecod has already saved at this point? If so do I need to create another user object, make changes and call .save again? Or is the user still available to me?

The user has already been saved at this point and is available as $event->params['user']. If you modify data and save again, however, you will need to be careful of creating an endless loop — not sure what you are trying to do. In this case you should be ok because of the "IsNewUser" conditional.

public function init()
{
    parent::init();
    craft()->on('users.saveUser', function(Event $event) {

        if ($event->params['isNewUser']) {

            $user = $event->params['user'];
            // update default fields
            $user->firstName = "Bob";
            // update custom fields
            $user->getContent()->setAttributes(array(
                'phone' => "222-222-5555"
            ));
            // save user
            $success = craft()->users->saveUser($user);

            if (!$success) {
                MyPlugin::log('Couldn’t update user "'.$user->username.'"', LogLevel::Error);
            } else {
                MyPlugin::log('Successfully updated user "'.$user->username.'"', LogLevel::Info);
            }
        }

    });
}


Query entries relatedTo multiple categories in controller I have an AJAX GET call that should count all the products matching three different taxonomies.

Product families
Sectors of application
Liquids suitable for the product

so in the form the user could select pumps, agriculture, diesel and the controller called should count the products that matches all those criteria.

I get the solution in the templating engine:

{% set relationParams = ['and', id1, id2, id3 ] %}
{% set products = craft.entries.section('products').relatedTo(relationParams) %}

But something is not working as expected in the controller:

        $prodCriteria = craft()->elements->getCriteria(ElementType::Entry)->section('products');

        $prodCriteria->relatedTo = array(
            'and',
            'targetElement' => $catIds // Where $catIds is an array of ids
        );
        $products = $prodCriteria->count();

        $this->returnJson( $products );

It seems like relatedTo behave like an or operator.
Also, is it possible to make the relatedTo behave in a more complex way, like, I want to use or for product families and and for other taxonomies?

You need to pass an array of element IDs, where the first index is "and" – just like in your template (Twig) code – to targetElement. Basically, this just means that you need to prepend the string "and" to your array of IDs.

Something like this should do it:

...

$prodCriteria->relatedTo = array(
    'targetElement' => array_merge(['and'], $catIds),
);


Smart Map with linked SVG icons for markers I have a smart map where I'm trying to use linked SVG files for the marker icons. In Safari, the files load at actual size, which in this case is fine, but in Chrome and Edge, they are scaled up, and in Firefox and IE, they don't show up at all.

I tried setting a size using marker options, but it looks like that doesn't support google.maps.MarkerLabel properties:

{% set options = {
    markerOptions: {
        scaledSize: 'new google.maps.Size(50,50)',
    },
} %}

If I replace the SVG icon with PNGs, they work fine in all browsers.
Is there a different way to specify the icon size/path for SVGs?

Turns out, there was a bug in Smart Map which made this impossible. Fortunately, it's now fixed!
As of Smart Map v2.4.2, it is possible to build more elaborate markers using a nested syntax for the markerOptions value. Try something like this...
{% set options = {
    markerOptions: {
        icon: {
            url: '/path/to/svg/file',
            scaledSize: 'new google.maps.Size(50,50)'
        }
    }
} %}


Get field that contains search query After a standard search with something like:

{% set results = craft.entries.search( query ) %}
{% for result in results %}

{{ result.link }}

{% endfor %}

Is there a way to find out which field the query was found in?

This currently isn't possible natively in Craft, but if you think it should be,  you can create a feature request!


Craft 3 js - extend the field layout designer field settings I would like to have the ability to include a custom option in the field layout designer field settings. There is already a plugin for Craft 2 that uses this feature Relabel for Craft

And I would like to include a behavior like this in Craft 3 too but I can't find a way to solve this issue.

The FieldLayoutDesigner is initialized here and the settings are created with

initTab: function($tab) {
    if (this.settings.customizableTabs) {
        var $editBtn = $tab.find('.tabs .settings'),
            $menu = $('
').insertAfter($editBtn),
            $ul = $('
').appendTo($menu);

        $('
' + Craft.t('app', 'Rename') + '
').appendTo($ul);
        $('
' + Craft.t('app', 'Delete') + '
').appendTo($ul);

        new Garnish.MenuBtn($editBtn, {
            onOptionSelect: $.proxy(this, 'onTabOptionSelect')
        });
    }

    // Don't forget the fields!
    var $fields = $tab.children('.fld-tabcontent').children();

    for (var i = 0; i < $fields.length; i++) {
        this.initField($($fields[i]));
    }
},

But I don't see any triggers or other options to extend the content. Can someone please point me to the right direction how to include a custom button properly?

I think waiting for the click event on the wheel icon and wait until the DOM menu is created to attach a custom button might not be the best and intended idea?

Thank you very much.

If someone has a better approach to solve that please tell me because my method right now fells really wrong and like a hack that might be troublesome in the future. I would like to accept the answer of someone else - until then I'll use the following

onKeyDown: function(ev){
    ev.preventDefault();
    var btn = $(ev.target);
    if(btn.data('menubtn')){
        var menu = btn.data('menubtn');
        var options = menu.menu.$menuList;
        if(options.find('.myClass').length === 0){
            options.append('
Another Button wuhu ^.^
')
        }
    }
},
init: function () {
    var e = this;
    var icons = $(".settings.icon");
    $.each(icons, function(index, item){
        var menuBtn = $(item).data('menubtn');
        if(menuBtn){
            var $menu = menuBtn.menu;
            $menu.on('show', $.proxy(e, 'onShowMenu'));
            e.addListener($(item), 'mousedown', 'onKeyDown');
        }
    });
    // add the event listener
    Garnish.$doc.on('click', '.myClass[data-action="myCustomDataAction"]', this.showHoverMenu.bind(this));
},


Multiple and or relatedTo in plugin element criteria I am trying to return entries that relate to a series of categories.

For example, I am trying to return clothing, in this example, I want to return all entries related to (flannel or denim) and (blue or red) in the products channel.

Flannel, denim, blue and red are all apart of the same category group called: filters, and the category field handle is productFilters

I was trying to return all those entries but it returns 0 entries, any help is appreciated. I know I can do this probably using the craft cms element query in the template but I need to do this in a plugin.

$color_categories = craft()->elements->getCriteria(ElementType::Category, [
    'slug'  => ['blue', 'red'],
    'group' => 'filters'
])->find();

$fabric_categories = craft()->elements->getCriteria(ElementType::Category, [
    'slug'  => ['denim', 'flannel'],
    'group' => 'filters'
])->find();

$entries = craft()->elements->getCriteria(ElementType::Entry, [
    'section'           => 'products',
    'relatedTo'         => ['and', $fabric_categories, $color_categories],
]);

return $entries;

Aren't you missing the ->find() on the last bit?

$entries = craft()->elements->getCriteria(ElementType::Entry, [
    'section'           => 'products',
    'relatedTo'         => ['and', $fabric_categories, $color_categories],
])->find();
return $entries;


How to link images inside an order PDF? In my order PDF template I have an image that shows when I preview the template as a web page but not in the generated PDF. I’ve tried SVG, PNG and JPEG.

If I use a relative path I get the error Image not readable or empty. With an absolute path I get DOMPDF_ENABLE_REMOTE is set to FALSE.

I found any relative link should not lead with a slash.


How to implement "cookie consent message" to visitors of our website using Craft 3 I want to implement cookie using message to the visitors of our site. How we will implement this in craft 3?

A sample message is

"Hi there, we use cookies to offer you a better browsing experience and to analyse site traffic. By continuing to use our website, you consent to the use of these cookies. Learn More"

This will appear like a popup in footer of the page.

Thanks

Just search for "Cookie" in the plugin store. There are several free ones along with some paid. I have used the Cookie Consent Banner on a couple sites.


Custom Plugin for ZenDesk Tickets I need all of the custom fields on an order submitted to ZenDesk to create a new ticket once the order is completed.

Once a ticket is created in ZenDesk, we will need the ticket number saved on a new custom field on the order. This will be used later for grabbing comments on the ticket.

There is a Zendesk plugin for Craft CMS that could be of use:

https://plugins.craftcms.com/zendesk

  This plugin can work either as a dashboard widget on your clients website, or you can post to it from a frontend form on your own website.


Is there a prescribed way to to represent complex field types as strings? I've found the need lately for a way to represent complex fieldtypes like Matrix, Entries, etc as strings. e.g. in the following plugins:

https://github.com/boboldehampsink/auditlog
https://github.com/boboldehampsink/export

Currently, it seems like you have to more or less account for every fieldtype and do some special processing.

I'm wondering if there is a method that every fieldtype can use (__toString or other) to do this kind of thing in a unified manner.

I was looking at how Craft does the Matrix "preview" for collapsed rows, but I think that's just all JS.

There isn’t, and yeah, the collapsed Matrix block preview text is just created with some Javascript that checks the fields and their inputs within each block.


Copy the Entry Type along with its field layout For a current project, I am attempting to automate the creation of a section.

I am using a default_section as the base of all the others. This section will contain a couple of entries, and a couple of entry types.

My goal right now is to copy over the Entry Types in its totality. Right now, I'm struggling with the field layout that I have set for the Entry Type

Let's say that the first Entry Type has the following field layout:

And this is the code that I am using

private function copyEntryTypes($savedSection, $entryTypes)
{
    foreach ($entryTypes as $entryType) {
        $copiedEntryType = $entryType;

        $newEntryType = new EntryTypeModel();
        $copiedEntryType->id = null;
        $copiedEntryType->sectionId = $savedSection->id;
        $values = $copiedEntryType->attributes;
        $newEntryType->setAttributes($values);

        $currentLayout = $copiedEntryType->getFieldLayout();
        $currentTabs = $currentLayout->getTabs();
        $postedFieldLayout = array();

        foreach ($currentTabs as $tab) {
            $fields = $tab->getFields();

            foreach ($fields as $field) {
                echo '<pre>' . var_export($field->attributes) . '</pre>';
                $postedFieldLayout[$tab->name][] = $field->fieldId;
            }
        }

        $requiredFields = array();

        $fieldLayout = craft()->fields->assembleLayout($postedFieldLayout, $requiredFields);
        $fieldLayout->type = ElementType::Entry;
        $newEntryType->setFieldLayout($fieldLayout);

        //TODO: New Entry Types are succesfully being copied. Now all I need is to move over the fieldset

        if (craft()->sections->saveEntryType($entryType))
        {
            var_dump('Successfully appended fields.');
        }
        else
        {
            var_dump('Could not append the fields.');
        }
    }

    return true;
}

//note: this code is WIP, so it's not super clean, sorry.

The result is that the fields are being looped through correctly, I can var_dump them and find the correct ID's. The problem is that the resulting EntryType I have made does not contain the layout I am trying to copy over.

That's looking like this:

After hours I managed to fix it. I'm assuming I made an error where I was trying to copy the Fields in the Entry Type I literally just created. So it was copying over 0 fields.

I built the functions from scratch again and finally found the working code. For future reference or to help others, here is the snippet in question.

private function CopyEntryTypes($savedSection, $baseSection)
{
    $baseSectionEntryTypes = $baseSection->getEntryTypes();

    foreach ($baseSectionEntryTypes as $baseSectionEntryType) {
        $newEntryType = $this->createNewEntryType($baseSectionEntryType, $savedSection->id);
        //oke so the New Entry Type is saved, we should get a return statement from the function
        //now loop through the tabs/fields of the baseSection Entry Type.

        $currentLayout = $baseSectionEntryType->getFieldLayout();
        $currentTabs = $currentLayout->getTabs();

        // This will the array passed to assembleLayout
        $postedFieldLayout = array();

        // Loop through each tab and build our array
        foreach ($currentTabs as $tab) {
            $fields = $tab->getFields();
            foreach ($fields as $field) {
                $postedFieldLayout[$tab->name][] = $field->fieldId;
            }
        }

        //so now we have a collection of entry types, each of them have a tab-name which we can use to identify
        //the goal is to get 'all' the tabs into the new entry type.
        $requiredFields = array();

        // Assemble the layout
        $fieldLayout = craft()->fields->assembleLayout($postedFieldLayout, $requiredFields);
        $fieldLayout->type = ElementType::Entry;
        $newEntryType->setFieldLayout($fieldLayout);

        // Save it
        if (craft()->sections->saveEntryType($newEntryType))
        {
            Craft::log('Successfully appended fields.');
        }
        else
        {
            Craft::log('Could not append the fields.', LogLevel::Warning);
        }
    }
}

private function createNewEntryType($baseSectionEntryType, $savedSectionId)
{
    $newEntryType = new EntryTypeModel();
    $baseSectionEntryType->id = null;
    $baseSectionEntryType->sectionId = $savedSectionId;
    $values = $baseSectionEntryType->attributes;
    $newEntryType->setAttributes($values);

    if (craft()->sections->saveEntryType($newEntryType))
    {
        var_dump('Successfully saved Entry Type.');
    }
    else
    {
        var_dump('Could not save the Entry Type.');
    }

    return $newEntryType;
}

I'm also using code that I modified from: How can I programmatically add a tab to entry type? so this guy deserves the credit.


Correctly using eager loading in Plugin development I'm trying to get some data with eager loading, which results in more queries than before.

Is there another way to tune down the number of queries as low as possible? As you can see i only need the posBrandKey (text) and id values.

$criteria = craft()->elements->getCriteria(ElementType::Category);
$criteria->status = null;
$criteria->limit = null;
$criteria->group = 'productBrand';
$criteria->with = array('posBrandKey');

$brands = array();
foreach ($criteria as $entry) {
    $key = $entry->posBrandKey;
    $brands[$key] = $entry->id;
}

My goal is to have the best performance possible, this is one of the many queries I call in the same script.

Eager loading only works when your field is a RelationField it does not work with Text fields. If you goal is to reduce the length of the queries and to maximize your performance you could fetch the raw rows instead of populating the elements.

$criteria = craft()->elements->getCriteria(ElementType::Category);
$criteria->status = null;
$criteria->limit = null;
$criteria->group = 'productBrand';

// create a query
$query = craft()->elements->buildElementsQuery($criteria);
// select only the rows you want/need
$query->select('elements.id as id, content.field_posBrandKey as posBrandKey');
$brands = [];
// execute it
$rows = $query->queryAll();

foreach($rows as $row){
    $brands[$row['posBrandKey']] = $row['id'];
}


Add a button to the entry edit screen via plugin I would like to add a button to the edit entry screen, only for already saved entries, alongside the "Share" button.

When clicked, I'd like to call my plugin's controller action and post the entry ID.

Where would I look to see how to do this?

Not sure if you can put it next to the Share button, but check out the Triggers feature of Button Box...

  https://github.com/supercool/buttonbox

You can create a "Triggers" field, which is just a button that hooks up to JS. Then use the JS to ping your Controller via AJAX.

The button exists as a field, so you could just put that field at the top of your field layout. It's not well documented, but it's really easy to do.


Sprout SEO: Getting error on save, preventing updating "default" meta data After creating a default meta entry in Sprout SEO. Any subsequent updates aren't saved and I get an error message "Couldn't save the default"

Using:

Craft 2.4.2725
Sprout SEO 1.1.1

Has anyone else come across this?

This issue came as a result of the MySQL DB sql_mode including the NO_AUTO_VALUE_ON_ZERO mode which affects how auto_increment columns work. When trying to create a new row entry it will only auto_increment if null is passed.

Full explanation here:

http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_no_auto_value_on_zero

This setting matched with the way the controller's actionSaveDefault function was setting the id to a blank value rather than a null value caused it to trigger this DB behavior of writing a 0 rather than auto_increment.

While the cause of the issue is not Craft or SproutSEO specific, this answer might help anyone else with the issue.

Check your MySQL DB sql_mode
If, NO_AUTO_VALUE_ON_ZERO is set make sure you're passing null if you want it to auto_increment


Use locale not included in Craft I have to develop a website under Craft CMS 2 and going to Locale Options I see I can add a language, but I need to use a language that is not included in the official codes for the representation of names of languages.
There's a cultural and important question here for my client, because Valencian language is included into Catalan language under the code "ca_ES" but is frowned upon here. So, I want to use other code, for example, "va_ES". How can I do this under Craft CMS 2?
Thanks a lot.

I think you should be ok to just copy the ca_ES file and rename it to whatever handle you like. Full instructions here: https://craftcms.com/knowledge-base/adding-additional-locales-in-craft-2#creating-custom-locales
I had to do this myself for an Icelandic locale and it worked fine.


Using Structures instead of Singles Has anyone ever tried using Structures instead of Singles? I'm developing something that's kind of like multiple sites in one, they share the same central design, just with content differences and a few colour changes. I thought if I could use a Structure instead of Singles, I could contain each section to a specific area (making it easy to maintain), and use Entry Types to decide on the content.

The problem is with using a Structure is I keep getting Variable "entry" does not exist. errors. Any suggestions?

If anyone can suggest a fix, or a better way of handling something like this, I'd love to hear it!

Thanks

I'm doing this at the moment. It's not a perfect solution, but nor is it terrible. In a lot of ways, I'd quite like Craft to just burn Singles and Channels and use nothing but Structures. You can do everything with Structures that you can with the other two, and you get better flexibility and much nicer groupings in the CMS that make more sense to clients (the one confusing bit of Craft clients seem to have is why editing pages is spread out over three areas they don't see any real logic behind). But, that's not how things are. Anyway...

If you're getting "entry does not exist" then you've got something broken in your routing. Every page inside a Structure is an Entry, and if you've got URLs resolving to entries in your Structure then you've got access to the entry variable in your template.

Check your Structure and see what template it's actually loading. The only thing I can think of at the moment with the little detail you've given is that you've got templates in a path that match the Structure, and instead of routing theough the database it's routing theough the files.

i.e., if you've got templates/my-structure/my-entry.twig and also an Entry with a URI of /my-structure/my-entry then you might be skipping the database because your filesystem is matching first.


Importing Blog posts from Drupal into Craft I am using InstaBlog plugin to manage Blogs in Craft. I would like to import some 1000 blog entries from Drupal. I know it has an option to import blogs from WordPress. I was wondering if this can be done from Drupal?

Any help is highly appreciated!

There are several import plugins that can help you import your data from Drupal, but they may require a bit more configuration than the InstaBlog plugin that is designed for a specific use case.

Import Plugins

Import plugins like FeedMe and Import provide you a user interface where you can map fields from your import file to fields in Craft. Assuming you can export your data into one of the supported formats for those plugins, you could map the fields from your export and use the interface to import your data.

Sprout Import is also a versatile import plugin, but does not currently have a UI. It requires that you get your data into an import-friendly JSON format, and also gives you a lot of flexibility in how you resolve relationships or handle custom data types.

Drupal Views Data Export is a good plugin to help output your Drupal data in the format that can be used by one of the above import plugins.

Extract, Transform, Load

A good process to follow as you migrate your data is referred to as the ETL Process (Extract, Transform, Load). You need to:

Extract - Get your data out of the previous system (in your case Drupal)
Transform - Transform that data into a format that can be imported into the new system (this can be done with Drupal Views Data Export module, or some other method that can help transform the data in the Drupal Database to importable files for one of the Craft import plugins)
Load - Import your data into Craft (this step is handled by the Craft import plugins)

For large amounts of data, you'll likely run into several other challenges as well. Many of those questions will likely be documented by the specific import plugin you choose. When working with large migrations, while many things can be handled programmatically, don't forget to consider what can be handled manually as well. Often, a few parts of a migration are easier to do manually and being open to a bit of manual work can help make some of the programmatic steps less complicated.


Uploading PSD files not possible I have created an Asset field type and have the "restrict file types" option not checked.

When I attempt to upload a file with extension .PSD i get the message Upload failed for 020516_Action-Buttons_Desktop.psd. The error message was: “Error uploading the file: This file type is not allowed”

Is there a setting someplace else thats preventing this?

I also tried checking the restrict option and selecting "Photoshop file". But this also did not work.

You can add the psd extension to extraAllowedFileExtensions in your config file.

'extraAllowedFileExtensions' => 'psd'

https://craftcms.com/docs/config-settings#extraAllowedFileExtensions


How should I include my custom enums class in my plugin? If I was going to include my custom enums for my plugin, should the include be outside of my plugin class or use the init() method. What is the best way to handle this and are there any pros or cons to either?

Current method:

<?php
namespace Craft;

// include enums for custom statuses
include(dirname(__FILE__) . '/enums/PluginNameEnums.php');

class PluginNamePlugin extends BasePlugin
{
    // etc
}

I suppose it depends on what the code is going to be doing.  If it's standard "business logic" code related to your plugin, then it would make more sense to add it to your plugin's services, which is where we recommend that type of logic goes.  There, it handles the interactions with the database and returns the appropriate models back to your plugin's controllers and/or template variables.

Adding it to your service layer will also get you the added benefit of Craft auto-uploading the classes for you as well and attaching them to the global craft() instance as craft()->pluginHandle

Update

If we're talking about enums, I'd follow Craft's example and create an enums folder for your plugin.  From your plugin's init() method, simply import your custom enums:

public function init()
{
    Craft::import('plugins.yourPluginHandle.enums.MyCustomEnum');
}


Two different lightswitches to add class on body tag I'm using a lightswitch field to add a class to my html document body-tag. The field is added to a section  with a handle named "events".

To make this happen, I do this in my _layout.html:

{% if entry.whiteLogoText %}
    <body class="white">
{% else %}
    <body>
{% endif %}

Now I also want to use such a lightswitch for entries of a different section (with a field handle named 'projects').

Should I make a new lightswitch field for this particular section, and if so, how should I print it?

I wanna make sure I don't get two <body>-tags.

You can use the same lightswitch field on both of your channel sections.

But I wouldn't use an EntryModel in the _layout.html (assuming that's a template you use to extend your actual entry and index templates with).

You probably have two different _entry.html templates for your sections "project" and "events". Define a variable in these if your condition (lightswitch) is true:

{% extends "_layout" %}

{% if entry.whiteLogoText %}
    {% set bodyClass = 'white' %}
{% endif %}

{% block content %}
{% endblock %}

This is how your _layout.html should look like:

{% if bodyClass is defined %}
    <body class="otherBodyClasses {{ bodyClass }}">
{% else %}
    <body class="otherBodyClasses">
{% endif %}

<main class="page" role="main">
    {% block content %}
    {% endblock %}
</main>

</body>

Or with the ternary syntax:

<body class="otherBodyClasses {{ bodyClass is defined ? bodyClass }}">

.

Edit:

You can additionally set that bodyClass variable in other templates using different conditionals:

{% if myGlobalSetHandle.whiteLogoTextForProjectsEntries %}
    {% set bodyClass = 'white' %}
{% endif %}

or (based on my latest assumptions on what you wanna do):

{# Define var before the for loop #}
{% set bodyClass = '' %}

{# Check if `whiteLogoText` is set on any "project" entry #}
{% for project in craft.entries.section('projects') %}
    {% if project.whiteLogoText %}
        {% set bodyClass = 'white' %}
    {% endif %}
{% endfor %}

With this last code example you have to define the variable before the loop to make it accessible outside of it. Because you will always have a bodyClass defined then, change the conditional in your _layout.html like this:

<body class="otherBodyClasses {{ bodyClass is defined and != '' ? bodyClass }}">


Loop through fields from 'single' I have a structure for different categories like salad, soup, main course and so on. Basically they share the same fields - but I want to be able to have dynamic singles based on those structures. For example I have a MainMenu-Single where I than can select entries from salads, soups, main courses and so on.

But is there a way to loop through all the fields in that single?

I tried:

{% for category in craft.entries.section('foodMenuCategories') %}
    {% if entry.{category} is defined %}
       ...

Sadly that doesn't work.

I think there's a few ways you can do this with twig.

You should be able to check whether the category slug exists as an attribute on the entry object:

{% for category in craft.categories.group('foodMenuCategories') %}
    {% if category.slug in entry.getAttributes|keys %}
        ...

Or by using the category slug in an array accessor:

{% for category in craft.categories.group('foodMenuCategories') %}
    {% if entry[category.slug] is defined %}
       ...

Or whether the getAttribute() method on the entry model returns anything truthy for that handle:

{% for category in craft.categories.group('foodMenuCategories') %}
    {% if entry.getAttribute(category.slug) %}
        ...

It's also important, that the slug is the same in every language!


"Could not find composer.json file" error in CraftCMS 3 I recently updated my CraftCMS 3 with the help of Composer.

When I try to install a plugin with the plugin store, I get an error saying that Craft couldn't find my composer.json file. He proposes me to define the  CRAFT_COMPOSER_PATH in index.php. But, when I do, I still get the same error.

My composer.json is the root of craft folder. I seriously don't know how to solve my problem.

Here's a screenshot (sorry I use Craft in french):

Thank you!

You need to open your index.php file and add composer path line.
E.g. my composer.json file is placed in root folder and I defined below path inside my index.php:
    <?php

//Project root path
$root = dirname(__DIR__);

// Load and run Craft
define('CRAFT_BASE_PATH', $root.'/craft');
define('CRAFT_COMPOSER_PATH', $root.'/composer.json'); <======= this line
require_once $root.'/vendor/autoload.php';
$app = require $root.'/vendor/craftcms/cms/bootstrap/web.php';
$app->run();


Calling an event from a third party plugin in my plugin Trying to work out if I’m doing something wrong with catching an event from another plugin in my plugin.

I’m trying to use amforms “onSaveSubmission” event, so, in my plugin’s init()
function i have

craft()->on('amForms.onSaveSubmission', function(Event $event) {
    var_dump($event);
});

But, when I submit a form successfully, this event is triggering an error:

Internal Server Error

Property "Craft\AmFormsService.onSaveSubmission" is not defined.

The onSaveSubmission event is in /plugins/amforms/services/AmForms_SubmissionsService.php

craft()->on('amForms_submissions.saveSubmission', function(Event $event) {
    BusinessLogicPlugin::log(print_r($event, true));
});

Pay attention to the casing
Craft\AmForms_SubmissionsService → amForms_submissions

https://craftcms.com/docs/plugins/hooks-and-events#listening-for-events


Database & Asset Syncing Between Environments I've recently setup a new cloud server for a client with a Craft Multi Environment setup. And I also would like to to be able to do the Database & Asset Syncing Between Environments in Craft CMS as in the excellent nystudio107 article.

I have it setup at my work and it works really well as you just have to navigate to /scripts folder via the terminal, and then type ./pull_db.sh

Like I said I have this setup at my office and it works really well. But on this new server I've setup I'm having an issue in that I get the following when I do the ./pull_db.sh

-bash: ./pull_db.sh: Permission denied

I've checked the setting in the .env.sh that I've created and match what I have in the office setup. So need to work out why I'm getting the permission denied.

Anyone got any ideas?

-bash: ./pull_db.sh: Permission denied

The error indicates that the shell script doesn't have execute permissions.  Running this command should make it executable:

chmod +x pull_db.sh


Is Craft's Email Service Protected Against Mail Header Injection Attacks? We have a client website using Sprout Forms for a contact form. The client has queried a number of security topics with us, one of which is about Mail Header Injection attack protection (https://www.acunetix.com/blog/articles/email-header-injection/).

I've reached out to Ben at Barrel Strength and his response was that Sprout Forms uses the default Craft email service so any security steps Craft is taking they're piggybacking on.

The site is currently using the PHP Mail email setting.

Does the Craft email service have any protection / validation in place to mitigate against potential Mail Header Injection attacks or would we need to implement any updates to protect against this?

Does the Craft email service have any protection / validation in place to mitigate against potential Mail Header Injection attacks

Yes.

Attacks like this, for the most part, are really only a concern for PHP apps that roll with their own custom email logic instead of using a widely used/tested email library.  Craft 2 uses PHPMailer and Craft 3 uses SwiftMailer.

And they both provide methods for stripping out newlines to prevent header injection attacks.


How do I push contact form data to SugarCRM? (currently using Sprout Forms) SugarCRM has a REST API, and Craft boasts its ability to integrate with almost anything that has an API; however, I am working on a site that uses Sprout Forms, which doesn't mention anything in their docs about integration.

Is there a way, in addition to emails and saved entries, for Craft to push Sprout Form data to SugarCRM?

If this isn't possible, if there another contact form solution that will integrate this way?

I was able to accomplish this by grabbing Craft Business Logic, stripping out most of the examples, and simply listening for a form submission:

craft()->on('sproutForms.onSaveEntry', function (Event $event)
{
    $entry = $event->params['entry'];
    $content = $entry->getContent()->getAttributes();

    // Let's not pass fields we don't need
    $fields = array();
    $ignore = array('id', 'slug', 'title', 'handle', 'locale', 'element', 'elementId');

    foreach ($content as $field => $value)
    {
        if(!in_array($field, $ignore))
        {
            $fields[$field] = $value;
        }
    }

    $fields = http_build_query($fields);
    $ch = curl_init('https://url-to-sugar.crm/index.php?entryPoint=WebToLeadCapture');
    curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);

    $response = curl_exec($ch);
    curl_close($ch);
}

I just created an init function in the plugin and added this there. I didn't need to use an API because the data is only flowing in one direction. I just used curl to push the data.


Images missing, service unavailable Folks:

When users visit the site only some of the images on the page show. Checking Chrome dev tools shows that the missing images are failing with "server unavailable" errors. The image is there if you go to it directly.

This appears to be random. Images show sometimes but not others. I have erased the cache, rebuilt the search index and the asset list. No change.

The client says that the site sometime fails completely but I have yet to witness this.

I have VPNed from various locations and it seems to be the same no matter where I'm coming from.

The hosting company says the only error they see is "image missing" and the DB connection is fine.

Any help would be great.

The hosting company says the only error they see is "image missing" and the DB connection is fine.

That seems suspicious to me.  Assuming the 503 Service Unavailable status code is initiated in Craft, it will do that in two common occurrences for front-end requests.  One is when Craft is in the middle of being updated, and the other is when it is having problems connecting to the database.

A look through the Craft logs as well as your web server access logs should help verify this.


Counting section handle in TWIG with weighted search plugin I am using the weighted search plugin to inplement a search functionality in my site. It works as it should but I am looking for a way to tell how much results were found of each type. Where type for example is blog and mapMarker.

This is how the search bar gets its results:

{% set query = craft.request.getParam('query') %}
{% set typesToSearch = ['mapMarker', 'blog'] %} <- This is what I want to count
{% set results = craft.weightedSearch.substringSearch(query, typesToSearch) %}

And then I have a block of code that shows all my results, and this is the place where I want to tell the end user how much results is from each typesToSearch.

How do I implement such feature in this code? :

{% for searchResult in results %}
    {{ searchResult.entry.type|length }} <- I tried this but this doesn't work.
{% endfor %}

You can search each section separately, count the totals of each and then merge them back together to form your full results.

{# Search each section separately #}
{% set query = craft.request.getParam('query') %}
{% set mapMarkerResults = craft.weightedSearch.substringSearch(query, ['mapMarker']) %}
{% set blogResults = craft.weightedSearch.substringSearch(query, ['blog']) %}

{# Merge the two sections' results together #}
{% set fullResults = mapMarkerResults|merge(blogResults) %}

Because Twig's |merge filter will add all the blogResults after mapMarkerResults the sort order will be wrong. Using the SuperSort plugin (version 1.2.0 supports Craft 2) you can fix that.

{# Use SuperSort's rsortAs method to sort the results by Weighted Search's score in descending order #}
{% set fullResults = fullResults|supersort('rsortAs', '{score}') %}

Now you can handle the output.

There's {{ blogResults|length }} results from the Blog section.
There's {{ mapMarkerResults|length }} results from the Map Marker section.

{% for searchResult in fullResults %}
    {{ searchResult.title }}
{% endfor %}

Note: SuperSort might not sort exactly the same as Weighted Search. They will correctly be sorted by score in descending order, but it might not break ties the same way (e.g. two entries with a score of 1). If it's important for the search results to be in exactly the same order as Weighted Search you should run the search again. This is obviously more server intensive and I wouldn't recommend it as it'll slow down your page loads.

{% set mapMarkerResultsCount = craft.weightedSearch.substringSearch(query, ['mapMarker'])|length %}
{% set blogResultsCount = craft.weightedSearch.substringSearch(query, ['blog'])|length %}
{% set fullResults = craft.weightedSearch.substringSearch(query, ['people', 'blog']) %}


How can I manually update the URI of an entry? Is there a way to manually change the URI for an entry?
for instance where is this stored in the database (is it?)

I need to update one that is: /vacancies  to /vacancies-1444 for example
the 1444 never got added to the URI when created by an API entry creation and /vacancies is the root of a list of vacancies.

For most cases, it should be as simple as updating the slug for that entry to vacancies-1444 on the entry edit page.

This is assuming it's not in a Structured Section and you haven't defined some custom URI rules where the last segment of the URI isn't {slug}.


Updates available on local copy but don't show on live site My local copy of a live site is showing an update to Craft 2.2 build 2593 is available but a check for updates on the live site gives "Craft is unable to determine if an update is available at this time."

Has anyone come across this kind of behaviour before?

Am I safe to update my local copy, commit changes and push to live site?

Both local and live site are both in sync at the moment running Craft Pro 2.2.2592

Generally, it’s perfectly safe to update locally and push the changes live.

Two things to keep in mind:

If there were any migrations in the update, your production site will be put in Maintenance Mode when you deploy the update, and you will need to visit the Control Panel and click the Finish Up button to complete the update. You can tell if this is going to be necessary by checking craft/app/Info.php and seeing if the CRAFT_SCHEMA_VERSION has changed, or by checking to see if there are any new files within craft/app/migrations/.
If you update locally and then a second update is immediately available, the chances are that you hit a “breakpoint update”, which means that you have to update TO a certain release before you can update PAST it. That will apply to your production site as well, so in that case, you will actually need to deploy the first update to production, click that Finish Up button if there is one, and then run the second update locally, deploy it, and once again click the Finish Up button.


How to set the value of a Date field from PHP? I'd like to set the value of a Date field from my custom PHP code.
How can this be made? Which format does the Date field expect when using the setValue() function?

Here's an example value that will set it to today:
[
  'timezone' => 'America/New_York',
  'date' => date('m/d/Y')
]

As always, easiest to find out how it's done by inspecting the fields as they are saved in the control panel.


Get Level 1 entry on a section as Nav I have a template which I want to use for different sections.

In my template I have this code:

{% set pages = craft.entries.section('catering').level(1) %}

  {% for page in pages %}

{{ page.getLink() }}

  {% endfor %}

But I want to select the current section by Craft self. So I can use the same template for multiple sections.

To expand on my comment you could do this:

In templates/_pages/index.twig you would do:

{% include '_pages/_types/_' ~ entry.type %}

Then create a folder in /templates/_pages/ called _types in it use, an example _standard.twig in which "standard" coincides to your Entry Type slug.

I hope that helps. I couldn't find the original SE post but I know that this method has been mentioned and preferred by many Crafters!


Why is my Super Table field returning the ID for existing blocks? I have a front-end profile form that is using a Super Table field to populate a user's phone number.

If the user has not populated the field before, everything works great. I am able to use new1 to collect the user's information.

It is when I am trying to display existing data that I am getting the error

  Impossible to access an attribute ("id") on a string variable ("92").

I am following this guide to help show existing data.

This is what my template looks like:

{% set fieldHandle = 'phoneNumber' %}
{% set field = craft.fields.getFieldByHandle(fieldHandle) %}
{% set blocktype = craft.superTable.getSuperTableBlocks(field.id)[0] %}

<input type="hidden" name="fields[{{ fieldHandle }}]" value="">

<label for="phoneNumber">Phone Number</label>

{% if currentUser.phoneNumber.phoneNumber|length %}
    {% for block in currentUser[fieldHandle] %}
        <input type="hidden" name="fields[{{ fieldHandle }}][{{ block.id }}][type]" value="{{ blocktype }}">
        <input type="hidden" name="fields[{{ fieldHandle }}][{{ block.id }}][enabled]" value="1">

        <input type="text" name="fields[{{ fieldHandle }}][{{ block.id }}][fields][phoneNumber]" value="{{ block.phoneNumber.phoneNumber }}">
    {% endfor %}
{% else %}
    <input type="hidden" name="fields[{{ fieldHandle }}][new1][type]" value="{{ blocktype }}">
    <input type="hidden" name="fields[{{ fieldHandle }}][new1][enabled]" value="1">

    <input type="text" name="fields[{{ fieldHandle }}][new1][fields][phoneNumber]"
    {%- if currentUser is defined and currentUser.phoneNumber.phoneNumber|length -%}value="{{ currentUser.phoneNumber.phoneNumber }}"{%- endif -%}>
{% endif %}

While trying to debug myself, this:

{{ currentUser[fieldHandle] }} // 92

So this:

{% for block in currentUser[fieldHandle] %}

...is really saying "for block in 92". So, that is why I am getting the error, I'm not sure what the correct syntax is to resolve the error though.

My super table is set to have a max rows of 1 and static field is selected.

Thank you for any suggestions!

I think the key thing here is that its a static Super Table field, which is treated differently to a repeatable one. Instead of looping through each block, there's only one. Fortunately, you have all the required information, as this is in fact the blocktype variable.

{% set fieldHandle = 'mySuperTableField' %}
{% set field = craft.fields.getFieldByHandle(fieldHandle) %}
{% set blocktype = craft.superTable.getSuperTableBlocks(field.id)[0] %}

<form method="post" accept-charset="UTF-8">
    {{ getCsrfInput() }}
    <input type="hidden" name="action" value="users/saveUser">
    <input type="hidden" name="userId" value="{{ currentUser.id }}">

    {# Start with the top-level Super Table field #}
    <input type="hidden" name="fields[{{ fieldHandle }}]" value="">

    {# Ensure any existing rows in your Super Table field are saved #}
    <input type="hidden" name="fields[{{ fieldHandle }}][{{ blocktype }}][type]" value="{{ blocktype }}">
    <input type="hidden" name="fields[{{ fieldHandle }}][{{ blocktype }}][enabled]" value="1">

    <input type="text" name="fields[{{ fieldHandle }}][{{ blocktype }}][fields][customField1]" value="Value 1">
    <input type="text" name="fields[{{ fieldHandle }}][{{ blocktype }}][fields][customField2]" value="Value 2">
    <input type="text" name="fields[{{ fieldHandle }}][{{ blocktype }}][fields][customField3]" value="Value 3">

    <input type="submit">
</form>


What happened to commerce_discounts->saveDiscounts or How to relate vouchers to product types in Commerce 2? We sell vouchers to our shop users. To prevent them for being used on vouchers themself, i could relate them to specific productTypes or even products in Commerce 1.

craft()->commerce_discounts->saveDiscount($discount, $groups, $productTypes, $products)

In Commerce 2 the 3rd and 4th parametes are gone. How can i relate vouchers to product types programmaticely?

You now need to set the groups, product types, and purchasables on the discount model directly, then just pass the discount model to the saveDiscount method:

Plugin::getInstance()->getDiscounts()->saveDiscount($discount)

An example of setting these things on the discount before saving can be found in the discount controller:

https://github.com/craftcms/commerce/blob/develop/src/controllers/DiscountsController.php#L128-L166


Get Entries within a Category Group with no duplicates in each category How would I loop through all categories in a group to get this scenario:

Get 4 entries per category
No duplicates across any of the categories, if it's in Cat 1, should not show in any other.
Category info (title, URL, etc)

So here is a visual:

Category 1

Entry 1
Entry 2
Entry 3
Entry 4

Category 2

Entry 1 (duplicate from Category 1, do not want here, so get 4 different)
Entry 5
Entry 6
Entry 7
Entry 8

Category 3

Entry 2 (duplicate from Category 1, do not want here, so get 4 different)
Entry 6 (duplicate from Category 2, do not want here, so get 4 different)
Entry 9
Entry 10
Entry 11
Entry 12

I hope this gives a decent visual of what I want.

I've tested this with some of my own content and believe it works to your spec. You need to keep a track of all entries that have been displayed so far. You then loop through each categories related entries and if the entry hasn't been shown in a previous category we add it to a new array within that category loop.

    // Set empty array to hold id's of all currently displayed entries
    {% set entries_displayed = [] %}

    // Loop over a category group
    {% for category in craft.categories.group( 'productBrand' ) %}

{{ category.title }}

      // Get related entries to the category
      {% set related_entries = craft.entries.relatedTo( category ) %}

      // Set empty array to hold id's of entries we'll eventually output
      {% set entries_to_display = [] %}

      // Loop through related entries
      {% for entry in related_entries %}

        // If the entry hasn't been displayed
        {% if entry.id not in entries_displayed %}

          // We want to show the entry
          {% set entries_to_display = entries_to_display|merge([entry.id]) %}
        {% endif %}
      {% endfor %}

      // Finally grab the entries to display from the array of id's that haven't already been shown
      {% set entries = craft.entries.id( entries_to_display ).limit( 4 ) %}
      {% for entry in entries %}

        // Add the id to our "already displayed" array
        {% set entries_displayed = entries_displayed|merge([entry.id]) %}

        {{ entry.id }} - {{ entry.title }}

      {% endfor %}
    {% endfor %}

UPDATE:

Erik later discovered an error in my original answer where I was setting entries_displayed in the first for loop before they'd actually been output in the last for loop. I've updated the code to reflect his fix.

  I had to move the entries_displayed array to the last for loop which displayed the entries. That way I knew exactly what entries had been displayed. If I didn't do that, it would assume more than 4 were shown per category.


The twig syntax for this for loop I am trying to develop a loop in a craft template that adjust the numbers of rows and awards per row based on the total number of awards.  The numbers are all coming back correct but I am struggling with getting the syntax of the loop correct. Below is the type of loop I am trying to execute.

for ($i = 1; ; $i++) {
if ($i > 10) {
  break;
}
  echo $i;
}

But I am getting errors because my syntax is not correct and I cannot seem to find this, although I realize I am probably either just missing it somewhere or not recognizing it.

I was trying something like this, along with other variations, but it keeps throwing errors.

{% set exactRowsNeeded = count / 7 %} <!-- correct -->
{% set rows = ceil(exactRowsNeeded) %} <!-- correct -->
{% set exactAwardsPerRow = count / rows %} <!-- correct -->
{% set awardsPerRow = ceil(exactAwardsPerRow) %} <!-- correct -->

{% set r = 1 %}
{% for r %}
{% if r <= 2 %}
  {{ r }}
{% set r = r++ %}
{% endif %}
{% endfor %}

Here throws an error at the "for r" line.  It seems to be looking for something like "for r in rows" or something.  Even just a link to an example would be awesome I just cannot seem to get this syntax correct.

The code below ended up solving the issue for me.

{% for row in 0..rows %}


Magazine possible in Craft? I have been a wordpress user for the longest time, a friend of mine now uses Craft, I took a look at his backend and really liked the way he creates his content in it. I also like that it uses Twig.

I watched some of the Craft movies on the website about the entry types, structures etc. but it would be of some help if some experienced user could help me with the question if Craft is the right choice for me:

I have a small magazine website about movies, so I would need the following structure:
- Movies (a list of movies, when I click on a movie I would like to have a list of all news, reviews regarding to this movie)
- News
- Reviews
- Directors (a list of directors, when I click on the director I would like to display a list of all of this directors movies)

Is this possible out of the box with Craft CMS? I'd be thankful for any hint on how you would realize this.

Best regards
Florian

you can do all of that with Craft CMS, the thing you're searching for are "related entries" where you can relate news to a certain movie ... director ... basically you can relate everything to everything.

You can find more information about relationships here:
https://craftcms.com/docs/relations