WARNING: heuristic fragment matching going on! when querying matrix fields or any query with multiple fragment types with Graph QL using Nuxt Apollo I am relatively new to using Craft Headlessly and am trying to query matrix fields with Nuxt JS and it's Apollo module.
I have discovered, that although the graphQL queries work in the GraphiQl interface, they do not work with Apollo due to Apollo not knowing the schema for unknown fragments. I've stumbled apon a few others who have had this issue such as this guy but their solution confused me and seemed more complicated than I would expect. I'm sure there must be a simple solution considering this is a widely used system for working with Craft Headlessly.
I also saw this response from someone (see the response from Mylesthe.dev) who gave some instruction but I still didn't quite understand how to apply this. The post above this also mentions that Apollo-client 3.0 should be able to handle unknown fragment types but I'm on @nuxtjs/apollo ^v4 and still experiencing it.
Does anyone have a simple clear fix for this that I can apply to my set up, so that I can query matrix fields with multiple fragment types in Craft CMS?
My Package.json file is:
{
  "name": "nuxtjs-test",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate"
  },
  "dependencies": {
    "@nuxtjs/apollo": "^4.0.1-rc.5",
    "core-js": "^3.6.5",
    "dotenv": "^8.2.0",
    "flickity": "^2.2.2",
    "headroom.js": "^0.12.0",
    "node-fetch": "^2.3.0",
    "nuxt": "^2.14.6",
    "vue-rellax": "^0.2.0"
  },
  "devDependencies": {
    "@nuxtjs/dotenv": "^1.4.1",
    "@nuxtjs/style-resources": "^1.0.0",
    "fibers": "^5.0.0",
    "sass": "^1.32.0",
    "sass-loader": "^10.1.0"
  }
}

My apollo GQL query is (const GET_HOMEPAGE):
{
  entry(section: "homepage") {
    ... on homepage_homepage_Entry {
      homepageBuilder {
        ... on homepageBuilder_sectionHeadline_BlockType {
          typeHandle
          headline
        }
        ... on homepageBuilder_showcase_BlockType {
          typeHandle
          limit
        }
        ... on homepageBuilder_articles_BlockType {
          typeHandle
        }
      }
    }
  }
}

my apollo smart query is:
apollo: {
      entry: {
        query: GET_HOMEPAGE,
        error (error) {
            this.error = JSON.stringify(error.message);
            console.log(error);
        },
        result ({ data, loading, networkStatus }) {
          console.log("[networkStatus]",networkStatus);
          console.log(data);
        },
      },
    },

my apollo settings in Nuxt.config file is:
  apollo: {
    clientConfigs: {
      default: {
        httpEndpoint: process.env.APOLLO_DEFAULT_ENDPOINT,
      }
    },
    defaultOptions: {
      $query: {
        fetchPolicy:'no-cache'
      }
    }
  },

I struggled with this for ages, but after @mylesthe.dev (who responded to one of the posts i mention above) spoke to me directly to provide fantastic support and some examples, I figured it out. So for anyone else still struggling like I was, here's the code (thanks to his work) which finally got things working for me:
First of all, in your nuxt.config.js set up your apollo configs:
// Apollo config and endpoint for graph ql
  apollo: {
    includeNodeModules: true,
    clientConfigs: {
      default: '@/apollo/client-configs/default.js' // This is where you'll set up the client and import the possible fragment types
    }
  },

Now we create the apollo client set up with the fragment schema file (which we'll create) in apollo/client-configs/default.js
import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
import schema from './schema.json';
const fragmentMatcher = new IntrospectionFragmentMatcher({
    introspectionQueryResultData: schema
  })

export default ({req, app}) => {
    const token = process.env.GRAPHQL_TOKEN
    return {
        httpEndpoint: process.env.API_ENDPOINT,
        getAuth: () => `Bearer ${token}`, // remove if you're using the public schema
        cache: new InMemoryCache({ fragmentMatcher }),
    }
}

Now save an empty schema.json file in apollo/client-configs/.
Next we need to set up the script to query and generate this schema on nuxtServerInit.  You'll need fs to write your schema file. You can install it with NPM: npm install --save fs.
Once installed, go back to your nuxt.config and add fs to the build:
  build: {
    extend (config, ctx) {
      config.node = {
        fs: 'empty'
      }
    }
  }

Then in your store/index.js:
import Vuex from 'vuex';
import fetch from 'node-fetch';
import fs from 'fs';

const createStore = () => {
  return new Vuex.Store({
    actions: {
        async nuxtServerInit({commit}, {app}) {

            // only update fragements locally
            if (process.env.NODE_ENV == 'local') {

                // LOAD FRAGMENT TYPES AND STORE IN FILE
                // APOLLO READS THIS FILE LATER
                fetch(process.env.API_ENDPOINT, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json', authorization: 'Bearer ' + process.env.GRAPHQL_TOKEN, },
                    body: JSON.stringify({
                        variables: {},
                        query: `
                            {
                                __schema {
                                    types {
                                        kind
                                        name
                                        possibleTypes {
                                            name
                                        }
                                    }
                                }
                            }
                        `,
                    }),
                })
                .then(result => result.json())
                .then(result => {
                    // here we're filtering out any type information unrelated to unions or interfaces
                    const filteredData = result.data.__schema.types.filter(
                    type => type.possibleTypes !== null,
                    );
                    result.data.__schema.types = filteredData;
                    fs.writeFile('./apollo/client-configs/schema.json', JSON.stringify(result.data), err => {
                        if (err) {
                            console.error('Error writing fragmentTypes file', err);
                        }
                    });
                });

            }

        },
    }
  });
};

export default createStore

Your schema should now be generated locally to the schema file and that file will be stored in the apollo cache.


Attach Custom Information to Commerce Order Model I have shipping methods that will require additional information from the user. For example, a local delivery shipping method which requires the user to include a timeframe for delivery (say, Thursday @ 3pm.)
I thought I'd go about it doing something like this:

On select shipping page during checkout, user selects the delivery date/time (based on what is available.)
User selects date, then submits form.
That date is attached somewhere to the order model.
The shipping method rules will validate the chosen date.
Include this additional information (selected delivery date) in saved order on checkout completion.

Is there a way to do this? Basically, I need to attach additional information for this shipping method (and another similar one.) I've looked through the order model docs but can't find a field I could add custom data to.

Add a custom plain text field to your orders, say test.

Then, when calling updateCart, you can add data in to this custom field using a form with an input named like this:

  <input name="fields[test]" type="text"> etc...

This data will then get saved with the order.  This same approach can basically be applied to any field/type.

To actually validate the data, you'll need to look to making a plugin, most likely listening to onBeforeSaveOrder to check the vailidity of the data.  If valid, great, if not, set perfomAction to false and return an error on the Order model.

See https://craftcommerce.com/docs/events-reference#commerce_orders.onbeforesaveorder


Changing first matrix block I'm trying to target the first matrix block and changing the structure of the HTML, but nesting an IF statement within the loop but it's actually not doing anything, instead it's just displaying both the same.

{% for block in entry.contentMatrix %}
{% if entry.contentMatrix.first %}

          {{ block.contentTitle }}

        {{ block.contentDescription }}

  {% else %}

          {{ block.contentTitle }}

        {{ block.contentDescription }}

{% endfor %}

Your condition {% if entry.contentMatrix.first %} will check if there exists a block in your field or not, it does not check if your current block is the first or not. Since there is one the condition will always become true. What you want to do is to check if you are in the first loop or not so I would suggest you to do something like this

{% for key, block in entry.contentMatrix %}
    {% if key == 0 %}

Or something like that


How do we create a pre-defined Asset upload field in a plugin that integrates with the native Craft Assets file manager? We've got a plugin.  It doesn't have the ability to add custom field types.  We're pre-defining all of the fields.  One of the fields needs to be an Asset field.  A user should be able to upload an Asset using the native Craft Asset UI, store that Asset locally or on Amazon or any supported cloud platforms.

How do we do this?

Where do we create the relationship between the uploaded Asset and the database record we want the Asset related to?

If we were allowing custom fields we could have our custom table relate to a Field Layout ID, and have any number of fields relate to that Field Layout.  But in our case, we're defining all of the columns we need in our template, in our own record, and don't really need to create any fields within Craft's fields table as we're setting them all up beforehand.

Do we need a Field Layout in this situation?  Do we need to create a Field within Craft under our own context (like Matrix blocks) to be able to control the settings such as where to upload the assets to, and whether to restrict the upload to a single folder, or single image?

I feel I have lots of pieces of the puzzle, but can't yet see how they fit together.

I did this recently with my Ad Wizard plugin... There are several different parts which need to be brought together to make it work:

In your Record file, add this to defineRelations:

'asset' => array(static::BELONGS_TO, 'AssetFileRecord')

In your Model file, add this to defineAttributes:

'assetId' => AttributeType::Number

Whichever template is responsible for editing that data will need something like this:

        Image

        {% if assetsSourceExists %}
            {{ forms.elementSelect({
                elements: elements,
                id: 'assetId',
                name: 'assetId',
                elementType: elementType,
                criteria: {"kind":[],"localeEnabled":null,"locale":"en_us"},
                sourceElementId: assetId,
                jsClass: 'Craft.AssetSelectInput',
                addButtonLabel: 'Select Image',
                limit: 1,
            }) }}
        {% else %}

No assets sources currently exist. Create one now...

        {% endif %}

You'll notice in the Twig code above, I set references to the following variables:

assetId
elements
elementType
assetsSourceExists
newAssetsSourceUrl

These variable were set in the actionEditMyElement method of the Controller prior to loading the template:

// Set assetId
$variables['assetId'] = $myModel->assetId;

// Set elements
if ($variables['assetId']) {
    $asset = craft()->elements->getElementById($variables['assetId']);
    $variables['elements'] = array($asset);
} else {
    $variables['elements'] = array();
}

// Set elementType
$variables['elementType'] = craft()->elements->getElementType(ElementType::Asset);

// Set assetsSourceExists
$sources = craft()->assets->findFolders();
$variables['assetsSourceExists'] = count($sources);

// Set newAssetsSourceUrl
$variables['newAssetsSourceUrl'] = UrlHelper::getUrl('settings/assets/sources/new');

// Render the template!
$this->renderTemplate('myplugin/_edit', $variables);

Your Controller will probably have something like this in your actionSaveMyElement method:

$myModel->assetId = craft()->request->getPost('assetId', $myModel->assetId);

Your Service file will probably have something like this to save your record:

$assetId = (!empty($myModel->assetId) ? $myModel->assetId[0] : null);
$myRecord->assetId = $assetId;
...
$myRecord->save();

Hope that helps, let me know if I missed anything!


Monthly Calendar || Month View So I have /calendar and linking previous/next months on that template. The previous/next month urls are /calendar/2015-08 and /calendar/2015-08.

I have this custom route setup:

On my /calendar/2015-08 I'm getting this:

Variable "entry" does not exist

Part of my template looks like:

{% extends '_inc/_layout' %}

{% block meta %}
<title>{% if entry.metaTitle|length %}{{ entry.metaTitle }}{% else %}{{ entry.title }}{% endif %}</title>
<meta name="description" content="{{ entry.metaDescription }}" />
<meta name="keywords" content="{{ entry.metaKeywords }}" />
{% endblock %}

I know why this happening but my question is how do I circumvent this? I want some of the same data on /calendar to be on subsequent monthly calendar pages.

Thanks in advance!

Craft won't set the entry variable automatically unless the route matches a particular entry. If you're sharing a template between routes that may or may not correspond to an entry, you need to make sure that var gets set explicitly by you if not automatically by Craft:

{% if entry is not defined %}
    {% set entry = craft.entries.section('myStructure').slug('calendar').first %}
{% endif %}


How do I set a specific entry in a template with "set" This won't work in a template:

{% set entry = craft.entries.id(43) %}
Titel: {{ entry.title }}

But this does:

{% for entry in craft.entries.id(43) %}
Titel: {{ entry.title }}
{% endfor %}

Is it really necessary to use the for loop? I tried to use set because I'd like to over rule the entry variable for the whole template that I'm using if a specific url is visited

{% if craft.request.segment(2)=="openings-en-trainingstijden" %} {% set entry = craft.entries.id(43) %}{% endif %} {{ entry.title }} etc..

Another example this code:

{% for entry1 in craft.entries.id(43) %}Titel: {{ entry1.title }}{% endfor %}
{% set entry2 = craft.entries.id(43) %}Titel: {{ entry2.title }}

Results in:

Titel: Openings- en trainingstijden
Titel:

You need to add .first where you are setting the entry variable:

{% set entry = craft.entries.id(43).first %}

That way you can avoid doing a for loop.


Creating a Custom Field Type with nested Fields I'm just wondering is it possible to have nested Fields inside of a Custom Field type.

So if I create a custom Field type. I wish for it to contain all of the following. So it will contain multiple fields inside of it.

Asset
Matrix
Entry

Is this something that can be achieved.

Appreciate any pointers.

I don't believe you need a new custom field type for this. What your describing has been accomplished quite well already by the Neo plugin...

  https://github.com/benjamminf/craft-neo

Additionally, the Super Table plugin has similar capabilities...

  https://github.com/engram-design/SuperTable


How to set field values for the table field type in Craft 3 I'm trying to insert an entry along with values for a table field. According to the docs, the setFieldValues method takes an array of values in the format handle => value, but it doesn't specify how the value should be formatted for each field type.

Here's my best guess at how it might work for the table field:

$entry = new Entry();
$entry->sectionId = 1;
$entry->typeId = 1;
$entry->title = $title;
$entry->setFieldValues([
  "field_handle" => [
    ["column_1_handle" => "hello", "column_2_handle" => "world"], // Row 1
    ["column_1_handle" => "more", "column_2_handle" => "stuff"] // Row 2
  ]
]);

This inserts the correct number of rows into the table field, but the values are empty, so I'm guessing I'm structuring the array incorrectly.

Any ideas?

I figured this out. The table field is expecting JSON:

$entry = new Entry();
$entry->sectionId = 1;
$entry->typeId = 1;
$entry->title = $title;
$entry->setFieldValues([
  "field_handle" => '[{"col1":"hello","col2":"world"},{"col1":"more","col2":"stuff"}]'
]);


Index "Column A" for unique values, then recursively group "Column B" values based on those uniques I have two levels of product variants in a table field. If the product uses Secondary Variants, I need a way to search the Primary Variants column for unique values, then output individually grouped Secondary variants.

Both Primary and Secondary Variants are unique for each product.

Is there a way to do this with TWIG/Craft templates? If not, what do you recommend? Query JSON? Plug-in?

Possible, yes. But if you should do it with Twig alone is a totally different thing. There's other ways to do that in Craft,
e.g. with relations (Entries Fields) and splitting your Products and their variants into separate sections. Or what about using a structure,
with your variants being child entries to the product?

But here's how you do that with your table field (totally legitimate in my opinion, one advantage being the ease of use for the Client):

{# Prepare variable before loop #}
{% set myVariants = [] %}

{% for row in myTableField %}

    {# Concatenate a string to the value to prevent it from being numeric #}
    {% set variantKey = 'key' ~ row.col1 %}

    {% if variantKey not in myVariants|keys %}

        {# Insert a new key and add the first value to it #}
        {% set myVariants = myVariants|merge({ (variantKey): [row.col2] }) %}

    {% else %}

        {# The key already exists, so merge the value to the existing ones #}
        {% set myVariants = myVariants|merge({ (variantKey): myVariants[variantKey]|merge([row.col2]) }) %}

    {% endif %}

{% endfor %}

This is how you print it:

    {% for variantKey, variantsLevel1 in myVariants %}

            {# Remove the string from our key again #}
            {{ variantKey|slice(3) }}

                {% for variantLevel2 in variantsLevel1 %}

{{ variantLevel2 }}

                {% endfor %}

    {% endfor %}


Possible to view field handles on entry type field definition page? When I am configuring the fields for a given entry type, is there a way to see those fields' handles on the same page? I often reference the entry type page to know which fields are associated with a given entry type, but then I have to cross reference the fields page to make sure I'm using the correct handle. Is there a better way to do this?

You can use the CP Field Links plugin to view the handles on the edit entry pages.

And it sounds like this feature request is very close to what you're asking for.  You might want to throw a vote its way.


Wrapping my head around Categories I have a category group set up called 'gists'. I have entries that contain a category field which pulls in the category group 'gists'.

Now I need to access entries that are tied to individual categories but I need to do so by the category slug.

I cannot figure out how to make this happen. I have tried numerous things but cannot get my head around this. Here is my latest.

{% for entry in craft.entries.section('gist').relatedTo('tech').limit(10).find() %}

Craft site has the excellent document How do I list the entries related to a category?

Building on that, you would fetch your category (by slug), and then the entries related to the category.

{# Fetch the category with slug 'categorySlug' #}
{% set category = craft.categories.slug('categorySlug').first() %}

{# Fetch all of the entries related to this category #}
{% set entries = craft.entries.relatedTo(category) %}

Then loop over those entries.


Express Forms Not Sending Notification Emails Craft 3.3.0.1
Express Forms 1.0.4

I have an Express Forms set up. It submits and saves entries to the DB which can be viewed in the CP, however email notifications are not sent.

Sending a test email via settings > email works as expected as does a different Express Forms form, but this one does not and I am flummoxed.

when I check the Express forms log I see this:

Here is a simplified template of my form where you can see the notification email address are set to a field in the page entry or if that is empty default email addresses are used.

{#
// set send email address from careers entry
#}
{% set sendEmailAddress %}
  {# loop through emails from job entry page and set the form to send to those emails #}
  {% for email in entry.applicationEmails %}
    "{{ email.emailAddress }}"{% if not loop.last %},{% endif %}
  {% else %}
  {# if empty send to this address #}
    "test@domain.com", "test2@domain.com"
  {% endfor %}
{% endset %}

{# this testing div outputs emails as expected #}

  {{ sendEmailAddress }}

{% set form = craft.expressforms.form("jobapplication") %}

{# General Error Handling #}
{% if not form.valid %}

        {{ "Error! Please review the form and try submitting again."|t }}
        {% if form.errors|length %}

                {% for error in form.errors %}

{{ error|t }}

                {% endfor %}

        {% endif %}

{% endif %}

{{ form.openTag({
   return: '?success=1',
   dynamicNotifications: {
      to: [sendEmailAddress],
      template: "job-application.twig",
   }
}) }}

  {#
    Various Fields here
  #}

  <button type="submit" data-application-submit class="btn btn-default" disabled>{{ "contact_submit"|t }}</button>

{{ form.closeTag }}

I've tried various approaches to using dynamic emails notifications but nothing seems to work.

My email notification template looks like this where {eMail} is the email field name in the form.

---
name: 'Job Application Email Notification Template'
description: 'submits job applications to reciever'
fromName: 'Strongco'
fromEmail: '$SYSTEM_EMAIL'
replyTo: '{eMail}'
cc: null
bcc: null
subject: 'Job Application: {positionAppliedFor}'
includeAttachments: true
---

The following submission came in on {{ dateCreated|date('l, F j, Y \\a\\t g:ia') }}.

    {% for field in form.fields %}

{{ field.label }}: {{ field.valueAsString }}

    {% endfor %}

Please advise.

I'm guessing if you update to the latest 3.x release of phpdotenv, the issue will resolve itself.

3.x added better support for environment variables running in multi-threaded environments.  You can read some background info here:
 https://github.com/craftcms/cms/issues/3631

Note that you'll likely need to update how phpdotenv is loaded in your public index.php file. You can read the upgrade guide here: https://github.com/vlucas/phpdotenv/blob/master/UPGRADING.md


Craft site moved to HTTPS - now having issues I have had a Craft install running for some time now, and it has come to the point where I want to run it securely over HTTPS.

Using Laravel Forge, I have set up a Let's Encrypt certificate successfully, so on certain pages of the site it all works well. In my config/general.php file I altered the siteUrl and environmentVariables -> baseUrl to use https.

However when I try to log in to the admin on this server, in the JS Console, the GET requests for all the admin/resources CSS / JS files are returning 404. So the admin login screen shows without any styling, and crucially, logging in returns a bad CSRF token screen!

Any tips?

Thanks

Here's my nginx config:

# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/www.fira.co.uk/before/*;

server {
    listen      80;
    server_name www.fira.co.uk;
    rewrite     ^   https://$server_name$request_uri? permanent;
}

server {
    listen 443 ssl;
    server_name www.fira.co.uk;
    root /home/forge/www.fira.co.uk/public;

    # FORGE SSL (DO NOT REMOVE!)
    ssl_certificate /etc/nginx/ssl/www.fira.co.uk/105882/server.crt;
    ssl_certificate_key /etc/nginx/ssl/www.fira.co.uk/105882/server.key;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
    ssl_prefer_server_ciphers on;
    ssl_dhparam /etc/nginx/dhparams.pem;

    index index.html index.htm index.php;

    charset utf-8;

    # FORGE CONFIG (DOT NOT REMOVE!)
    include forge-conf/www.fira.co.uk/server/*;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    access_log off;
    error_log  /var/log/nginx/www.fira.co.uk-error.log error;

    error_page 404 /index.php;

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

    location ~ /\.ht {
        deny all;
    }

    # Media: images, icons, video, audio, HTC
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
  expires 1M;
  access_log off;
  add_header Cache-Control "public";
}

# CSS and Javascript
location ~* \.(?:css|js)$ {
  expires 1M;
  access_log off;
}
}

# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/www.fira.co.uk/after/*;

So, removing the cache settings for CSS and JS in my nginx config fixed this.

# CSS and Javascript
location ~* \.(?:css|js)$ {
expires 1M;
access_log off;
}

Also, once I got into the admin area after adjusting this, resaving certain entries flushed the twig template cache.


Unsure whether to use Sprout Forms or code forms regularly I was wondering if anyone who has experience using Sprout Forms might be able to steer me in the right direction on whether I'm better off using the Sprout Forms plugin or coding the forms traditionally. Here's a list of some of the main things in the forms.

10 unique forms with about 30 fields each
One field will be Users Field Type (or another way to choose up to 3 users)
Front end forms will allow guests and logged in members to fill out
Back end admin will edit submitted entry form and fill out admin only fields which are hidden on front end
Ideally be able to conditionally display certain fields on the front end based on selections made by the person filling out the form (example: if person selected "Apple" choice in question 2, then show sub choices "gala", "Granny Smith". If person selected "banana" choice in question 2, then don't show any sub choices)
Form field content will need to be searchable so info can be displayed on front end template (show user how many forms he submitted, show field content based on date period)
Need to be able to create and display different reports on all 10 forms on a front end page (possibly export to csv too)

Thank you very much!

Sprout Forms offers you a lot of the same functionality as standard Craft Entries. Both Sprout Forms and Entries allow you to create front-end forms that allow users to submit data to the database. Here are a few thoughts on why you would choose one over the other to manage content that requires front-end forms. None of these reasons are absolute, so take them with a grain of salt for your own situation (and happy to modify this list if anybody has feedback in the comments):

Craft Entries

You want your submitted data to be managed alongside your other content on the Entries tab in the Craft Control Panel
Your submitted data has the concept of an "author" and can be related to a user in your database
Your submitted data has any other concepts that are specific to Entries, such as Post Date or Expiry Date
You want to manage the HTML for all of your forms and fields in your templates

Sprout Forms

You want to allow form submissions by anonymous users who are not logged into your website
You don't want all of your form data cluttering up the Entries area where you manage the primary content of your website
You want to create multiple, similar forms with variations on fields (such as creating a new form with slightly different fields to test a landing page)
You just want a backup of a submitted form in the database (the primary workflow will take place via a notification email that gets triggered when a form is submitted)
You want to be able to easily output your form in your templates dynamically (Sprout Forms handles all of the front-end code for you – including error states – with a single line of code). In addition, the base templates it uses to output the form can be customized using Template Overrides to meet your website design requirements.

Can Sprout Forms handle all of your requirements? Yes, however there are a few items worth mentioning as they may involve other Sprout plugins or custom development. I'll go into detail below.

10 unique forms with about 30 fields each

Sprout Forms can handle as many fields as you need. And makes it easy to output them in your templates without having to create all the necessary HTML by hand using the displayForm, displayTab or displayField tags.

One field will be Users Field Type (or another way to choose up to 3 users)

Currently, we support three relations field (Entries, Categories, Tags). Adding support for the Users Relation field would be possible via a custom integration (mostly just copying one of those existing custom fields), or reach out and we may be able to add this to the core plugin. We held off on adding Users at this point as we wanted to get better feedback on how it would be used to know how to implement it best.

Front end forms will allow guests and logged in members to fill out

Any user can fill out a form. If you want to capture information about a logged in user, you can pass the information you want to track to a field in your form. Sprout Fields has two fields that are helpful for this, the Hidden Field and the Invisible Field.

Back end admin will edit submitted entry form and fill out admin only fields which are hidden on front end

Admins can edit the form via the Craft Control Panel. You can hide fields from displaying on the front-end in several ways. The Hidden or Invisible field give you some basic ways to do this, however are more for capturing values that are not visible to the user on the front-end.

Another way is to use Rendering Options which allow you to customize the id or class names of particular fields as they are dynamically output.  You could, for example, add the class name of hidden to the fields you don't want displayed on the front-end and either supress their visibility or remove them from the page with javascript.

A final way would be to create a custom field that behaves exactly how you need it to.

Ideally be able to conditionally display certain fields on the front end based on selections made by the person filling out the form (example: if person selected "Apple" choice in question 2, then show sub choices "gala", "Granny Smith". If person selected "banana" choice in question 2, then don't show any sub choices)

This is going to be your most challenging item with both Craft Entries and Sprout Forms. You will likely have to write some custom javascript to get this behavior to work, and you'll have to keep this code in mind if you ever update your fields or naming conventions as the code on the page will probably only know what you tell it about how you have things setup in your database.

The easiest place to start here will be to see if you can target the default IDs output on your fields and add the behavior you need to them. If you need more customization of the class names for your code, Template Overrides and Rendering Options give you a lot of flexibility in how you structure your code for your needs.

There are probably several other approaches that can be taken here based on your specific use case so it would be best to talk this through with a developer who knows your project requirements well.

Form field content will need to be searchable so info can be displayed on front end template (show user how many forms he submitted, show field content based on date period)

Sprout Forms Form Elements and Sprout Forms Form Entry Elements (the user submissions in Sprout Forms) use Craft's Element Type API and are searchable in the same way that all Craft Elements are searchable.

You would need to be sure you are capturing the right user information in your form entries to perform the searches your require such as the userId. Sprout Forms captures date information about when a submission is created and modified.

Need to be able to create and display different reports on all 10 forms on a front end page (possibly export to csv too)

Sprout Reports is designed to work closely with Sprout Forms for your custom reporting needs. Out of the box, Sprout Forms has one report integration that lets you run a report on all of your submitted entry data. However, we purposefully de-coupled Sprout Forms and Sprout Reports to allow more customization for your reporting.

Sprout Reports enables you to create custom reports that provide different views into your Form data, add additional columns to your reports such as related user data, and customize what options an admin user has to select from when running a report.

Custom reports do require a developer to set them up, but they are very flexible and fairly easy to implement once you have clearly defined what you need. Please reach out to the Sprout Team if you have any questions on how these work or how to set them up.

All reports are exportable via CSV.


Create entry from template / UI without a form I need to create an entry from my UI after the user triggers a particular event on the page.

I want this to happen automatically and not rely on the user to submit a form.

Is there a way to create an Entry from a twig template (i.e. by calling the required controller function)?  If not, is there an existing plugin that could work?

My content structure is something like this:

mySection = name of Channel that the entires will belong to.  Has the following fields:

myField1 = number
myField2 = text
myField3 = number
user = craft user field (relates the entry to an appropriate user)

I was hoping I could set those variable and call some sort of submit/save function to create the new Entry.

The only way to do this is asynchronously with javascript. If you already have an interactive event on the page I'm guessing you are using JS already? If so you just need to submit a hidden front end form alongside the CSRF token.


Return entries where custom field partially contains My entries have a field containing a third-party product id and a price, separated by a hyphen, like so:

p666a-12.99

In the template, a plugin is returning me some product ids, and I want to return all entries containing those product ids. I know I can fetch all entries, reduce the custom field down to the product id and compare it to the product ids returned from the plugin, but that seems a bit tardy.

Can I filter my entries using the custom field directly?

{# pluginIds = 'p666a, p678a' #}
{% set entries = craft.entries.section('sectionName').customField(pluginIds) %}

You could use the Preparse plugin to save the product ID part of your field in a new hidden field.

Add a new "productId" Preparse field to your entry type with this code in the field's settings:

{{ entry.customField|split('-')|first }}

To update all existing entries, re-save them by going into Settings → Sections → Section Name and click Save.
You can now set up a criteria model exactly like you mentioned in your question, except that you now use the
Preparse field as your custom field parameter:

{% set entries = craft.entries.section('sectionName').productId(pluginIds) %}


Yii Modules in Craft, samples? Does anybody know of a collection or library of Yii Modules online?

I'm trying to understand how easy they can be moved from one application to another, are we going to see something similar to the plugin store for modules within Craft? :O

In the context of Craft CMS, Modules typically would be used for adding functionality to the website itself. As such, you'd use it for things that are specific to that project. Check out the article Enhancing a Craft CMS 3 Website with a Custom Module for details.

You can also generate your module scaffolding via pluginfactory.io


JS tag is adding semicolons to my content I'm trying to output matrix content to create a javascript for my gallery. When I wrap the output with the {% js %}tag each line has an extra semicolon at the end like this:
{ "src": "/assets/uploads/_wsHigh/cp_slideshow_lg_img1.jpg", "width":"1440", "height":"810" },;
{ "src": "/assets/uploads/_wsHigh/cp_slideshow_lg_img2.jpg", "width":"1440", "height":"810" },;

If I output as text its not there. How would I get rid of it?
 {% js %}

{% if image %}
{%- if loop.first -%}
window.addEventListener('DOMContentLoaded', function() {
    (function($) {
$('.slider-pop').on('click', function() {
         $(this).lightGallery({
             dynamic: true,
             download: false,
             zoom: false,
             hash: false,
             dynamicEl: [{% endif %}{%- if not loop.last -%}{ "src": "{{ image.getUrl('wsHigh') }}", "width":"{{ img.getWidth('wsHigh') }}", "height":"{{ img.getHeight('wsHigh') }}" },{% endif %}
             {%- if loop.last -%}{ "src": "{{ image.getUrl('wsHigh') }}", "width":"{{ img.getWidth('wsHigh') }}", "height":"{{ img.getHeight('wsHigh') }}" }]
         })
     });
     })(jQuery);
     });
 {% endif %}{% endif %}{% endjs %}

I am not sure if the code does what you want it to do - but nevertheless you have three {% endif %} but only two {% if %}. Assuming the line
dynamicEl: [{% endif %}{%- if not loop.last -%}{ "src": "{{ image.getUrl('wsHigh') }}", "width":"{{ img.getWidth('wsHigh') }}", "height":"{{ img.getHeight('wsHigh') }}" },{% endif %}

has one surplus endif tag just at the beginning of the array which prematurely ends the if clause, your code correctly would be:
{% js %}
   {% if image %}
       {%- if loop.first -%}
           window.addEventListener('DOMContentLoaded', function() {
               (function($) {
       $('.slider-pop').on('click', function() {
                $(this).lightGallery({
                    dynamic: true,
                    download: false,
                    zoom: false,
                    hash: false,
                    dynamicEl: [
                       {%- if not loop.last -%}{ "src": "{{ image.getUrl('wsHigh') }}", "width":"{{ img.getWidth('wsHigh') }}", "height":"{{ img.getHeight('wsHigh') }}" },{% endif %}
                           {%- if loop.last -%}{ "src": "{{ image.getUrl('wsHigh') }}", "width":"{{ img.getWidth('wsHigh') }}", "height":"{{ img.getHeight('wsHigh') }}" }]
                })
            });
            })(jQuery);
            });
        {% endif %}
    {% endif %}
{% endjs %}


What's the proper way to create a plugin that uses and extends another author’s plugin? I’m creating a plugin that will ultimately create new entries using the Moves API (https://dev.moves-app.com). The Moves API needs OAuth make authenticated calls on a user's account, so I'm using Dukt's OAuth plugin (https://dukt.net/craft/oauth) to handle the OAuth authentication process.

I actually have it up and running, but to create an Oauth provider that isn't supported natively by Dukt's plugin, I've added files to their folders.

Here’s what I’ve done.

Created a Moves.php file in the craft/plugins/oauth/vendor/chrisnharvey/oauth/src/Oauth/Provider/ folder that sets up the necessary info to communicate w/ the Moves API - Link to source: https://gist.github.com/bwlng/2cb486c8d83001deae19#file-moves-php
Created a MovesOAuthProviderSource.php file in the craft/plugins/oauth/vendor/chrisnharvey/oauth/providers/folder that echoes the other providers Dukt supports out of the box. Link to source: https://gist.github.com/bwlng/2cb486c8d83001deae19#file-movesoauthprovidersource-php

Is there a better way to do this? Ideally want to require the Dukt plugin be installed, and then keep the code I've linked to above in my own folder in craft/plugins/moves.

Adding a new provider to OAuth plugin is a two step process:

Create a new OAuth Provider in lusitanian/oauth

The first thing you will need to do is to add support for your new provider in lusitanian/oauth OAuth PHP library. This library supports OAuth 1 & 2 authentication process and you can give a look at other providers to get started writing your own.

It's usually just a matter of a smart copy paste from the code of another provider, by updating:

scopes
api URL
authorize URL
access token URL

That said, you will sometimes have to adjust your code to support the web service's specificities. Read your web service's authentication docs carefully to understand who they implemented the OAuth authentication process and you'll be good to go.

So when your provider is ready, just perform a pull request on lusitanian/oauth OAuth PHP library on GitHub. We're pulling new providers on each Craft OAuth plugin release, so if you got your provider added to lusitanian's library, it will be automatically part of Craft OAuth plugin's next release.

At this point, if you add your new provider in Craft OAuth plugin code, it won't do anything and the provider will not appear in OAuth settings.

Create an OAuth Provider Source in the OAuth plugin

The OAuth provider source class makes the link between between your lusitanian/oauth provider and Craft OAuth plugin.

You should name the file based on lusitanian/oauth's provider file name and save it under oauth/providers folder. For example if your lusitanian/oauth provider file is named Vimeo.php, you provider source file will be named VimeoOAuthProviderSource.php.

This file contains basic informations like the web service's console url, its name, and a simple getAccount() method, and when you'll add it to the oauth/providers folder, your provider will start showing up in Craft CP / Plugin / OAuth.

When you're ready with your OAuth provider source, perform a pull request on Craft OAuth plugin on GitHub and your provider will be added to the next release.

Checking that OAuth plugin is installed

In your plugin, you will have to check that OAuth is installed before using it in order to prevent errors.

In your templates you can check that OAuth plugin is installed this way:

{% if craft.oauth is not defined %}

    {# OAuth plugin not installed #}

{% else %}

    {# OAuth installed #}

{% endif %}

In your php files, you could do it that way:

$plugin = craft()->plugins->getPlugin('oauth');

if(!$plugin)
{
    // oauth is not installed
}
else
{
    // oauth is installed
}

I'm working on a step by step guide on how to implement OAuth in Craft plugin. It's not ready yet but I'll probably start to share the draft in August.


Contact form submission type in Contact Form Extensions I have a site with three forms that use P&Ts Contact Form plugin. My client now wants the submissions to be visible in the backend and have a 'download to CSV' if possible.
I was looking into the Contact Form Extensions plugin to visualise the data, but I can't find a way to change the submission type from 'contact' so the three different form types can be easily filtered in the left hand column (see screen below).

Is there a way to do this with some custom code on submission? Also, is there a plugin to allow me to download the submissions as CSV?
I'm basically just trying to avoid a new form plugin entirely as the forms are built quite custom on the front end.
Thanks in advance!

You can override the form name by adding a hidden field to your form like this:
<input type="hidden" name="message[formName]" value="myFormName">

Set the value of the hidden field to a unique value for each different form that you have on the site. Then submissions to each form will then be indexed in the control panel by the different values used for the hidden field.
Full documentation for the Contact Form Extensions plugin can be found here: https://github.com/hybridinteractive/craft-contact-form-extensions/blob/master/README.md
There's currently no native way to export the submissions to a CSV. There is a GitHub issue open for this (https://github.com/hybridinteractive/craft-contact-form-extensions/issues/13) which includes a suggested work around using a Twig template to handle the exports: https://github.com/hybridinteractive/craft-contact-form-extensions/issues/13#issuecomment-518668747


Get related entries in plugin via Entries field type I have 2 sections: Gift Cards and Merchants.

In Gift Cards, I have a entries field that is limited to the Merchants section and limited to 1 selection.

In Merchants, I have a field merchantId that is a plaintextfield.

In my plugin, I would like to return all gift cards that have a merchantId of 123.  I've tried a few different ways, but all ways have either given no results or I get a 'missing index Merchant' error in the FieldServices class.

Hopefully someone here has done something similar and can point me in the right direction.

First, you should get all the Merchant Entries with the merchantId of 123

$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section('merchants');
$criteria->merchantId = '123';

$merchants = $criteria->find();

Next, find all Gift Card entries that are related to the found merchants.

$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section = 'giftCards';
$criteria->relatedTo = array(
    'targetElement' => $merchants,
    'field' => 'YOUR-ENTRIES-FIELD'
);

$gift_cards = $criteria->find();


Entry slug auto appends -1 even when the original slug is unique I have an entry slug like this: cics-west-belden-1

the -1 seems to be auto appended to the slug, but there are no other entries with the project cics-west-belden in my project. When I remove the -1 from the end of the slug and save, the -1 always comes back. changing it to cics-west-belden-2 saves works. Even changing it to cics-west-belden- works.

But as soon as I try to save it as  cics-west-belden, it changes back to cics-west-belden-1 again.

Is this a bug with craft or maybe my database somehow got corrupted where it thinks this entry already exists when in fact it doesn't

I don't know the specific rules Craft uses but I believe Craft auto appends the -1 when it tries to save an Element that has a matching URI in the craft_elements_i18n table.

A few scenarios that I can think of that may behave like you describe:

Somehow, there is an existing record in your database that matches the URI of your Entry using the cics-west-belden slug
You have another Section, Category Group, or other custom Element set to generate URIs in the same format as the Section you are posting the Entry to which already has an Element saved using your cics-west-belden slug.

To rule out the scenario where a matching record already exists in your database, open your database and look in the craft_elements_i18n table. Search for all records that match your slug and see if you only find the one:

SELECT *
FROM craft_elements_i18n
WHERE slug = 'cics-west-belden';

To confirm that no other URIs already match your Entry, you could do a similar search in the URI table:

SELECT *
FROM craft_elements_i18n
WHERE uri LIKE '%cics-west-belden%';


Craft CMS logo still showing on CP Login page We have uploaded a logo in the CP, but the CP Login page still has the craftcms logo under the login box. Perhaps a config setting to remove this that I don't know about?

As of Craft 2.5, by default you will see your Site Name in plain text above the login form, and a light Craft CMS logo below it. If you have Craft Client/Pro and upload a custom Login Page Logo from Settings → General, the plain text Site Name will get replaced with that logo, but the Craft CMS logo will remain.

The Login Page Logo was never meant to be used to white-label the CMS - even pre-2.5 if you uploaded a custom logo, there would still be Craft and P&T references in the CP footer (which hasn’t changed).


Can't remove index.php without getting a 404, .htaccess redirect not working, why? So this is not my first craft build, and basically, it's identical to my last setup on the craft front, I can't see anything wrong, but I can't remove index.php without causing a 404. I've tried the .htaccess fix, not luck. The last site I did simply had "deny from all" in .htaccess, but it didn't need index.php, so I don't see why I would need to change that for it to work? Is there anywhere else I can look for a settings change that might allow for cleaning up the urls?

Check and make sure your .htaccess file is in your public HTML folder public/.htaccess!

If you do not include your .htaccess file in your public folder, Craft will display your home page properly, but all other pages will fail to load unless you add index.php?p= in your URL.

Without .htaccess:
http://website.com/mypagethatreallyexists = 404

Without .htaccess:
http://website.com/index.php?p=mypagethatreallyexists = Your page

With .htaccess:
http://website.com/mypagethatreallyexists = Your page


Prepping a field's value from a fieldtype before it hits Craft\BaseModel->__set() I'm trying to create a FieldType that takes a POSTed day/month/year array and saves it into a datetime column, but I think because of the column type it's tripping up before it ever gets to prepValueFromPost().

So far I'm extending Craft\DateFieldType, which defines the content attribute as AttributeType::DateTime for me, and I've got my prepValueFromPost() function:

public function prepValueFromPost($value)
{
    if ($value)
    {
        $value = join('-', array($value['year'], $value['month'], $value['day']));

        return parent::prepValueFromPost($value);
    }
}

To work it into a string that DateFieldType::prepValueFromPost() can use (probably). The issue is, during $entry->setContentFromPost($values), it first sets the raw post content (an array) to the attribute:

/vagrant/craft/app/models/BaseElementModel.php(888): Craft\BaseModel->__set("userDateOfBirth", array("day" => "01", "month" => "1", "year" => "1986"))

Which then looks at the column type for that field, sees its a DateTime and tries to shoehorn my array into createFromString:

/vagrant/craft/app/models/BaseModel.php(349): Craft\DateTime::createFromString(array("day" => "01", "month" => "1", "year" => "1986"))

Which is no good. And all this happens before my fieldtype's prepValueFromPost() ever gets called, so I'm not sure what to do :(

I can see how this is unexpected behavior. The code in BaseElementModel::setContentFromPost() isn’t considering that the ContentModel it’s setting data to is going to be doing its own manipulation of the data before the field type has had a chance to tweak it (thanks to setAttribute()). And in AttributeType::DateTime’s case, that means trying to convert the value to a DateTime object, else completely discarding the value.

Anyway, I’ll tweak this for the next release. Shouldn’t have any negative side effects if we just hold off on assigning the value to the ContentModel until after the field type’s prepValueFromPost() has had a chance to do its thing.


In Commerce, can I apply a discount only on a specific number of one product? I know that I can apply a discount if a specific number of products is ordered. I could also add a discount for a specific product, with a specific amount. But, am I able to create a discount with this conditions:

Applies to entire product type
A specific number of one product is added to the cart

So, if I set this discount for 3 products, but people buy 2 x PRODUCT A, 1 x PRODUCT B, it would not apply. If customers buy 3 x PRODUCT A, 2 x PRODUCT B, it would apply for product A.

I could probably fix it with a plugin, but is it possible out of the box? Am I missing something?

As far as the release notes from Commerce 1.2:
https://craftcommerce.com/changelog#build1323

It can only be given a minimum quantity of items now.


Setting Quantity Field on Subscriptions How can I pass in a quantity value while creating a subscription?

Plugin (version):

Craft CMS (3.1.21)
Craft Commerce (2.1.2)
Stripe for Craft Commerce (1.2.0)

Problem: My website allows users to subscribe to meal plans. For example, a user can subscribe to receive 5 vegetarian meals per week. Another user may also subscribe to recieve 10 meals per week. Currently, I must create two subscritpion plans on Stripe and on Craft (i.e Vegetarian-5 and Vegetarian-10). Stripe's API offers the ability to create a single plan that charges per quantity (i.e I want to create one Vegetarian Plan and charge $10 per meal).

I wrote a plugin that uses createSubscription() from craft\commerce\services. However, ideally I want to send a quantity value but after reviewing Craft's logic for this function, I am unable to figure out a way to pass in a quantity value. However, I could easily bypass Craft and use the Stripe's API to do this (setting subscription quantity through stripe API) but that feels like the wrong solution.

I realize that this is an older question, but I have found the answer for it after much searching, and want to leave this answer for others who might be coming from a search engine.

The way I have found that you would do this is with the Stripe Payments plugin. The documentation for it can be found at https://github.com/craftcms/commerce-stripe.

From there, you will find that there is a beforeSubscribe event. You can use that to set parameters for quantity. From the documentation:

use craft\commerce\stripe\events\SubscriptionRequestEvent;
use craft\commerce\stripe\base\SubscriptionGateway as StripeGateway;
use yii\base\Event;

Event::on(StripeGateway::class, StripeGateway::EVENT_BEFORE_SUBSCRIBE, function(SubscriptionRequestEvent $e) {
    $e->parameters['someKey'] = 'some value';
    unset($e->parameters['unneededKey']);
});

For my subscription, I have found that $e->parameters['items'][0]['quantity'] = 3; works for my setup.


How can I utilize existing UI for my plugin's control panel views? I'm new to building plugins and I need to make templates for the control panel. How can I use existing Craft UI components to keep things consistent and save myself from having to rebuild everything?

Have a look in craft/app/templates for tons of great, easily-reusable examples that make up the existing control panel! They may not be documented, but there's a whole lot of quality stuff there.

You may also want to consider using macros from craft/app/templates/_includes (Craft TemplatesService doc, Twig macro doc), which will go a long way toward good DRY templates.

Bonus: this is also a great way to learn clever ways of doing things in Twig, like breadcrumbs for example. P&T builds excellent stuff, so there's lots to learn from and steal whether it's for the control panel or the front end.


Query multiple fields with dates So I'm trying to build a query based on events and their start and end dates. Once a user selects a year, I want to display all events that took place in that year, but also display events that might have spanned across multiple years and include that selected year. For example, if a user selects 2012. I should display all events starting in 2012, but also events that might have lasted from say 2010-2013.

What I'd like to do is query all event entries and return only events whose startDate is less than or equal to the select year AND whose end date is greater than or equal to the selected year:

{% set startDateParam = '<=' ~ yearParam ~ '-01-01' %}
{% set endDateParam =  '>=' ~ yearParam ~ '-01-01' %}

{% set pastEntries = craft.entries({
   startDate: startDateParam,
   endDate: endDateParam
}).section('events').order('endDate desc') %}

However, this doesn't seem to work. What is the correct way to query for entries that satisfy both the startDate AND endDate?

Any and all help is greatly appreciated. Thanks.

craft.entries isn't going to like a variable in the start or end dates.

i.e. your startDateParam should just be {% set startDateParam = yearParam ~ '-01-01' %}

And then your craft.entries is going to grab everything between the two dates.

If you're trying to grab everything that overlaps the year ends... I suspect you're going to have to do a little bit of funny business...

e.g. start date = a month before the year end, and end date is a month after the end date.

then when you do the loop, have it check both.

If start date is before the end of the year OR the end date is after the beginning of the year.

Then show all the items that meet that criteria. So if there's an event dec 12-13, 2015, the loop picks it up, but your if-check hides it. If it runs dec 30, 2015 to jan 2, 2016, the if-check shows it.

Maybe something like

{% set startDataParam = date_modify('November 1, ' ~ year-1 ~ ' 00:00:00') %}
{% set endDateParam = date_modify('February 28, ' ~ year+1 ~ ' 23:59:59') %}

{% set pastEntries = craft.entries({
 startDate: startDateParam,
 endDate: endDateParam
}).section('events').order('endDate desc') %}

{% for pastEntry in pastEntries %}
{% if pastEntry.startDate => date_modify('January 1,' ~ yearParam ~ ' 00:00:00') or pastEntry.endDate <= date_modify('December 31,' ~ yearParam ~ ' 00:00:00')}
  {{ all your event details here }}
{% endfor %}

That make sense?


How can I retrieve a global value in a different locale? Not much to add to the question, other than I need to display a global's value in a different locale to the current locale.

Is this the best way of doing it?

craft.globals.getSetByHandle('localeModal').locale('es').getFieldValue('headline')

Yes, that's how you would do it.

{{ craft.globals.getSetByHandle('localeModal').locale('es').getFieldValue('headline') }}

Or in shorter syntax:

{{ localeModal.locale('es').headline }}


Importing voucher codes from Espresso Store to Verbb Gift Vouchers I'm doing some messing with MySQL to import some Espresso Store voucher codes into a Craft Commerce site as Verbb Gift Vouchers.

I've got a long query that basically reads the data from the EE table(s) and creates rows in giftvoucher_codes table.
It also creates a corresponding row in the elements and elements_sites tables.

Everything seems to join up and get created but I still don't see the imported vouchers in the Gift Vouchers area of Craft's control panel.

I've tried clearing caches with no luck.

What am I missing? What else needs to be updated to get them to show up?

I think you'd be better off creating a quick module with a controller method to import your voucher codes, to make sure Craft (and Verbb Gift) create all the necessary table rows for the vouchers to work (code is untested, but just to get an idea):

use verbb\giftvoucher\elements\Voucher;

public function actionCopyVouchers()
{
    $esVouchers = Craft::$app->db->createCommand()->select('*')->from('es_vouchers')->all();

    foreach ($esVouchers as $esVoucher) {
        $voucher = new Voucher();
        $voucher->field = $esVoucher->field;
        $voucher->anotherField = $esVoucher->anotherField;
        // ... Whatever your voucher needs ...

        Craft::$app->getElements()->saveElement($voucher);
    }
}


How to store S3 credentials in environment variables? For a Craft 2 S3 asset source, access keys are expected to be entered in from the Control Panel. Is there a way to supply the access key and secret through environment variables instead?

Not really.

In Craft 2 S3 settings ultimately get stored in the database.

Normally the answer would be "you can write a plugin that adds its own Asset Source Type and changes that behavior", but in Craft 2, it is not easy to add custom Asset Source Types, either.

Craft 3 has solved both of those problems.  You can register custom Asset Volume Types as well as override Volume settings.


Reverse Related entries with Matrix Field I have a site with channels ‘articles’ and ‘tutorials.’ An article entry has a matrix field which contains an entry field to link to a tutorial. Every tutorial is linked from within at least one article.

I would like each tutorial page to link back to the articles it appears in.

If I'm on a tutorial page and have the following code in my template…

{% set articles = craft.entries.section('articles').relatedTo(entry) %}
{{ articles|length }}

articles|length is always zero.

I did a test with just a simple entry field to link to a tutorial and that works fine. Is there something special that needs to be done to get it to work with a matrix field? Could it be a configuration issue?

Have a look at the 'Going Through Matrix' section at http://buildwithcraft.com/docs/relations#the-relatedTo-param.

{% set articles = craft.entries.section('articles').relatedTo({
    targetElement: entry,
    field: 'myMatrixField.fieldHandle'
}) %}


Output coupon in the code back end using Craft Commerce I use the plugin Craft Commerce. I can not find how to output the coupon code used by the customer in the back end on the order page.
Anyone would know how to?
Thanks a lot!

I have gone ahead and made the coupon used more visible on the order edit screen. Will be in the next release of Craft Commerce.

In the meantime, if you want the code to show up in the discount description in the backend, add it to the discount description when setting up the discount.


How to properly format this date I have events that are presented by month.  Right now they are being separated by Month but the heading for each chunk shows January as the month for each one.  Not sure why, or how to fix it, am interested in understanding both.  I am somewhat new to craft.

{% if entry.heading is defined %}
{{ entry.heading }}
{% endif %}

{% set allEntries = craft.entries.section('tours').find() %}
{% set allEntriesByMonth = allEntries|group('entryDate.month') %}

{% for month, entriesInMonth in allEntriesByMonth %}

{{entry.entryDate|date('M')}}

        {% for entry in entriesInMonth %}

{{entry.entryDate.month}}.{{entry.entryDate.day}}.{{entry.entryDate.year}}&nbsp;&nbsp;-&nbsp;&nbsp;{{entry.locationCity}}, {{entry.locationState}}&nbsp;&nbsp;&nbsp;register

        {% endfor %}
{% endfor%}

I am trying to adjust the h2 with |date('M') in order to display the date as text.  If I do not do that it displays the correct month number, but when I try to format it it breaks and displays the same month for all entries even though it is still ordering them.  So how can I format this to show month as text without breaking it?

Any attempt to format the date breaks it. The dates below should be september and october.

I would suggest to already format entryDate within the group filter in the way you actually want to output it later.
To do that use Twig's date filter (→ see all possible formatting options).

{% set allEntries = craft.entries.section('tours').find() %}
{% set allEntriesByMonth = allEntries|group('entryDate|date("F")') %}

{% for month, entriesInMonth in allEntriesByMonth %}

{{ month }}

    {% for entry in entriesInMonth %}

{{ entry.entryDate|date('m.d.Y') }}

    {% endfor %}
{% endfor%}


Filter and sort Commerce products based on Matrix blocks We have a website that uses Craft CMS v3.1.28 and Commerce v2.1.6.1. The below logic is implemented within a plugin and we're prepared to do custom implementations aka. prepared to go deep!

I would like to extend an existing ProductQuery with two innerJoins on a Matrix field. The matrix blocks represent product groups (by title; "contain") and sets the order of the product groups. I am currently getting duplicate rows (see code in first answer). I think I might have to innerJoin on the subQuery (generated below)..?

Now, we're currently using the code below to get the products and it works. However, it's not very efficient, since we then have to loop through the matrix and match by title to get the right order.

// $base_product_titles is the array of titles from the matrix blocks
// this query is obviously done per category
// additionally we have some filters ($types and $variant_criteria)

$base_products_query = Product::find()
        ->relatedTo($category)
        ->title($base_product_titles)
        ->type($types)
        ->hasVariant($variant_criteria)
        ->orderBy('type')
        ->with([
            'usage',
            'casing',
            'series',
            'defaultVariant',
            'variants',
            'variants.tire_size',
            [
                'variants.images',
                [ 'withTransforms' => ['product_overview']]
            ]
        ]);

PS: We group the above result by title in the template using |group('title').

I would appreciate any guidance!

Kind regards,
Meinhard

I've tried the following, but it "obviously" gives me duplicate rows and my SQL and Craft/Yii knowledge isn't good enough to solve it. It's basically its own subquery with no relation to the "filters" in the query above, except for the title. I'm thinking that I could innerJoin on the initial subquery (which is the query/result from above) but don't know how ($base_products_query->subQuery equals NULL)?

$base_products_query->innerJoin('`craft_matrixblocks`', "`craft_matrixblocks`.`ownerId` = '".$category->id."' AND `craft_matrixcontent_product_sorting`.`elementId` = `craft_matrixblocks`.`id`");
$base_products_query->innerJoin('`craft_matrixcontent_product_sorting`', '`content`.`title` = `craft_matrixcontent_product_sorting`.`field_product_product_title`);
$base_products_query->orderBy('craft_matrixblocks.sortOrder');


Need help with simple PHP plugin I'm not a plugin developer, nor is my knowledge of PHP sufficient to handle this issue.

I need a simple method or plugin, to be able to generate this PHP code in a template.

<?
$params="";

foreach($_POST as $name=>$value)
{
    if ($name!="controllerPage")
    {
        $params=$params.$name."=".$value."&";
    }
}
?>

In the same template I need this code to retrieve the above

<? echo $params; ?>

Who can show me the way?

This is the POST data that is attached to the URL

$_POST=array (
'view' => 'SearchResult',
'controllerPage' => 'https://navigantes.eu/yachts-search',
'customCssPath' => 'https://navigantes.eu/css/booking-manager-small.css',
'setlang' => 'en',
'target' => '_blank',
'companyid' => '1234',
'filter_country' => 'HR',
'filter_region' => '',
'filter_base' => '',
'filter_year' => '2016',
'filter_month' => '11',
'filter_date' => '10',
'filter_duration' => '7',
'filter_flexibility' => 'on_day',
)

Which needs to be translated to this:

view=SearchResult&amp;customCssPath=https://navigantes.eu/css/booking-manager-small.css&amp;setlang=en&amp;target=_blank&amp;companyid=1234&amp;filter_country=HR&amp;filter_region=&amp;filter_base=&amp;filter_year=2016&amp;filter_month=11&amp;filter_date=10&amp;filter_duration=7&amp;filter_flexibility=on_day&

Solved the issue by using {{ craft.request.getPost('') }} method:

            <iframe name="" width="100%" height="800" frameborder="0" scrolling="auto"
            src="https://www.booking-manager.com/wbm2/page.html?
                view={{ craft.request.getPost( 'view' ) }}&
                customCssPath={{ craft.config.environmentVariables.rootUrl }}/css/booking-manager-small.css&
                setlang={{ craft.request.getPost( 'setlang' ) }}&
                companyid={{ craft.request.getPost( 'companyid' ) }}&
                filter_country={{ craft.request.getPost( 'filter_country' ) }}&
                filter_region={{ craft.request.getPost( 'filter_region' ) }}&
                filter_base={{ craft.request.getPost( 'filter_base' ) }}&
                filter_year={{ craft.request.getPost( 'filter_year' ) }}&
                filter_month={{ craft.request.getPost( 'filter_month' ) }}&
                filter_date={{ craft.request.getPost( 'filter_date' ) }}&
                filter_duration={{ craft.request.getPost( 'filter_duration' ) }}&
                filter_flexibility={{ craft.request.getPost( 'filter_flexibility' ) }}&
            ">
        </iframe>

And finally Brad's suggested method worked by changing craft.request.getSegments() into craft.request.getPost():

{% set segments = craft.request.getPost() %}
{% set stringParams = '' %}

{% for name, segment in segments %}
{% if name != 'controllerPage' %}
    {% set stringParams = stringParams ~ name ~ '=' ~ segment ~ '&' %}
{% endif %}
{% endfor %}

<iframe name="" width="100%" height="800" frameborder="0" scrolling="auto" src="https://www.booking-manager.com/wbm2/page.html?{{ stringParams }}">

I think you can do this in the template by using for example:

craft.request.getSegments

or

craft.request.getParam( name )

See the docs:

https://craftcms.com/docs/templating/craft.request


getting redactor video.js plugin installed I tried to install the redactor video.js plugin but I can't make it work. I tried to intgrate it via "control panel js" plugin. Put the "video" tag under "buttons", but it doesn't appear. How do I integrate the video.js plugin properly?
Craft 3.5.13.2, Redactor 2.8.2

Since the video button is supplied by a plugin, it should go under the plugins key rather than the buttons key. Your config would end up something like:
{
  "buttons": ["html", "format", "bold", "italic", "lists", "link", "file"],
  "plugins": ["video"]
}


Set email recipient based on value of select in freeform - possible? Basically I have a select in my freeform, say with values catalogue A, catalogue B, catalogue C.
Is it possible to set the email recipient depending on the value that the user will select? e.g. requests for catalogue A,B should go to one email address, catalogue C to another one. Any advice appreciated!

FreeForm actually has a Dynamic Recipients field that sounds like it will do what you're wanting. I believe you can choose to have it displayed as a select field, radio buttons, or checkboxes.

Alternatively, you could probably create a little custom Twig and set up dynamic template notifications. I would think you should be able to switch the recipient array there based on the value of your select field for each submission (but it's possible I'm wrong; the Dynamic Recipients field definitely seems like the better option).


Assigned Files in entries won't get synced on localization I've got an entry-type, which has images and sound-files assigned through an asset-field.
When i create an entry, those fields won't be synced in my other languages, even though the mark for "This field is translatable" is checked.

If you want this field to be synced (always same assets selected) across your locales you actually have to uncheck "This field is translatable".


In Craft 3 how do I find the title of the previous and next entry when looping through a channel? {# Set parameters for prev/next elements list #}
{% set params = craft.entries.section('nieuws').all() %}

{# Get the prev/next elements #}
{% set nextEntry = entry.getNext(params) %}

This used to work in Craft 2 in v3 I get an unknown property error. I can retrieve the prev and next links via the paginate tag but how do I retrieve the titles of the prev and next entry??

This did the trick - I'm assuming a news channel here with datestamped entries.

{% set query = craft.entries
    .section('nieuws')
    .id('not ' ~ entry.id)
    .limit(1) %}

{% set prevEntry = clone(query)
    .postDate('<= ' ~ entry.postDate.timestamp)
    .order('postDate desc')
    .one() %}

{% set nextEntry = clone(query)
    .postDate('>= ' ~ entry.postDate.timestamp)
    .order('postDate asc')
    .one() %}

{% if prevEntry %}

< {{ prevEntry.title }}

{% endif %}

{% if nextEntry %}

{{ nextEntry.title }} >

{% endif %}

Hat tip to How to get the previous or next two entries


I want to display entries that have a field that is the same as a field in a global variable There is a publishMonth (multiselect) and publishYear (radio buttons) field in each article. They do not correspond to an actual date. Each article is is associated with one year, or one or more months. I'd like my editor to be able to change two global variables. currentMonth (radio button), and currentYear (radio button) to change all the articles display on the webpage at once at any time she pleases. Some articles may be associated with one or more months. Articles do not get changed over at the same date and time each month, which is why it's not associated with a real month or year. The code below returns nothing.

The idea is to make it as easy as possible for my editor to "flick the switch" to the next month.

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

    {% if entry.publishYear in currentEdition.currentYear %}

{{ entry.title }}

    {% for image in entry.images.limit(1) %}

    {% endfor %}

{{ entry.body|striptags|slice(0,300) }}... Read more

{{ entry.publishYear }}

        {% for option in entry.publishMonth %}

{{ option }}

        {% endfor %}

    {% endif %}

{% endfor %}

Since you've confirmed that the issue is in the if statement and I can see your comparison, I'll clarify usage and propose a solution.

The in operator, is a containment operator and it expects a scalar|primitive value on the left and an array|iterable on the right.

I am assuming that entry.publishYear is an int or a string: 2017. However, I'm not sure about currentEdition.currentYear. It seems like it's also an int or string: 2017.

If the currentEdition.currentYear is not an array or an iterable item, you should use == instead of in.

{% if entry.publishYear == currentEdition.currentYear %}

Have you tried that? Or can you try it and let me know?


entry.getAuthor().getGroups() always return empty array I'm trying to output users groups for every entries in a for loop, but it returns an empty array:

{%for entry in craft.entries.section('news') %}
    ...
    {{ dump(entry.getAuthor().getGroups()) }}
{% endfor %}

But it's working correctly in the entry page itself.

Any idea how I can return the groups in a for loop?

I spot a couple of Twig errors in your code.

First, in your for loop you're casting the entries returned by craft.entries to a variable news, but you're calling entry.getAuthor() inside the loop. Either change news to entry or entry to news.

Second, I'm not sure if craft.entries('news') actually returns anything (or at least not what you actually want) – it should probably be craft.entries.section('news').

Putting it together, this should work:

{% for entry in craft.entries.section('news') %}
    ...
    {{ dump(entry.getAuthor().getGroups()) }}
{% endfor %}

Also, since you're not reporting any error messages output by Craft, I'm guessing you haven't enabled devMode in your development environment. It's a really good idea to have devMode set to true while you're working on your code, because then Craft will report any syntax errors (like your undeclared entry variable) which will make it way easier for you to debug.

Just remember to never have devMode enabled for production environments – it's both a performance and security issue if you do.


Posting remotely - to fields in a channel or a plugin's fields? Been looking at porting a site from EE to Craft.

We have a custom module that accepts a POST and then stores that data in fields in a particular channel. The mappings are stored in extension settings so there are no hardcoded field IDs in the module code.

In Craft, how would we go about that? I can see that we'd need to have a controller method that would be publicly accessibly but am unsure if we can easily use Entries or if we need a custom table with fields, field layout etc.

The use case is a job board. Jobs are just entries in that they have a job title, body, summary, salary range, blah blah blah, and CMS users should be able to create jobs in Craft, so just a channel looks fine. The only addition is that a third party needs to post data to the channel to create jobs too, hence the need for the plugin.

Can you please advise the best approach here? The bit I'm stuck on is either creating mappings in the plugin settings that link the posted data with fields created in the channel, or on showing a template where the CMS user can create and edit jobs using the standard Craft field layout UI.

Hope that all makes sense!

Thanks

I'm not sure if this is the 'best' approach, but you can definitely accomplish this without creating your own tables, unless you have some other specific need. In your plugin defineSettings method you could either define individual fields (if the entry fields are predetermined) or a table field (if both the post data and entry fields should be configurable) to store field mappings. In your public controller method you can then map the post data to your entry's fields via the settings that you defined, perform other security/data checks, etc. and save the entry.

In the plugin's controller:

public function actionSaveJob()
{
    // get 'post to field' mappings from plugin settings
    $pluginSettings = craft()->plugins->getPlugin('JobPostPlugin')->getSettings();
    $titlePostVar   = $pluginSettings->titlePostVar;
    $bodyPostVar    = $pluginSettings->bodyPostVar;
    $summaryPostVar = $pluginSettings->summaryPostVar;

    // retrieve post data
    $title   = craft()->request->getPost($titlePostVar);
    $body     = craft()->request->getPost($bodyPostVar);
    $summary = craft()->request->getPost($summaryPostVar);

    // create a new entry
    $entry = new EntryModel();
    $entry->sectionId  = 2;
    $entry->typeId     = 2;
    $entry->authorId   = 1;
    $entry->enabled    = true;

    // set entry content
    $entry->getContent()->setAttributes(array(
        'title'     => $title,
        'body'      => $body,
        'summary'   => $summary,
    ));

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

Completely untested, but should be more or less correct. If anyone sees an error please comment or feel free to edit.

You would also want to add conditions to ensure that the post data exists and that it is formatted correctly, and that whatever security conditions you've established are met, and perhaps record/return success and or errors.

For simplicity I have shown this all happening in a controller action, however, I think the recommended approach would be to separate this between a controller and a corresponding service, so that the controller is never actually modifying the DB.


Simple user query with orderBy not working Craft 3.3.13

This query does not order users correctly.

{% set users = craft.users.groupId(3).orderBy('lastName asc') %}

Bug?

Just did a simple test on a fresh install of the latest Craft with 3 users in a user group using this code and the output was what I'd expect:

{% set users = craft.users.groupId(1).orderBy('lastName asc') %}

    {% for user in users %}

{{ user.lastName }}, {{ user.firstName }}

    {% endfor %}

Gives:

Aardvark, Adam
Meadows, Marc
Zimmerman, Bob


Building a video subscription library I'm looking for advice. We've had a client float an idea with us for a possible extension to their existing Craft website.  They want to provide a library of pre-recorded fitness video classes for their customers - This would be a subscription AND 'on demand' service. I guess like Mijingo but for fitness? Here's some questions I have:

Is this possible with CraftCMS or would it need Commerce?
We're thinking the Stripe payment plugin - any advice/alternatives?
Can we stream off S3 or is it better to use Vimeo CDN, is there a plugin to assist?
How to ensure videos are only available to logged in users?
What happens when somebody unsubscribes - how do we automatically remove/pause their access?

If anyone has experience in something like this and can offer any pointers, pitfalls to avoid etc,  i'd be so grateful.

Many thanks!

Just recently worked a similar project so I'll share what we've uncovered.

Your needs are basically 2-fold: take payment and provide a platform where people can log into and consume content.

  Is this possible with CraftCMS or would it need Commerce?

Craft has you covered on content, however taking payment is where having Commerce built-in can be beneficial.

If you're able to build the billing component yourself, you don't need Commerce, however having it built-in, can save a lot of development time and having it integrated in the same system makes sense, especially if someone might have access to tiers of content (this class goes here, this one is not included, etc.) Using Craft's user groups can be pretty beneficial here.

  We're thinking the Stripe payment plugin - any advice/alternatives?

Does your client already have other systems where their customers already "subscribe" (eg MindBody, ZenPlanner, Pike13, etc)?

If that's the case, you could interface the two. Upon login (or periodically via cron) ping the 3rd party billing system and see if there's an active subscription. If there is, let them continue; if not, throw up an error message.
If you're going to offer subscriptions, Stripe is currently the only first-party gateway to do so. Payment Gateways are definitely a weak spot for Commerce at the moment.

A lot of offline business will have their own merchant accounts so using a gateway like Authorize.Net is pretty common, however the 3rd party plugin doesn't support subscriptions yet.

As an aside, payment processors hate risk. And the risk becomes higher with digital products, subscriptions, etc. Payment gateways like Stripe are notorious for withholding funds especially if your client scales too quickly, too fast.

When it comes to recurring billing and high ticket amounts, these are payment processor red flags. Having a solid payment processor history is helpful when it comes to disputes and chargebacks. It's a huge bummer to have a client have a super successful launch and then they get an email from their processor saying their account is on hold or that they're withholding funds for 2 weeks. Having a "backup" option of taking payment even if it's manual can be helpful.

  Can we stream off S3 or is it better to use Vimeo CDN, is there a plugin to assist?

Unless you like giving more money to Bezos than necessary, bandwidth on S3 is expensive. And it doesn't really handle video all that well IMO. If someone is on a smartphone with a mediocre internet connection, you don't want to send them down 4K video when medium quality SD or HD would suffice.

Vimeo and Wistia are better options in this respect. These services can tailor the streaming experience and you can easily lock down content. Wistia excels when it comes to more analytics (who watched what, how long and more). Their API is pretty easy to work with as well.

  How to ensure videos are only available to logged in users?

Both Wistia and Vimeo have options to embed only on domains but unlike YouTube and Vimeo, Wistia doesn't let Google index its content by default so it makes it a slightly better choice.

Unlike YouTube where there's not really a good way to prevent users from going back to watch the video on the site (where users can then go and bookmark it), you can customize the player and branding so it's really "embedded" on the site.

  What happens when somebody unsubscribes - how do we automatically remove/pause their access?

On every page load of a restricted page, typically you want to {% requireLogin %} and then check to see if the user has an active subscription.

The Commerce docs and included templates are good examples of a starting place.

Depending on how you setup your site and what the user has access to,  you can relate the Commerce subscription with the class/video module in question to make sure the user is only allowed to see what they currently have purchased or have access to.


BaseURL field not available First time I install CraftCMS and during the wizard as well as in the Control Panel the fields for BaseURL are displayed like this:

I got passed the wizard by using the comand line tool but now can't create a new site.

Am I missing some sort of option / configuration? (running on Windows Server 2019 / IIS 10 / PostgreSQL 12.2)

Edit: I just noticed the same behavior within the email settings:

On our servers we only have the Internet Explorer installed which results in this behavior.

When accessing the site with Chrome or Firefox everything works as it should.


Paginate entries grouped by day Been at this a couple of hours and my head is scrambled. Wonder if anyone has already solved it and cares to share? I'm trying to paginate a list of entries grouped by day - showing 3 days worth of entries on each page. This is slightly different (I think) to other threads on SE. Here's where I'm at so far:

{% set allEntries = craft.entries.section('stories').with(['categories']).all() %}
{% set allEntriesByDay = allEntries|group(e => e.postDate|date('long')) %}
{% for day, entriesInDay in allEntriesByDay %}
    <h2>{{ day }}</h2>
    {% for entry in entriesInDay %}
        ...
    {% endfor %}
{% endfor %}
{% include "_includes/pagination" ignore missing %}

Based on this clever tweet, you can do this:

{% set allEntriesByDay = craft
  .entries()
  .section('stories')
  .orderBy('postDate DESC')
  .with(['categories'])
  .all() | group(e => e.postDate|date('long')) %}

{% set dataProvider = create({
  'class': 'yii\\data\\ArrayDataProvider',
  'allModels': allEntriesByDay,
  'pagination': {'pageSize': 3}}) %} {# Set the days per page here #}

{% set results = dataProvider.getModels() %}

{% set currentPage = dataProvider.getPagination().getPage() + 1 %}
{% set totalPages = dataProvider.getPagination().getPageCount() %}

{% if currentPage > 1 %}
  {% set prevPage = currentPage - 1 %}
{% endif %}
{% if currentPage < totalPages %}
  {% set nextPage = currentPage + 1 %}
{% endif %}

{% if results | length %}
  {% for day, entriesInDay in results %}

{{ day }}

    {% for entry in entriesInDay %}
      {{ entry.title }}

    {% endfor %}
  {% endfor %}

  {% if prevPage is defined %}
    < Previous page
  {% endif %}

  {% if nextPage is defined %}
     - Next page >
  {% endif %}

{% endif %}


Entries related to Users I know this question has been asked a few times but no of the answers work.

I have a News channel with a Users field type as one of the layout fields.

I want to find all news entries related to user id X but the entries returned are wrong.

{# Get current member e.g URL /members/1/ #}
{% set currentMember = craft.users.id(craft.request.segment(2)).first() %}

{# Get current members news entries #}
{% set currentMemberNews = craft.entries.section("news").relatedTo(currentMember) %}

currentMemberNews contains all news. I just want the currentMember news.

Not sure what I am doing wrong?

Have you tried this:

{% set currentMemberNews = craft.entries.section('news').relatedTo({
    targetElement: currentMember,
    field: 'yourFieldHandle',
}) %}

To specifically define the correct field and the fact that the member is on the target side of this relation?


Get assets from an asset source I have a bunch of images that aren't related to any entries but are in an asset source. Let's call this 'My Images'.

How do I just grab those assets? I can't find anything in the docs that suggests this is possible—it seems such an obvious use-case though I'm sure I am missing something.

What you want is craft.assets

  You can access your site’s assets from your templates via craft.assets. It returns an ElementCriteriaModel object.

Use sourceId for the parameter.

To find the sourceId, look at the craft_assetsources table in the database. There doesn't seem to be any way to query for AssetSourceModel.


Localization with categories I am using Lindsey's Language Link plugin for my language switcher.

Everything works well, as long as the url is not a category url.

Here it is:

{% set element = (entry is defined ? entry : null) %}

{% for locale in craft.i18n.getSiteLocales %}
    {{ locale.nativeName|capitalize }}
{% endfor %}

Where can I tell Craft to used the translated slug in my language switcher?

If someone still is looking for an answer:

{% block locale__switch %}
    {# Loop through all of the site locales #}
    {% set otherLocales = craft.i18n.getSiteLocaleIds() %}

    {% for locale in otherLocales %}

        {# Check if site is category or Entry #}
        {% if category is defined %}
            {% set siteLocale = category.locale(locale) %}
        {% elseif entry is defined %}
            {% set siteLocale = craft.entries.id(entry.id).locale(locale).first %}
        {% endif %}

        {# Make sure that it's actually localized to this locale #}
        {% if siteLocale.locale == locale %}

            {# Output a link to it #}
            {{ locale }}{% if not loop.last %} |{% endif %}
        {% else %}

            {# Output a link to the hompage #}
            {{ locale }}
        {% endif %}
    {% endfor %}
{% endblock %}


Visual editor for Craft 3 Client is coming from WP and is used to Elementor (https://elementor.com/). Can create own rows, columns, etc. in content. Is there a visual editor for Craft 3? Client hasn't specifically requested but think they'd like more than just rich text.

If you are looking for "drag and drop" I would use matrix blocks. You can define text block, image block, video block, etc that would be available in Elementor.

Maybe you don't get as much out of the box as a plugin, but you are able to define exactly what is available to the client.

Happy coding :)


In a plugin, what's the way in PHP to output a CSRF token? My plugin has a tab in the CP. On that tab is a form. What's the way for PHP to generate a CSRF token that can be output to the form with echo?

EDIT to document the final answer

$token = craft()->request->getCsrfToken();
$out .= <<<MYFORM
   <form action="#" method="post">
      <input type='hidden' name="CRAFT_CSRF_TOKEN" value='$token'>
      ...
   </form>
MYFORM;
return $out;

And make sure that /craft/config/general.php includes this:

return array(
       'enableCsrfProtection' => true,
);

Maybe try craft()->request->getCsrfToken(), see if that does it?

Edit

Sorry, misunderstood the question, since you are saying your plugin has a CP section then i'm assuming you're actually looking for a twig way to output the CSRF input, not so much a PHP way. To output the CRSF input in your template simply do {{ getCsrfInput() }}


Front end form with Matrix won't add more than one row I have Notification entry with sendTo field and nViewed matrix:
- viewedBy = Users field, limit of 1
- viewedDateTime = Plain Text

User's don't see whole front end form, just a 'Mark as Read' link. The link uses js to populate viewedDateTime and submit form. My form:

<form id="update-{{ msg.id }}" method="post" accept-charset="UTF-8">
   {{ csrfInput() }}
   <input type="hidden" name="action" value="entries/save-entry" />
   <input type="hidden" name="redirect" value="{{ theredirect }}" />
   <input type="hidden" name="sectionId" value="{{ msg.section.id }}" />
   <input type="hidden" name="entryId" value="{{ msg.id }}" />
   <input type="hidden" name="fields[nViewed]" />
   <input type="hidden" name="fields[nViewed][new1][type]" value="viewed" />
   <input type="hidden" name="fields[nViewed][new1][enabled]" value="1" />
   <input type="hidden" name="fields[nViewed][new1][fields][viewedBy][]" value="{{ currentUser.id }}" />
   <input type="hidden" name="fields[nViewed][new1][fields][viewedDateTime]" value="" />
   <button type="submit" class="tx-11 btn bd-0">Mark as read</button>
</form>

When the first user from sentTo clicks the 'Mark as Read' link, they get added to the matrix. All good.

When the second user from sentTo (testing on a different browser) clicks the 'Mark as Read' link it overwrites the first users row instead of adding another row to matrix.

I've also tried using field name="fields[nViewed][new{{ currentUser.id }}]... to make them unique but still overwrites.

What am I missing?
Amanda

According to the craft cms docs

  To show a “New Block” form, first come up with a temporary ID for the
  block, prefixed with new:. For example, new:1, new:2, etc.

so, you need to you use prefix new: with the colon is a must.


A Streamlined Way to Export / Import Entries Between Environments? Do any of you have a preferred workflow for exporting entries to be imported into another installation of Craft using plugins or migrations or other processes? I'd think this would be a good job for a plugin, but I'm also curious what works for other Craft users.

Plugins That Work Well with Feed Me?

It seems that Feed Me is the de facto solution for importing as it's been absorbed into Craft, but is there a specific plugin or method that works well with that plugin for exporting?

The most actively maintained export plugin I've found is "craft-export-csv," but it's a paid plugin that hasn't seen any maintenance since last April, and I'm wary to build a process around a plugin that could see deprecation.

Alternate Plugins?

Beyond something that can be chained into Feed Me, is there an all-in-one solution, like Field Manager for exporting fields? Nothing seems to come up when searching the Plugin Store.

If nothing exists out there that fits this criteria, I'd be down to start working on something like this on my own, as it'd save me and my coworkers potentially hours of copying / pasting fields between environments.

Thanks for your time!

This is what I do to solve this problem: Database & Asset Syncing Between Environments in Craft CMS

I've found that this KISS technique of just declaring one environment as the "gold master" and pulling changes to all other environments works really well for me.


Get all entries from a channel Is there any known way to get all the entries from a certain channel? I dont want to do this in a view but in PHP since i need to do a bulk update of an attribute to all the entries in a certain channel.

You would do that using an ElementCriteriaModel:

$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section = 'mySectionHandle';
$criteria->limit = null;

$entries = $criteria->find();

You can read all about how to work with ElementCriteriaModel’s in the Working with Elements guide in the Craft docs.


How to get first child URL within Craft/Twig Nav tags I have a navigation structure as follows:

{% set page = entry ?? category ?? null %}

    {% nav entry in entries %}

            {{ entry.title }}

            {% ifchildren %}

                    {% children %}

            {% endifchildren %}

    {% endnav %}

As you can see, I have an entry.type called "No link" which means that the user doesn't want the parent page to have a page of it's own, yet it still needs to appear in the nav to give context to the children.

My question is; how can I get the first child's URL within the ifchildren tags so I can make the parent automatically redirect to the first child's page in the navigation?

I know how to do this in regular forloops, but it would be nice to do this within Craft's nav tags.

Thanks,
Jay

In that case you can put this in the href value:

{{ entry.descendants.type('page').first.url ?? '' }}

(Replace page with the other entry type handle(s).)


"Service Unavailable" Error I'm having a problem installing locally on my Mac (using MAMP Pro, Sequel Pro).  I followed all the steps in the Mijingo installation video - plus a few others.  When I go to install Craft CMS I get the following error message:

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

I checked terminal and .htaccess appears hidden under the public directory.  I changed the permissions.  And the config file appears to be pointing in the correct places.

What might I be missing? ...or at the very least, how do I delete and start again fresh?  Is it as simple as deleting the Craft files and starting over again or are there hidden files that need to be addressed before I can start clean again?

It sounds like you're missing permission on a folder in the /craft directory. Best thing to do, is just retrace your steps by following the official install guide.

I don't use MAMP though, so there might be extra stuff you need to do, but if you scroll down to the bottom of that page to the Additional Resources section. There are some other links to articles which might help, in particular this one:

Installing Craft CMS on Mac OS X Using MAMP & Sequel Pro

If you do want to start again then you should be safe to delete the /craft folder and try again. Although unless you're missing files, you shouldn't really need to start again.


How to use assets while building Craft CMS plugins? I am trying to build a basic plugin, when installed has a single nav bar item, and of course a twig template which shows up on clicking on that navbar item.

I have used the basic template to extend to make my page:

{% extends "_layouts/cp" %}
{% set title = "Page Title"|t('plugin-handle') %}

{% block content %}

Page content goes here

{% endblock %}

The resulting page for the plugin looks like shown in the screenshot attached below:

Now I am trying to add content in the content section, but I am not sure how to add my assets

This won't work, and I am guessing I need to get the paths using some variable in the twig templating system, but I am not sure how. And the documentation is not clear on this part, or maybe I don't know where to look right away.

How to include my assets on the page, like images, js and css files?

You need to register asset bundles in your plugin, see the Craft docs -> https://docs.craftcms.com/v3/extend/asset-bundles.html


How can I get parameters in twig? I wrote a PHP script to deploy data to live-cdn and included a "deploy" button on the dashboard. the script returns ?success=true, and i need to show div element with "Congratulations"

i tried this with no success:

{% if app.request.query.get('success') %}
  <div>
    Glückwunsch! Deployment läuft.
  </div>
{% endif %}

Actually, reading from the Craft 2 docs it's:

craft.request.getQueryString()      // returns the whole query string
craft.request.getQuery('success')   // returns only the value of 'success'