_includes/forms documentation on field types I'm trying to find any documentation on the usable forms from  {% import "_includes/forms" as forms %}
so for example I have no idea what the difference is between elementSelect and select or how I get the options in there

Thanks for your help

For anyone looking for more information, you can find all of the form macros for _includes/forms here:

/craft/app/templates/_includes/forms.html

and the child templates here:

/craft/app/templates/_includes/forms/<filename>


How to prevent user save loop in CP? I have a plugin that uses its init function to save custom user data from front end registrations. It uses:

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

and

if (craft()->request->isSiteRequest()) {}

To perform front end save routines.

I want to add a small  custom user save rule for admin usage outside of the IsNewUser logic in order to preserve like this:

 if (craft()->request->isCpRequest()) {
   $user = craft()->users->getUserById($uidfromURL);
   $user->getContent()->URN = 'my custom value';
   $success = craft()->users->saveUser($user);
 }

The problem is that this code just loops thru the plugin. I need the custom field to be manually editable, but i also need to create a default value too on initial user creation in admin.

I had a similar problem a while ago when a plugin listened for onSaveUser and then saved the user itself, causing an infinite loop. Someone provided me something like:

craft()->on('users.onSaveUser', function(Event $event) {
    static $recursionLevel = 0;
    if ($recursionLevel == 0) {
        $recursionLevel++;
        // do your stuff
    }
});


Setting channel url format to include value of entries fieldtype URL I have a channel with an entry type which has a simple dropdown for {region} and an entries fieldtype which links to a channel of destinations.

I'd like the URL format for the channel to be /region/destination/slug. If I do /{region}/{destination.url}/{slug} the output is /region-name//entry-slug, i.e. nothing is output for the destination.

What should I have where I currently have {destination.url}?

It needs to be:

{destination.first().slug}

Or if this is for Craft 3:

{destination.one().slug}


When using "createElementSelectorModal()" how do you respect selected locale? When using createElementSelectorModal() in a plugin, how do you make your source list show items from the current locale selected in the CP? It only seems to show the items from default locale no matter what locale you have selected.

The BaseElementSelectorModal class takes a second parameter settings, which can include a criteria object. This criteria object is used to create an ElementCriteriaModel on the server, which means it can have any property an ElementCriteriaModel can have – including locale:

var currentLocale = Craft.getLocalStorage('BaseElementIndex.locale') || Craft.locale;

var modal = Craft.createElementSelectorModal('Entry', {
    criteria : {
        locale : currentLocale
    }
});


Create entry with newly-uploaded asset programatically I'm trying to do something very simple - but I've yet to find documentation to cover this basic scenario.

I'm writing a plugin. In a controller, I want to create a new entry, and assign an uploaded file to an Assets field on the entry.

I can create an entry using the example code:

$entry = new EntryModel();
$entry->getContent()->title = 'Title of thing';
// set some custom fields
craft()->entries->saveEntry($entry);

One of the fields is an Assets type; I have image data in a variable - I want to create an asset and associate it to the relevant property of the entry.

Assets fields are capable of storing newly uploaded files into assets folders, and then automatically relating them to the entry (making this feature possible).

When you’re saving the entry yourself rather than using the entries/saveEntry controller action, there are two things you need to do in order to take advantage of this feature:

Make sure your form is set up correctly.

The form should be submitting with a POST request, and encoding with multipart/form-data:

<form method="post" enctype="multipart/form-data">

And the file input needs to have an input name based on the Assets field’s handle:

<input type="file" name="fields[myAssetsFieldHandle]">

Your controller needs to tell the entry where to find the uploaded file.

You can do this with setContentFromPost() if you want all custom field values in the POST data to be assigned to the entry automatically, or setContentPostLocation() if you want to assign the custom field values to the entry manually.

setContentFromPost() example:

$entry = new EntryModel();
$entry->getContent()->title = 'My New Entry';

// Look through $_POST['fields'] for any custom field values
// and assign them to the entry's content automatically
$entry->setContentFromPost('fields');

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

setContentPostLocation() example:

$entry = new EntryModel();
$entry->getContent()->title = 'My New Entry';

// Assign the custom field values manually
$entry->getContent()->summary = craft()->request->getPost('fields.summary');
$entry->getContent()->body = craft()->request->getPost('fields.body');

// Tell the entry where these custom fields are coming from in the POST data
// so that the Assets field will know where to look for an uploaded file
$entry->setContentPostLocation('fields');

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

Alternatively, you can manually store the uploaded file into an asset folder using AssetsService::insertFileByLocalPath(), get the resulting file ID, and assign that file ID directly onto the Assets field.

$fileIds = array();

$uploadedFile = UploadedFile::getInstanceByName('fields.myAssetsFieldHandle');

if ($uploadedFile)
{
    $response = craft()->assets->insertFileByLocalPath(
        $uploadedFile->tempName,
        $uploadedFile->name,
        $folderId,
        AssetConflictResolution::KeepBoth
    );

    if ($response->isSuccess())
    {
        $fileIds[] = $response->getDataItem('fileId');
    }
}

$entry = new EntryModel();
$entry->getContent()->title = 'My New Entry';

// Assign the custom field values manually
$entry->getContent()->summary = craft()->request->getPost('fields.summary');
$entry->getContent()->body = craft()->request->getPost('fields.body');
$entry->getContent()->myAssetsFieldHandle = $fileIds;

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

Note that in this approach, the name of the file input doesn’t matter, since you’re the one that’s telling UploadedFile where to look for it in $_FILES.


Is there a way to check if a value exists in an array in twig? Done some searching on this but can't quite find what I'm looking for. Most threads are regarding keys.

I want to know if there is a way to test if a value exists in a twig array.

It should be able to check whether the value is a variable, object or an array.

So for example:

{% if value not in array %}
    .... do someting
{% endif %}

Any suggestions welcome.

Like you said, to test if a value exists in a Twig array you'd do:

{% if myValue in ['apples', 'oranges'] %}
    {# do something... #}
{% endif %}

To check whether the value is an array or object you could use the iterable test:

{% if myValue is iterable %}
    {# myValue is an array or object #}
{% else %}
    {# myValue is probably a string #}
{% endif %}

To be certain, you might be best coming out of Twig using a plugin Template Variable and doing it directly in PHP.


Production siteUrl being used in staging environment I'm using the following multi-env config. My dev config works as expected. However, when I visit my staging site, it is setting the siteUrl to the production Url

    <?php

    // Dev URL
    $devUrl_au  = "au-site.dev";
    $devUrl_nz  = "nz-site.dev";
    $devUrl_us  = "us-site.dev";

    // Testing URL
    $testUrl_au = "test.site.com.au";
    $testUrl_nz = "test.site.nz";
    $testUrl_us = "test.site.co";

    // Production URL
    $liveUrl_au  = "site.com.au";
    $liveUrl_nz  = "site.nz";
    $liveUrl_us = "site.co";

    return [
        /***************************
        GLOBAL CONFIGURATION
        ***************************/
        '*' => [
            'environmentVariables' => [
                'assetUrl'  => '/',
            ],
            'doAnalytics' => false,
            'omitScriptNameInUrls' => 'auto',
            'enableCsrfProtection' => true,
        'siteRoutesSource' => 'file',
        ],
        /***************************
        DEVELOPMENT
        ***************************/
        '.dev' => [
            'devMode' => true,
            'enableTemplateCaching' => false,
        ],
        $devUrl_au => [
            'siteUrl' => [ 'en_au'  => 'http://' . $devUrl_au . '/',],
        ],
        $devUrl_nz => [
            'siteUrl' => [ 'en_nz'  => 'http://' . $devUrl_nz . '/', ],
        ],
        $devUrl_us => [
            'siteUrl' => [ 'en_us'  => 'http://' . $devUrl_us . '/', ],
        ],
        /***************************
        STAGING
        ***************************/
        $testUrl_au => [
            'siteUrl' => [ 'en_au'  => 'http://' . $testUrl_au . '/', ],
        ],
        $testUrl_nz => [
            'siteUrl' => [ 'en_nz'  => 'http://' . $testUrl_nz . '/', ],
        ],
        $testUrl_us => [
            'siteUrl' => [ 'en_us'  => 'http://' . $testUrl_us . '/', ],
        ],
        /***************************
        PRODUCTION
        ***************************/
        $liveUrl_au => [
            'doAnalytics' => true,
            'siteUrl' => [ 'en_au'  => 'http://' . $liveUrl_au . '/', ],
        ],
        $liveUrl_nz => [
            'doAnalytics' => true,
            'siteUrl' => [ 'en_nz'  => 'http://' . $liveUrl_nz . '/', ],
        ],
        $liveUrl_us => [
            'doAnalytics' => true,
            'siteUrl' => [ 'en_us'  => 'http://' . $liveUrl_us . '/', ],
        ],
    ];

I found an existing solution to this. It turns out the order of the file matters and due to the "partial-match", my siteUrl was being set to the staging url and then overriden with the production url.

Proper order of multi-environment config

I'm going to use the solution outlined here
https://craftcookbook.net/recipes/foolproof-multi-environment-config


Prevent craftcms caching CMS page with dynamic template I understood CraftCMS caching should exclude dynamic values, however I have a page built as an Entity within CraftCMS admin which {% include %}'s a template with a form.  The templates dynamic form values are somehow being rendered with cached values.

The included template form uses dynamic values from e.g. {{ craft.session.getFlash(key, '') }} which are getting cached by CraftCMS causing the form to render with someone else's session values.

Neither the Entity nor template had {% cache %} flags, and I've tried various cache settings to try and prevent such as {% cache unless craft.session.hasFlash('key') %} within the form template, and before the {% include %} within the Entity page, however the template is still rendered with cached form values.

This is CraftCMS 2.4 with no custom caching plugins, using a Redis cache store and default Craft caching config values.

How can I prevent this? Thanks!

The {% cache %} tag does not exclude dynamic data.

What it does, is to basically make note of any element criteria (i.e. any code relating to pulling entries, categories, assets, tags or users) contained in the Twig code inside the {% cache %}{% endcache %} pair.

Then, whenever something triggers a change to the related element criteria (e.g. if an entry is edited, published or deleted), the cache will automatically be cleared.

This is all related to elements, though – so any other dynamic data you may have in your template, such as session variables, will not trigger the same behaviour.

If your entry or form templates doesn't have any {% cache %} tags, I'm guessing you do have some in a base template wrapping your entry and form templates? If so, you'll need to take a more granular approach to your caching, e.g. by caching components separately and avoid {% cache %} tag nesting. To that end, your unless statement should work nicely for escaping dynamic data caching, as long as the component you're caching isn't wrapped by a higher-level {% cache %} tag.


Force trailing slash on URLs This is an .htaccess question which I found the answer to but, I need to integrate it with the .htaccess that comes with Craft.

I need to add trailing slashes to the end of all URLs.

I know there is a General Config Setting for adding trailing slashes to URLs to "dynamically-generated URLs" but, in the case there are any hard coded urls with out the trailing slashes or if someone links to the site without trailing slashes it would be nice to set it and forget it via the htaccess.

For example:

http://mydomain.dev/news/news-entry

would 301 redirect to

http://mydomain.dev/news/news-entry/

This is what comes with Craft by default:

<IfModule mod_rewrite.c>
    RewriteEngine On

    # Send would-be 404 requests to Craft
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]
    RewriteRule (.+) index.php?p=$1 [QSA,L]
</IfModule>

I found by just adding the code from the following site it will add slashes via a 301 redirect:

RewriteCond %{REQUEST_URI} /+[^\.]+$
RewriteRule ^(.+[^/])$ %{REQUEST_URI}/ [R=301,L]

Now my .htaccess file looks like the following:

<IfModule mod_rewrite.c>
    RewriteEngine On

    # 301 redirect with trailing slash
    RewriteCond %{REQUEST_URI} /+[^\.]+$
    RewriteRule ^(.+[^/])$ %{REQUEST_URI}/ [R=301,L]

    # Send would-be 404 requests to Craft
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]
    RewriteRule (.+) index.php?p=$1 [QSA,L]

</IfModule>

And here is another version/option which seems to work as well:

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*[^/])$ /$1/ [L,R=301]

Here is a third option which seems to work as well:

# Always append a trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !/$
RewriteRule . %{REQUEST_URI}/ [R=301,L]

I'll update once I've researched and settled upon the best option.


Grouping entries and ordering by section Im grabbing entries from two sections and displaying them using the group filter.

{% set entries = craft.entries().section('extendedEvents, festivalEvents')%}
{% set allEvents = entries %}
{% set allEventsBySection = allEvents|group('section') %}

{% for section, eventsInSection in allEventsBySection %}
- results-
{% endfor %}

No matter what I do the results are coming back ordered as section2 (entry, entry, entry) then section 1 (entry, entry, entry)

How do I affect the order of the sections when displaying the results?

The suggestion to order by sectionId resolved my issue here.

{% set entries = craft.entries().section('extendedEvents, festivalEvents'). orderBy({sectionId: SORT_ASC}) %}

As it was, I was working with two sections, so my quick fix was to simply reverse the order of the output of the for loop...

{% for section, eventsInSection in allEventsBySection | reverse %}


Got an "Oops" Screen While in Installer, Exited to Try Again, and Now I Can't Get Back to Installer Background info: trying to install Craft CMS on a Vm running on Xubuntu

So, I was finally able to see the glorious monkey screen to signify that I'd made it to the installer successfully, when disaster struck soon afterward... I began the installation, enter my info, and ended up waiting on a very, very long "Oops" screen that just seemed to keep going and going. I looked up some resources about the install process while I waited and thought I'd done something wrong, so I exited the window to try again, because no "back" option was available. When I went to the URL again to reenter my info, I got a screen saying "Page Not Found: The requested URL was not found on this server." I did absolutely nothing after exiting the installer, checked to see that the file I was using in the URL is still where it should be, and restarting Apache (and then my VM) didn't help either, so now I'm stuck.

What should I do? Any and all advice will be very greatly appreciated. I can't find the answer anywhere I've looked!

I feel silly posting an answer to my own question, but I wanted to post the solution in case anyone else ran across this, instead of just deleting the question.

I was using the URL http: //localhost/public/index.php/admin/install to get to the installer, and I think it wouldn't let me go back because the installation-- somehow-- was actually successful. I started playing around with the URL and found that http: //localhost/public/index.php/admin brought me to the admin dashboard. Trying to put in the address I gave the site is still throwing a Page Not Found at me, but I'm hoping that's because everything is there but not quite wired-up correctly yet; I'll try to come back and edit this if I find that there is more that should be included here to remedy this.


How do you programatically add a user to a user entry field I have created a controller called myPlugin_Controller.php

This is the following code inside it.

 <?php
class myPluginController extends BaseController
{
    public function actionSave()
    {

        $this->requirePostRequest();

        // get all the post variables
        $elementId = craft()->request->getPost('elementId');
        $userId = craft()->request->getPost('userId');

        // set the name of the field you want to update
        $fieldHandle = 'friends';

        // based on the element and field vars, get the models for each
        // using the elements and fields services
        $element = craft()->elements->getElementById($elementId);
        $field = craft()->fields->getFieldByHandle($fieldHandle);

        // store the current ids into a variable
        $currentIds = $element->{$field->handle}->ids();

        // merge the new id into the current ids
        $newIds = array_merge($currentIds, (array) $userId);

        // save the new array of ids, using the relations service
        craft()->relations->saveRelations($field, $element, $newIds);

        // redirect to the redirect url
        $this->redirectToPostedUrl();

    }
}
?>

This is my code in an html file, it is submitting some data however it returns a 404 error.

   <form method="post" accept-charset="UTF-8">
                  {{ getCsrfInput() }}
              <input type="hidden" name="action" value="myPlugin/Save">
              <input type="hidden" name="redirect" value="/success">

              <input type="hidden" name="elementId" value="{{ user.id }}">

              <input type="hidden" name="userId" value="{{ currentUser.id }}">

              <button type="submit" >Submit</button>
          </form>

i'm not too sure where its going wrong now.

Also if your wondering why its called user this is why
        {% set user = craft.users.username( craft.request.segment(2) ).first() %}
Do you know where I am going wrong now any tips or help is all appreciated! :)

Still not working I have looked at craft cms documentation online i've followed your steps and there steps.

Is there anything you can still see that is wrong?

You will need a custom plugin to do this.

I'll assume that you're familiar with that process.

You can build a form in your template like this, passing in the entry ID you want to add the user to and the user ID you want to add.

<form method="post" accept-charset="UTF-8">
    {{ getCsrfInput() }}
    <input type="hidden" name="action" value="myPlugin/save">
    <input type="hidden" name="redirect" value="/success">

    <input type="hidden" name="elementId" value="{{ entry.id }}">

    <input type="hidden" name="userId" value="{{ currentUser.id }}">

    <button type="submit" >Submit</button>
</form>

Then, you'll need a controller action in your plugin to which you submit a POST request from a form.

public function actionSave()
{
    $this->requirePostRequest();

    // get all the post variables
    $elementId = craft()->request->getPost('elementId');
    $userId = craft()->request->getPost('userId');

    // set the name of the field you want to update
    $fieldHandle = 'myUserField';

    // based on the element and field vars, get the models for each
    // using the elements and fields services
    $element = craft()->elements->getElementById($elementId);
    $field = craft()->fields->getFieldByHandle($fieldHandle);

    // store the current ids into a variable
    $currentIds = $element->{$field->handle}->ids();

    // merge the new id into the current ids
    $newIds = array_merge($currentIds, (array) $userId);

    // save the new array of ids, using the relations service
    craft()->relations->saveRelations($field, $element, $newIds);

    // redirect to the redirect url
    $this->redirectToPostedUrl();

}

EDIT:

It's very important that you follow the naming conventions in the docs.

You controller class should be named MyPluginController, which would then make the action in the form myPlugin/save (controller and action get removed from the exposed plugin and action names).

Also the redirect should be a page on the side where you want the user to go after being added, not pointing to your plugin.


Craft Commerce: Dynamic Product Price Rather than a static price for each product, I need the price to be dynamic based on two other fields of that product. Here's an example of what I need to accomplish:

Product

Field 1: Wholesale Cost (int)
Field 2: Increase Factor (int)

Price: (Wholesale Cost * Increase Factor) + Wholesale Cost

Digging around, I am finding absolutely nothing in regards to making the price of products dynamic. Is this possible at all with Craft Commerce, and if so how would I go about this?

[** Updated Dec 2016]

I think at this stage the best approach will be plugin based.

Create a business logic plugin if you haven't already.

Two good ways of doing that are : Business Logic Plugin or via https://pluginfactory.io

If you listen to:
https://craftcommerce.com/docs/events-reference#commerce_lineitems.onpopulatelineitem

...then you can do (basically any) logic on the price as it is created as a lineItem in the cart (i.e. added to the cart).

Here's some sketch code to get you started:

craft()->on('commerce_lineItems.onPopulateLineItem', function($event){

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

  if(isset($lineItem->options['giftWrapped']) && $lineItem->options['giftWrapped'] == 'yes')){
      $lineItem->price = $lineItem->price + 1;
  }

});


How to handle Belongs To User relationship In a custom plugin is it possible to have a element type with a belongs to relationship to a user, as you can only define half of the relationship (without somehow modifying the userRecord).

What would be the best practices to get something like this working?

Assuming your plugin is going to be the only thing referencing this Active Record relationship, your plugin could have its own MyUserRecord that extends Craft's UserRecord and does something like:

public function defineRelations()
{
    $relations = parent::defineRelations();

    $relations['myUser'] = array(static::BELONGS_TO, 'MyUserRecord', 'id', 'required' => true, 'onDelete' => static::CASCADE);

    return $relations;
}

And you would just utilize MyUserRecord instead of Craft's UserRecord in your plugin.


How do you auto zoom/center Smart Map with multiple markers? How can I auto center and zoom my Smart Map with multiple markers?
Something like this:
var bounds = new smartMap.map.LatLngBounds();
smartMap.map.fitBounds(bounds);

So for starters, let's clear something up for anyone visiting this thread:
We're talking about JavaScript... specifically, how to manipulate a map that has already been generated. The official documentation on what kind of variables (maps/markers/info bubbles) which are created by the plugin can be found here...
Beyond that, you can basically do anything you want with those JS variables. Much of that is beyond the scope of what I can help you with, but I'll try to at least point you in the right direction.

Map JS object
The way you'll want to refer to the map is like this:
smartMap.map['smartmap-mapcanvas-1']

By default, the map will be called "smartmap-mapcanvas-1" (or 2, 3, etc). But this value can be easily overridden when creating your map, by using the id parameter in your options.
Now that you've got this map object, you can do anything you want via the Google Maps API.
Marker JS objects
When you're referring to individual markers, the format looks like this:
smartMap.marker['smartmap-mapcanvas-1.100.myAddressField']

That naming scheme breaks into three separate components:

Your map ID ("smartmap-mapcanvas-1")
The element ID ("100")
The field handle ("myAddressField")

Now that you've got this marker object, you can do anything you want via the Google Maps API.
Info bubble JS objects
The format for marker info bubbles is nearly identical:
smartMap.infoWindow['smartmap-mapcanvas-1.100.myAddressField']

Now that you've got this info window object, you can do anything you want via the Google Maps API.
Debugging
Finally, since it's not always clear what maps, markers, and info bubbles have been created, you have these three functions available to you for debugging purposes...

smartMap.listMaps()
smartMap.listMarkers()
smartMap.listInfoWindows()

Beyond that, you're really just asking a standard JavaScript and Google Maps API question. I'd highly recommend searching Stack Overflow (or just a Google search) to get the best results on "how to use fitBounds" or "how to zoom/center" a map.
Hope that helps!


Import JSON feed data automatically without FeedMe Can JSON feed data be displayed in a Craft site automatically?

I have a page: URL/asdfh3
I've been dynamically using 'asdfh3' to pull in data from the JSON feed that is associated with 'asdfh3'.
This template works - BUT ONLY if an entry for 'asdfh3' already exists in craft.

Whilst this can be achieved by running a feed update using the FeedMe plugin, it isn't a satisfactory method - as the site breaks if new data is entered into JSON without a feed update in Craft (no template found).

So, how can Craft display external content without having to set up entries for each piece of external content?

The answer is Routing.
Define a wildcard route
e.g. URL/path/*
Then tell it to use a particular template if that route is used.

The key thing to do (which I didn't do first time around) is:
Don't duplicate the same route in a section.
If you do, Craft follows the section path not the routing path and expect entries to be in the CMS.


Getting entries excluding the first I'm trying to set up having the first entry pull in and then later down the page pull in the remaining posts (as I need to break the loop with other content). I'm a little unsure how to set up pulling in the 'Not firstEntry' for the second part. This is what I'm working with:
{% paginate craft.entries.section('blog').limit(1) as entriesOnPage %}
{% for entry in entriesOnPage %}
{% set firstEntry = craft.entries.section('blog').order('postDate desc').one() %}

{% if entry.id == firstEntry.id and craft.request.getPageNum() == 1 %}
//output first entry
{% endif %}
{% endfor %}

// DO OTHER STUFF

{% paginate craft.entries.section('blog').limit(12) as entriesOnPage %}
{% for entry in entriesOnPage %}

//OUTPUT 12 Entries not including the first

{% endfor %}

"Measure twice, cut once" goes the saying... (Kind of the opposite here, but the same principle!) - Fetch your data once, then cut it up how you like using Twig filters. In your case you can fetch the first item from an array with [0] and then slice off that same entry from the start of the same array with |slice(1) like this:
{% paginate craft.entries.section('blog').order('postDate desc').limit(13) as entriesOnPage %}

{% set firstEntry = entriesOnPage[0] %}
{% set theRest = entriesOnPage|slice(1) %}

{# ======================================================================= #}

{{ firstEntry.title }}

{% for entry in theRest %}
    {# OUTPUT 12 Entries not including the first #}

{{ entry.title }}

{% endfor %}


Plugins: Managing Related Records I am working on a plugin that is requiring several DB tables, some of which are relational pivot tables. This is more of a general how-to, but also best practice question on managing those relationships. I can post code examples if requested, but I'm more curious if A) I'm missing anything withing Craft and/or Yii or B) if there are already ways to do what I'm asking.

As far as I can tell, Yii does have a way to automatically manage related records, in either a HAS_MANY or MANY_MANY relationship. Meaning, you need to manually save them and also manually how they are updated or deleted.

This is a basic example of the HAS_MANY relationship:

Table A (HAS_MANY Table B records)
----------
id (PK)
attributes

Table B
----------
id (PK)
attributes

Table C (pivot)
----------------
id (PK)
aId (FK)
bId (FK)

I have all of the models and records setup (I think) correctly. If I understand Yii correctly, when saving Table A records and relating Table B records via the pivot Table C, this has to be done via separate calls to TableCRecord->save(). This seems fine, but the question is, is there a way or best practice to handle updating and deleting these relations? And, is there a better way design-wise to handle this either with functionality within Craft or Yii?

Any help or advice is greatly appreciated. If you need more info, I will be happy to provide whatever is needed.

Thanks!
Michael

You can see an example of how we're doing this exact scenario in Craft by looking in the database at the craft_users, craft_usergroups and the join table for the two, craft_usergroups_users as well as their related record classes in craft/app/records, UserRecord, UserGroupRecord and UserGroup_UserRecord.

UserRecord defines its relation to UserGroupRecord like so:

$relations['groups']  = array(static::MANY_MANY, 'UserGroupRecord', 'usergroups_users(userId, groupId)');

Essentially, "I'm related to UserGroups, through the usergroups_users table using the columns userId and groupId".

That way, if you're sticking purely with ActiveRecord, you don't have to worry about manually updating the usergropus_users table... Craft/Yii/ActiveRecord will do it for you.


Searching Multiple Categories in Craft CMS I have four category groups (Position, State, Status, Denomination). I am trying to create a search form so all four categories can be utilized together or individually.

Here is what I have for my form:

<form action="{{ url('ministry-jobs/results') }}">

<input type="search" name="query" placeholder="What are you looking for?" style="width: 100%;">

<select name="position[]">
  <option value="" selected>-- Select Position --</option>
  {% set positions = craft.categories.group('position') %}
  {% for position in positions %}
  <option value="{{ position.slug }}">{{ position.title }}</option>
  {% endfor %}
</select>

<select name="state[]">
  <option value="" selected>-- Select State --</option>
  {% set states = craft.categories.group('state') %}
  {% for state in states %}
  <option value="{{ state.slug }}">{{ state.title }}</option>
  {% endfor %}
</select>

<select name="status[]">
  <option value="" selected>-- Select Status --</option>
  {% set statuses = craft.categories.group('status') %}
  {% for status in statuses %}
  <option value="{{ status.slug }}">{{ status.title }}</option>
  {% endfor %}
</select>

<select name="denomination[]">
  <option value="" selected>-- Select Denomination --</option>
  {% set denominations = craft.categories.group('denomination') %}
  {% for denomination in denominations %}
  <option value="{{ denomination.slug }}">{{ denomination.title }}</option>
  {% endfor %}
</select>

  <input type="submit" value="Search">

And here is what I have on Results Page:

{% set query = craft.request.getParam('q') %}
{% set position = craft.request.getParam('position') %}
{% set state = craft.request.getParam('state') %}
{% set status = craft.request.getParam('status') %}

{% set homeGrownParam = craft.request.getParam('homeGrown') %}
{% set preparedProduceParam = craft.request.getParam('preparedProduce') %}
{% set redTractorParam = craft.request.getParam('redTractor') %}

{% set positionCat = position ? craft.categories.group('position').slug(position).find() %}
{% set stateCat = state ? craft.categories.group('state').slug(state).find() %}
{% set statusCat = status ? craft.categories.group('status').slug(status).find() %}

{% set positionParam = positionCat ? {targetElement: ['and']|merge(positionCat)} %}
{% set stateParam = stateCat ? {targetElement: ['and']|merge(stateCat)} %}
{% set statusParam = statusCat ? {targetElement: ['and']|merge(statusCat)} %}

{% set relationParams = [positionParam, stateParam, statusParam]|filter %}

{% set entries = craft.entries({
    section: 'ministryJobs',
    relatedTo: relationParams ? ['and']|merge(relationParams) : null,
    search: query,
    homeGrown: homeGrownParam,
    preparedProduce: preparedProduceParam,
    redTractor: redTractorParam
}) %}

{{ entry.postDate.format("m/d/y") }}

{{ entry.position }}

{{ entry.church }}

{{ entry.city }}

{{ entry.state }}

I am getting no results. I am not sure what I am doing wrong. Any help is greatly appreciated.

I might be missing something, but your code is missing a {% for entry in entries %} loop wrapped around your <div>.


Craft Commerce - No closure name "Customer" I am taking my first real stab at working with the commerce beta. This plugin is pretty fantastic btw - awesome job guys. I can't comprehend all of the tiny details that went into this considering all of the rabbit holes.

I am running into a snag though, on the last page of checking out it seems everything is going through (using the dummy account) as I can see the pending order in the CP. Perhaps it is something as a mis-configuration on my end (quite possible).

However, I am seeing this error when I click "Pay"

Commerce_AddressModel and its behaviors do not have a method or closure named "customer".

The url is:

www.mysite.com/commerce/customer/order?number=70829108ec467679afb90e2a857e6701

I am using this page to snag a valid visa CC number.

Steps to recreate:
I have enabled guest registration on my page. I used that option to create a new user. I received the confirmation email, clicked and was able to log into my site as the newly created user.

I clicked on the product, entered shipping info (free shipping), entered a valid CC number and clicked "pay".

That's when I see the error. But, the order is showing in the CP.

In the latest beta update a change was made to how addresses are managed. You can no longer access the customer from the address model.

So the following does not work:
{{address.customer}}

There was only one location we did this in the example templates and that was in the file: craft/templates/commerce/_includes/address.html. We removed it from the example templates, so I expect that possibly you have not updated your example templates from the latest release. You will need to manually download the latest release from http://craftcommerce.com/download to get the latest example templates, as the 'one click update' magic does not update the example templates automatically.

If you need to access the customer for the order, it is always best to do it from the order and not the order's addresses – like this:

{{order.customer}}


How do you save a new Entry to be enabled on 2+ Sites? I've made a plugin that let's you import Entries from a CSV file and I'm working through adding localization (Sites) support to it, but I can't figure out the right way to enable an Entry for a second Site.

$entry = New Entry();
$entry->authorId = $authorId;
$entry->sectionId = $sectionId;
$entry->typeId = $typeId;
$entry->enabled = true;
$entry->title = $title;
$entry->Slug = $slug;
$entry->siteId = $firstSiteId;

$entry->setFieldValues($attrs);

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

Everything above works, but it's this next part which I can't get to work properly. It just throws errors about violating the constraint for a duplicate element ID/site ID pair:

$entry->siteId = $secondSiteId;
Craft::$app->elements->saveElement($entry);

I also tried this, but the query never returns any results:

$findTheNewEntry = Entry::find()
    ->sectionId($sectionId)
    ->id($entry->id)
    ->status(null)
    ->siteId($secondSiteId)
    ->one();

$findTheNewEntry->enabled = true;
Craft::$app->elements->saveElement($findTheNewEntry);

I wish it was as simple as being able to provide an array or such for ->siteId but I know that's wrong.

I was able to get this working with this:

$findTheNewEntry = Entry::find()
    ->sectionId($sectionId)
    ->id($entry->id)
    ->anyStatus()
    ->siteId($secondSiteId)
    ->one();

$findTheNewEntry->enabledForSite = true;
Craft::$app->elements->saveElement($findTheNewEntry);

When creating a new entry via ->saveElement(), Craft automatically creates entries for all sites that have that section enabled. The issues I was having were because status and enabledForSite are different, and I needed to use ->anyStatus() to retrieve an element that was globally enabled when I created it but not enabled for the second site yet. Once that was retrieved, I could enable that entry for the second site as well.


Is there a better way than stacked if else i am using a slider in my template, and depending on if the user filled out values in the craft matrix (slides can have up to 4 rows) i want to have twig compile only the necessary code. I am not sure if my attempt is way too long and it could be archived much easier. thanks a lot for the help

    {% for block in entry.slideitemtop %}
    {% set Bild = block.ImageSlideTop.first() %}
    {% if block.textCSlideTop is empty and block.textBSlideTop is empty and block.textASlideTop is empty and block.headlineSlideTop is empty %}

    {% elseif block.textCSlideTop is empty and block.textBSlideTop is empty and block.textASlideTop is empty %}

        {{ block.headlineSlideTop }}

    {% elseif block.textCSlideTop is empty and block.textBSlideTop is empty %}

        {{ block.headlineSlideTop }}
        {{ block.textASlideTop }}

    {% elseif block.textCSlideTop is empty %}

        {{ block.headlineSlideTop }}
        {{ block.textASlideTop }}
        {{ block.textBSlideTop }}

    {% else %}

        {{ block.headlineSlideTop }}
        {{ block.textASlideTop }}
        {{ block.textBSlideTop }}
        {{ block.textCSlideTop }}

    {% endif %}
    {% endfor %}

There is certainly a lot of repeated code here so we can definitely improve on that! There are so many ways you could handle your Twig templates but this is how I would do it:

    {% for block in entry.slideitemtop %}
        {% set Bild = block.ImageSlideTop.first() %}

                {% if block.headlineSlideTop|length %}
                    {{ block.headlineSlideTop }}
                {% endif %}
                {% if block.textASlideTop|length %}
                    {{ block.textASlideTop }}
                {% endif %}
                {% if block.textBSlideTop|length %}
                    {{ block.textBSlideTop }}
                {% endif %}
                {% if block.textCSlideTop|length %}
                    {{ block.textCSlideTop }}
                {% endif %}

    {% endfor %}

All we are doing here is using the same template code for each slide, but for each loop through we are checking if the 4 fields have any content or not.

I also noticed a slide1 class. You can also automatically increment the number at the end of the class for each loop using {{ loop.index }}.


Can't install Craft on a GoDaddy shared hosting server I've followed Shanti's advice when something similar happened to her. However, it hasn't resolved my problem and I think something else is going on.

GoDaddy's support are quite usless (bascially just sales people). Having installed Craft as I normally would, I'm getting this Internal Server Error.

I can't even get to the point of installing craft; even if I try going to

  www.domain.com/index.php?p=admin/install

I have a feeling it's something to do with how the directories are structured for people with multiple domains on a host/reseller account. It looks something like this:

The website is setup to point to the "/website3/public" directory. I know I could put the Craft directory into the Public folder and fiddle with the index.php $craftPath variable. But I want to keep true to Crafts Installation guide, and keep those files secure.

So, if you have a similar setup; how might I go about trouble shooting the problem of getting things pointing in the right directions?

Thanks for the advice guys. It's helped me rule out the directories being an issue (sort of). Turns out that I was able to access the files in the craft directory all along. My issue related to the database settings.

Typically, the 'server' setting in the 'craft/config/db.php' folder is set to 'localhost'. But for GoDaddy you need to use your hostname. Get that by following these instructions.

You will also need to amend your 'craft/config/general.php' settings to include:

'omitScriptNameInUrls' => false,

At this time, I am unable to get clean-urls working on my Craft install. When 'omitScriptNameInUrls' is set to true, and I try to access any page (besides the homepage), I get that Internal Server Error again. I may open an new question for this as it seems to be slightly unrelated now.


Anyway to extend Craft Entry query search in Craft 3 I've had to manually do an SQL call to the get correct results but I was hoping there would be a tidier way of achieving this in Craft 3?

$query = ( new Query() )
->select('craft_content.title, craft_entries.id, ( 3959 * acos( cos( radians(' . $latitude . ') ) * cos( radians( field_clubLatitude ) ) *
            cos( radians( field_clubLongitude ) - radians(' . $longitude . ') ) + sin( radians(' . $latitude . ') ) *
            sin( radians( field_clubLatitude ) ) ) ) AS distance')
->from( 'craft_elements' )
->where('field_clubLongitude != "" and field_clubLatitude != ""')
->join( 'LEFT JOIN', 'craft_entries', 'craft_elements.id = craft_entries.id' )
->join( 'LEFT JOIN', 'craft_content', 'craft_elements.id = craft_content.elementId' )
->andHaving('distance < 100')
->orderBy('distance')
->limit(3);

The "proper" way to access the element query that gets generated is through a plugin via the ElementQuery's query and subquery properties.

It looks like you're doing a Haversine algorithm to calculate distance between a latitude and longitude.  There's are some similar plugins that already do this you can use as an example.

For example: https://github.com/ethercreative/simplemap/blob/v3/src/services/MapService.php


Element API with multiple categories gives back error 500 This works fine on localhost but crashes on remote Server. I can return one category, but it will crash when I try to display multiple categories. I also tried to save the categories in a variable and return the variable, which again worked on localhost but not on remote Server.

'programevent.json' => [
    'elementType' => ElementType::Entry,
    // 'cache' => true,
    'elementsPerPage' => 999,
    'paginate' => false,
    'limit' => 999,
    'criteria' => ['section' => 'program','type' =>'Event'],
    'transformer' => function(EntryModel $entry) {
        HeaderHelper::setHeader([
            'Access-Control-Allow-Origin' => '*'
        ]);
        $parent = $entry->getParent();

        return [
            'title' => $entry->title,
            'url' => $entry->url,
            'id' => $entry->id,
            'description' => (string) $entry->description,
            'level' => $entry->level,
            'themes' => array_map( function (CategoryModel $category) {
                return [
                    'id' => $category->id,
                    'title' => $category->title
                ];
            }, $entry->themes->find()),
            'kindOfEvent' => array_map( function (CategoryModel $category) {
                return [
                    'id' => $category->id,
                    'title' => $category->title
                ];
            }, $entry->kindOfEvent->find()),
            'languages' => array_map( function (CategoryModel $category) {
                return [
                    'id' => $category->id,
                    'title' => $category->title
                ];
            }, $entry->languages->find()),
            'parent' => $parent ? [
                'title' => $parent->title,
                'number' => $parent->number,
                'url' => $parent->url,
                'shuttleLine' => array_map( function (CategoryModel $category) {
                    return [
                        'title' => $category->title,
                        'color' => $category->color
                    ];
                }, $parent->shuttleLine->find()),
            ] : null,

        ];
    },
],

You may want to try further limiting what you're returning from the API call.

The server may just have a low PHP memory size limit set. There are many answers to fix the PHP memory size bytes exhaustion error. Here's a few:

https://stackoverflow.com/questions/415801/allowed-memory-size-of-33554432-bytes-exhausted-tried-to-allocate-43148176-byte
https://stackoverflow.com/questions/561066/fatal-error-allowed-memory-size-of-134217728-bytes-exhausted-codeigniter-xml

That is a PHP ini setting. If you don't have access to the php.ini file, you have to call ini_set()
 somewhere in your source code.

This statement sets no memory limit, although I do not recommend using this: ini_set('memory_limit','-1');

Try the lowest amount that you can afford before deploying application, as this can cause server issues if too much memory is allocated to by a bad PHP script.


How can I reference images separately within a rich text field? I'm migrating some posts from Wordpress, and the posts on Wordpress have the images within a rich text field.

I need to reference the image separately to the rest of the rich text field - below the image there is usually one or two lines of text.

Is there any way I can either:

a. Reference the image in my Twig separately to the rest of the rich text field, or

b. Somehow split the rich text field so that the image url becomes an asset within Craft.

I'm using Feed Me to import the data into Craft and WP All Export to export the data out of Wordpress.

Thanks!

There is currently no native way to achieve this with Feed Me, short of writing your own PHP middle-man script which would parse the HTML, extract just the images, and append it to you XML/JSON.

We do plan on adding hooks later (potentially with examples) for this sort of scenario, as its quite common, but will not be until at least Feed Me 3.1.


Bad Request Unable to verify your data submission and unstyled CP First of all the control panel login is unstyled, and I'm getting Bad Request Unable to verify your data submission when trying to login to the control panel. I can login using a form on the front end, but then I find the CP is still unstyled. Using console I can see the cpresources files cannot be found by the browser - but I've checked they are there, and have file permissions set.
Any ideas???

There isn't really enough information here to give a full answer, but 'Bad Request Unable to verify your data submission' means that Craft is not getting supplied the correct CSRF token.
To confirm, try turning off CSRF protection in your config:
https://craftcms.com/docs/3.x/config/config-settings.html#enablecsrfprotection


Pasting tables from Microsoft Word into Rich Text fields How do you paste a table created in Microsoft Word into a Rich Text field in Craft?

This is not possible at the moment. Craft 2.5 uses the updated Redactor II WYSIWYG editor, which dropped this from it's features. All pasted text is stripped to plain text.

Perhaps someone can suggest an alternative method that we can set up to make this easy for content editors.


Social Poster Setup Qeustion When using a plugin such as Social Provider https://verbb.io/craft-plugins/social-poster/docs/providers/facebook and setting up LinkedIn/Twitter/Facebook do you have your clients login and follow the instructions so everything is under their account?

Or do you do it yourself?

Not sure what the best practice is here

I'm not sure about best practice, but we always use our clients details. They normally own the site, so they should also own the social login flow.

We normally ask them to let us set it up, then they can change the password with the provider (if they want to) once it is working.


Is it possible to add a custom field to User model from a plugin? Within a plugin I'm working on, I'll be adding user synchronisation with a third-party database to enable SSO, so will be creating users within Craft based on an interaction from this other service.

I'd also like to associate the user ID from the other service against the Craft User model. Obviously you can create custom fields from within the CP - but is there a way for a plugin to automatically add a custom field so the admin doesn't need to do it themselves?

First of all, you will need the Pro package to be able to customise the user profile.

Then you would have to use the onAfterInstall and onBeforeUninstall events in your plugin file. These events are called when installing and uninstalling the plugin.

After the install, you need to create a new field and add it to the user field layout. And before uninstall, you have to remove the field from the layout and delete the field itself.

The code below should work, but it doesn't keep the required fields (I didn't find a way to get them using the available functions).

<?php

namespace Craft;

class UserfieldPlugin extends BasePlugin
{
    public function getName()
    {
        return Craft::t('Userfield');
    }

    public function getVersion()
    {
        return '0.9.1';
    }

    public function getDeveloper()
    {
        return 'Mario';
    }

    public function getDeveloperUrl()
    {
        return 'http://craftshake.com';
    }

    public function onAfterInstall()
    {
        // Create the third party field

        $thirdPartyField = new FieldModel();
        $thirdPartyField->groupId      = 1;
        $thirdPartyField->name         = Craft::t('Third Party');
        $thirdPartyField->handle       = 'thirdParty';
        $thirdPartyField->translatable = false;
        $thirdPartyField->type         = 'PlainText';

        craft()->fields->saveField($thirdPartyField);

        // Create the new user field layout

        $fieldLayout = craft()->fields->getLayoutByType(ElementType::User);
        $fieldsIds = $fieldLayout->getFieldIds();
        $fieldsIds[] = $thirdPartyField->id;

        craft()->fields->deleteLayoutsByType(ElementType::User);

        $fieldLayout = craft()->fields->assembleLayout(
            array(
                Craft::t('Profile') => $fieldsIds,
            ),
            array(),
            false
        );
        $fieldLayout->type = ElementType::User;

        craft()->fields->saveLayout($fieldLayout, false);
    }

    public function onBeforeUninstall()
    {
        // Get third party field
        $thirdPartyField = craft()->fields->getFieldByHandle('thirdParty');

        // Remove field from layout
        $fieldLayout = craft()->fields->getLayoutByType(ElementType::User);
        $fieldsIds = $fieldLayout->getFieldIds();
        $fieldsIds = array_diff($fieldsIds, array($thirdPartyField->id));

        craft()->fields->deleteLayoutsByType(ElementType::User);

        $fieldLayout = craft()->fields->assembleLayout(
            array(
                Craft::t('Profile') => $fieldsIds,
            ),
            array(),
            false
        );
        $fieldLayout->type = ElementType::User;

        craft()->fields->saveLayout($fieldLayout, false);

        // Delete field
        craft()->fields->deleteField($thirdPartyField);
    }

}

I hope this helps.

Mario


Paginate search results after combining sections in Craft 3 I have installed the Calendar plugin and I'd like to search across event entries from this plugin and from channel/section entries across the base Craft 3 site.

However, I am getting the usual Limit-Array error when trying to paginate the results.

Is there a method for paginating multiple search results in Craft 3? I haven't come across a way to do this in any current questions or Craft 3 Docs.

I doubt this is possible in Twig by default because you have two different Element types, thus you'll need to different instances of the ElementQuery to populate all models correctly. I think you'll need to create your own pagination. That being said Element::find()->all() will throw an error

  Cannot instantiate abstract class craft\base\Element

Thus you'll have to Query for your elements in your own

// get all possible element ids
$sectionId = X;
$query = (new Query())
    ->select('elements.id')
    ->from('{{%elements}}')
    ->leftJoin('{{%elements_sites}}', 'elements_sites.elementId = elements.id')
    ->leftJoin('{{%entries}}', 'entries.id = elements.id')
    ->where(new OrCondition([
        ['=', 'entries.sectionId', $sectionId], <-- your section Id
        ['is', 'entries.sectionId', null],
    ]))
    ->andWhere(new OrCondition([
        ['=', 'elements.type', \craft\elements\Entry::class],
        ['=', 'elements.type', YourCalenderClassComesHere],
    ]))
    ->andWhere(['elements_sites.siteId' => 1])
    ->limit(10)
    ->offset(0)
    ->column();

// populate entry by Id
foreach ($query as $elementId){
    $element = Craft::$app->getElements()->getElementById($elementId);
}


How to turn off application log in dev mode I have been searching through the admin panel on our staging site trying to find where to turn off the application log.

I know that you can turn off dev mode, and that will turn off the log, but I still want dev mode on, I just want to turn off the log itself.

I did look at the documentation here and was not able to find it.

Any suggestions.

Lifting from this answer to a similar question:

You'll have to write a simple, custom plugin, and add the following to the init() method in your plugin's primary class:

craft()->log->removeRoute('WebLogRoute');
craft()->log->removeRoute('ProfileLogRoute');

For instant success, you can scaffold your plugin by visiting the plugin factory – name it whatever you want and don't enable any components.


Does Craft do joined calls or multiple ones when fetching the related items? [Element API] I'm checking Element API's performance to decide if it's a good idea to replace my own custom API with Element API. Right now, when fetching the related items (Via fields or matrix elements), my API creates a unique joined query with all the right criteria and executes it at the end.

As Element API is able to use all the nice methods from Craft, maybe the question is related to Craft structure itself.

I've tried using MySQL´s SHOW STATUS LIKE 'Com_Select' but it was not really useful.

As Robin mentioned in a comment, this is exactly what eager loading was designed for... bringing in related elements in a single element query call.

The above link shows how to do it from Twig, but you can do it from PHP as well: https://straightupcraft.com/articles/examples-of-eager-loading-elements-in-twig-and-php


How can I save a tag value in an entry in Craft 3 I am working on a plugin and I have the following code

private function _tagProducts(array $products, array $names)
{
    foreach ($products as $productId)
    {
        $product = Craft::$app->getElements()->getElementById($productId, Product::class, null);
        $product['businessTag'] = ['something'];
        $product['purchasedWithVoucher'] = 'no';
        Craft::$app->getElements()->saveElement($product);
    }
}

If I remove/comment out the line $product['businessTag'] = ['something']; this snippet runs just fine and updates the field purchasedWithVoucher just fine. But, if I keep the businessTag line in I get the following error.

(Integrity constraint violation – yii\db\IntegrityException)

I have tried updating the tag field as $product['businessTag'] = 'something'; which at least throws no errors, but the product is not updated with the new tag, however the $product['purchasedWithVoucher']; line does update so I know that simply saving the changes isn't the issue.

The trick here is that Tags are also elements, so you'll need to save them or look them up to assign them. Something like this:

    public function createOrGetTag($keyword, $groupId) {
        $tagQuery = new TagQuery(Tag::class);
        $tagQuery->groupId = $groupId;
        $tagQuery->title = $keyword;
        $tag = $tagQuery->one();

        if (!$tag) {
            $tag = new Tag();
            $tag->groupId = $groupId;
            $tag->title = $keyword;
            Craft::$app->elements->saveElement($tag);
        }

        return $tag;
    }

And then in your field setting, you'd do something like this:

$product->businessTag->id[] = $tag->id;


"Object of class Craft\ElementCriteriaModel could not be converted to string" in Craft CP After updating some fields for entry types and submitting new entries, I'm getting a "Object of class Craft\ElementCriteriaModel could not be converted to string" in the Craft control panel upon trying to access any of the entries.

I can still create entries, but once created, I cannot access it again.

Any idea how to troubleshoot this?

The error it's giving back to me is on line 34

craft/app/templates/entries/_edit.html(34)

22         {% if not isVersion %}
23             <input type="hidden" name="sectionId" value="{{ section.id }}">
24             {% if entry.id %}<input type="hidden" name="entryId" value="{{ entry.id }}">{% endif %}
25             {% if craft.isLocalized() %}<input type="hidden" name="locale" value="{{ entry.locale }}">{% endif %}
26         {% else %}
27             <input type="hidden" name="versionId" value="{{ entry.versionId }}">
28         {% endif %}
29
30

31

32

33                     {% include "_includes/tabs" %}
34                     {% include "entries/_fields" with {
35                         static: isVersion
36                     } %}
37

38

39
40

41
42                 {% if showPreviewBtn %}
43                     {% include "_includes/previewbtns" %}
44                 {% endif %}
45
46                 {% if craft.isLocalized() and section.getLocales() | length > 1 %}

This was caused by an incorrectly configured assets field in the entry type. The upload location had an invalid variable set in the path.


Filter locations by country in Smart Map I'm using Smart Map to find locations ordered by distance. But I can only set 3 parameters: target, range and units. However, when my range goes beyond the country borders I obviously get results in other countries. I want to list all locations within a country by distance, but limited to that country.
Is it possible to do this? I tried related items, but can't seem to get it to work. And I don't see any option in Smart Map either.

What I've done to do something very similar is to add a template variable to my BusinessLogic plugin, that takes the ElementCriteriaModel, prepared with all other parameters e.g. section, limit and SmartMap set. The plugin then translates the model into a Yii CDbCommand using buildElementsQuery, adds the additional conditions to the query and returns the further filtered entry models to the template.

Here's my service function with modifications for your country filtering needs. It#s untested but should probably work as is:

public function addCountryCriteria(ElementCriteriaModel $criteria, $country)
{
    $query = craft()->elements->buildElementsQuery($criteria);

    // Add where condition for country filter
    $params = array(':country' => $country);
    $conditions = array('smartmap_addresses.country = :country');

    $query->andWhere($conditions, $params);

    // Join addresses table to bring in the state
    $query->leftJoin('smartmap_addresses smartmap_addresses', 'smartmap_addresses.elementId = entries.id');

    // Get query results and populate entry models
    $results = $query->queryAll();

    return EntryModel::populateModels($results);
}

Also have a look at my other answers on how to add conditions to CDbCommand from the template:

How do I select entries that have a particular block type?
Filtering Matrix through field value and multiple relations


Can't use composer with CraftCMS 3 I'm having trouble making updates using composer on a new CraftCMS 3 install. This was working at one point as I was able to require a local repository for plugin development purposes.

Any composer usage ("composer info", "composer update", "composer list", etc.) yields the following:

[UnexpectedValueException]
Package cebe/markdown's source key should be specified as {"type": ..., "url": ..., "reference": ...}, {"type":"git","url":"https:\/\/github.com\/cebe\/markdown.git","reference":null} given.

My (abbreviated) installed.json is as follows:

[
{
    "name": "cebe/markdown",
    "version": "1.1.2",
    "version_normalized": "1.1.2.0",
    "source": {
        "type": "git",
        "url": "https://github.com/cebe/markdown.git",
        "reference": null
    },
    "dist": {
        "type": "zip",
        "url": "https://api.github.com/repos/cebe/markdown/zipball/",
        "reference": null,
        "shasum": ""
    },
    "require": {
        "lib-pcre": "*",
        "php": ">=5.4.0"
    },
    "require-dev": {
        "cebe/indent": "*",
        "facebook/xhprof": "*@dev",
        "phpunit/phpunit": "4.1.*"
    },
    "time": "2017-07-16 21:13:23",
    "bin": [
        "bin/markdown"
    ],
    "type": "library",
    "extra": {
        "branch-alias": {
            "dev-master": "1.1.x-dev"
        }
    },
    "installation-source": "dist",
    "autoload": {
        "psr-4": {
            "cebe\\markdown\\": ""
        }
    },
    "notification-url": "https://packagist.org/downloads/",
    "license": [
        "MIT"
    ],
    "authors": [
        {
            "name": "Carsten Brandt",
            "email": "mail@cebe.cc",
            "homepage": "http://cebe.cc/",
            "role": "Creator"
        }
    ],
    "description": "A super fast, highly extensible markdown parser for PHP",
    "homepage": "https://github.com/cebe/markdown#readme",
    "keywords": [
        "extensible",
        "fast",
        "gfm",
        "markdown",
        "markdown-extra"
    ]
}

]

I've been staring at this all afternoon and could use a fresh set of eyes. Anyone have any ideas?

Thanks in advance.

All of the references in the source key were missing from my old installed.json file.

I'm not entirely sure what caused the issue but I corrected by installing a new instance of Craft and copying the installed.json into the version of the file that was causing problems.

I am now able to run composer commands again.


How to rearrange the order of blocks of a single matrix field using a frontend form? I'm trying to rearrange the matrix block order using a frontend form.

If I use JavaScript to change the order of inputs in the DOM will this change the order in the backend after form submission?
How do you include the correct value for image fields, is this using the image id?

I have a reduced test case of what I came up with below, anyone see where I'm going wrong?

<form method="post" accept-charset="UTF-8" enctype="multipart/form-data">
   {{ getCsrfInput() }}
   <input type="hidden" name="action" value="entries/saveEntry">
   <input type="hidden" name="redirect" value="viewentry/{slug}">
   <input type="hidden" name="entryId" value="{{ entry.id }}">
   <input type="hidden" name="fields[galleryBlock]" />

   {% for block in entry.galleryBlock %}

       {% switch slide.type %}

       {% case 'landscape' %}
            {# block 1 #}
            {% set image = block.image[0] ?? null %}
            <input type="hidden" name="fields[galleryBlock][{{ block.id }}][landscape]" value="{{ image.id }}">
            <input type="hidden" name="fields[galleryBlock][{{ block.id }}][enabled]" value="1">

        {% case 'portrait' %}
            {# block 2 #}
            {% set image = block.image[0] ?? null %}
            <input type="hidden" name="fields[galleryBlock][{{ block.id }}][portrait]" value="{{ image.id }}">
            <input type="hidden" name="fields[galleryBlock][{{ block.id }}][enabled]" value="1">

    {% endswitch %}

{% endfor %}

Your sort order will change according to your HTML, so when you change your html, the sort order will change. You can use certain Javascript libraries to move your containers in your DOM, when you save the entry, your related entries will change.

As for every relation field in Craft, you only have to insert an array of ids to relate the elements.

<input type="hidden" name="fields[galleryBlock][{{ block.id }}][landscape]" value="{{ image.id }}">

Is wrong because you insert the id of an image, not an array

<input type="hidden" name="fields[galleryBlock][{{ block.id }}][landscape][]" value="{{ image.id }}">

is the correct way


How do I check if a Global field exists in a template? In a template, can I check whether a Global field exists, before I try to output its value? I want to ensure the page doesn't break entirely in the unlikely event of the field being removed from the CMS.

If I do:

{% if myGlobalSet.myField is defined %}
    Defined.
{% endif %}

then it works as expected; "Defined" isn't displayed if myField doesn't exist.

But if I have:

{% if myGlobalSet.myField is defined %}
    Defined. {{ myGlobalSet.myField }}
{% endif %}

I get:

  Craft\GlobalSetModel and its behaviours do not have a method or closure named "myField".

if that field doesn't exist. It's like it's trying to process the field even though it's not defined.

That's a known issue with Twig's is defined test.  See here for an explanation and workarounds.

Note that this is no longer an issue in the upcoming Craft 3.


Craft's Content Table I'm essentially in the process of learning Craft and in that process have made some great strides.

Today I was examining Craft's tables to see how it was actually storing fields created through Settings-> fields. To my surprise most fields end up as a new column in the content table. To me this seems like a serious flaw as there is a very real limit to the size a table can grow to.

Given this information; what is recommended for developing a site in Craft that needs to have many fields?

If you have an answer I'd appreciate it. Please make it detailed. I'm at a loss with this one. Hopefully there is something I'm missing because if no... Craft may not be the solution I'm looking for. Which would be unfortunate.

Thanks

MySQL has a hard coded limit of 4,096 columns per table, although that can be effectively limited by the data types of columns involved.

Matrix fields get their own tables, so they don't count against the craft_content table.

But yes... if you're planning on having non-Matrix fields in the 2,000 - 4,000 field range, then there's a chance you'll bump into MySQL limitations.


How can I get the correct label of a dropdown that has matching values? I have a drop-down field in the CP - It represents a range of numbers that are based either a percent or a fixed number.

For example, a choice could be Fixed 5% or a choice could be Variable 5%
In either case, the value of my field is 5.00 for both options. The label is different, one says "Fixed" the other says "Variable".

It seems that this is a bad approach as I will usually get the first match based on value.

Let's say I have Fixed 5% listed first in my drop down field, but I actually choose Variable 5%. Currently, I am getting Fixed 5% as the selected option instead of Variable 5%.

I'm not sure how I can set up this field correctly so that Craft can see what I have chosen correctly. Perhaps there is a better way to setting up my drop down?

Craft saves only the option value of a field, not the option description. After saving and editing again, it loops trough all the option values and compare it with the saved value. If it matchs it selects the first option.

You always need to have unique values. For example you can use 5fix and 5var as option values. If you need different outputs in your frontend template, you can use a switch case like this (code is untested, but should work):

{% switch entry.field %}
  {% case "5fix" %}
    Fixed 5%
  {% case "5var" %}
    Variable 5%
{% endswitch %}


How do I setup an assets feed using the FeedMe plugin? I want to setup an assets feed using the FeedMe plug-in.  Everything is well documented, but the documentation for assets is still TBA.

I previously created and updated entries using FeedMe.  Now, I want to add a PDF asset to each entry.

My PDFs are already uploaded to an S3 bucket assigned to the asset field I want to FeedMe to update.  But, I can take them down and start clean if that works best.

I believe they've added the documentation you're wanting here: https://verbb.io/craft-plugins/feed-me/docs/content-mapping/field-types#assets

Assets
Accepts single or multiple values. You should supply the filename only, excluding the full path to the asset, but including the filename. If you're uploading remote assets, you'll need to produce fully-qualified URLs.
Additional Options

Upload remote asset (choose how to handle existing assets - Replace/Keep/Ignore)
Inner-element fields

<Asset>my_filename.jpg</Asset>
// Or
<Assets>
    <Asset>my_filename.jpg</Asset>
    <Asset>my_other_filename.jpg</Asset>
</Assets>

//
// When selecting upload
//
<Asset>http://mydomain.com/my_filename.jpg</Asset>

// Or
<Assets>
    <Asset>http://mydomain.com/my_filename.jpg</Asset>
    <Asset>http://mydomain.com/my_other_filename.jpg</Asset>
</Assets>


Craft CMS, Amazon EC2 & Load balancers I am looking for a simple solution & if possible resources on how to go about getting Craft CMS setup behind a load balancer. Craft CMS is going to be hosted on AWS EC2 instance, I have MySQL on a different instance. I have read about setting up and using shared storage variables but I haven't really found a way to setup a shared storage. Anyone has any idea on where to begin?

I don't know if anything on AWS can be considered simple, but there is a good writeup on getting Craft up and running with EC2: https://solspace.com/blog/spinning-up-a-craft-cms-development-site-on-amazon-ec2


How do I make display a specific post based on what the day of the week it is? I can do it in PHP, but I'm having trouble converting it to twig.

Here's the PHP:

$day = date("l");
date_default_timezone_set('America/Chicago');

if ($day == "Saturday")
{
    echo "
SATURDAY SPECIALS
";
    echo "

";
    echo "
FOOD
";
    echo "
Half priced desserts
";
    echo "
DRINK
";
    echo "
$1 off Seasonal Pints
";

}
elseif ($day == "Sunday")
{
    echo "
GAMEDAY SPECIALS
";
    echo "

";
    echo "
FOOD
";
    echo "
One Free Kids Meal w/ each Adult Meal
";
    echo "
DRINK
";
    echo "
$3 on ALL Bottled Beers
";    }
elseif ($day == "Monday")
{
    echo "
MONDAY SPECIALS
";
    echo "

";
    echo "
FOOD
";
    echo "
$1 Tenders
(5 piece min.)
";
    echo "
DRINK
";
    echo "
$2 Lonestar Pints
";  }
elseif ($day == "Tuesday")
{
    echo "
TUESDAY SPECIALS
";
    echo "

";
    echo "
FOOD
";
    echo "
$.50 Boneless Wings
 (10 piece min.)
";
    echo "
DRINK
";
    echo "
$4 Margaritas
";  }
elseif ($day == "Wednesday")
{
    echo "
WEDNESDAY SPECIALS
";
    echo "

";
    echo "
FOOD
";
    echo "
Half price APPs!
";
    echo "
DRINK
";
    echo "
$3 shots of Jameson & Jager
";
}
elseif ($day == "Thursday")
{
    echo "
THURSDAY SPECIALS
";
    echo "

";
    echo "
FOOD
";
    echo "
2 for $10 Wingzup Burgers
";
    echo "
DRINK
";
    echo "
$3 Draft Beers all day
";
}
else
{
    echo "
FRIDAY SPECIALS
";
    echo "

";
    echo "
FOOD
";
    echo "
$2 Chili Pies
";
    echo "
DRINK
";
    echo "
$10 Pitchers (Bud Lt./Ziegenbock/Lone Star)
";
}

To get the current date and time in Twig use the string "now" and filter it with the date() filter to return it in the format you need (see the list for supported parameters).

Then do the if / elseif conditionals similar to how you'd do it in PHP. Another option would be to use the Craft specific switch tag.

{% switch "now" | date("l") %}

    {% case "Monday" %}
        {# Do Monday stuff #}

    {% case "Tuesday" %}
        {# Do Tuesday stuff #}

    {% case "Wednesday" %}
        {# Do Wednesday stuff #}

    {# etc. #}

{% endswitch %}


Loading entry based on dynamic route I'm trying to load an entry based on the following url:

/artists/nameOfArtist/nameOfCategory/myEntry/thumb

This URL follows the structure of my entries: Artist > Category > Entry

So, I'm thinking that something like this should work:

{% set project = craft.request.getSegment(-2) %}

- This gets me the variable from 'myEntry' segment.

{% set artistParent = craft.request.getSegment(-4) %}

- This gets me the variable from 'nameOfArtist' segment.

Then, I want to find the 'project' entry that lives under 'nameOfArtist'.

{% set entry = craft.entries.slug(project).descendantOf(artistParent).first %}

but this is not working. What am I missing? Or is there a better way of doing this?

I think it's because you're trying to cram too much into your entry variable.  For one, .slug() is going to return an entry with that slug, so I think that's a bit of a full stop.  For two, .descendantOf() accepts an EntryModal object, but you're feeding it a uri/slug (ie. name-of-artist).

Try something like this:

{% set artistEntry = craft.entries.slug(artistParent).first %}
{% set projectEntry = craft.entries.descendantOf(artistEntry).first %}

Keep in mind that .descendantOf() only works with structures (not channels), so I'm assuming that's what you're working with. Also, you may need to specify how far down the lineage to go with .descendantDist().


How to Make getURL Output Complete URL (rather than root relative) I'm using getURL() as follows in my Craft template:

{% set sharingImageURL = entry.sharingImage[0].getUrl('socialMedia') %}

Every time the output is a root relative URL and I'd like it to be a complete URL (including http://www.mydomain.com).

I can't figure out how to make that work. Can I do it with getURL() or is there a different method I should be using? Would appreciate some guidance!

Thanks.

Craft should actually output absolute URLs when using getUrl. But you need to set siteUrl to make this work, so check if you have it set in Settings → General or with a siteUrl property in your general.php config file.


How to replicate a Craft installation as a starting point I want to create a basic Craft installation that I can use as my starting point. I don't want to just start with the Craft download, because there is a lot of common setup I don't want to repeat every time.

My problem is making sure I properly pay Pixel & Tonic for a new license each time I need one.

Relevant link: http://buildwithcraft.com/help/license-enforcement

But the TLDR is that purchases are tied to your craft/config/license.key file and the purchase will follow that file wherever it goes.

So as long as your replication script ignores that file, you'll get a fresh one tied to Craft Personal Edition the first time that Craft sees it's has an internet connection and you can make a new purchase.

Additionally, and regardless of edition, Craft will tie the license.key file to a domain when it thinks it's being run on a "public" domain.  Here is how we determine what is public.

Even if Craft gets that wrong (maybe you develop on public staging domaina.com, but the site will ultimately be on a public domainb.com) and Craft ties the license.key file to the staging domaina.com, the worst that will happen is that when you deploy the license.key file to domainb.com, you'll get a alert in the control panel saying something to the affect of:

"This license.key file is already in use on domaina.com.  Would you like to transfer it to domainb.com?"

None of the site's functionality will be affected.


Craft CMS Redactor formatting I am wondering the way to go about modifying the redactor formatting settings either for all the configs or on a per config basis. I want to add custom formatting styles and classes for various text elements. Per the documentation
it seems I need to add it with JS (not something I add in a config json file) but i'm not sure where I need to add the file.

You can use JavaScript to edit the Redactor settings, but the correct answer here is to add the settings with JSON config files. Those should go into your /craft/config/redactor folder.

Take look at the Redactor Styles plugin though – it will add a couple of textareas to your CP for adding custom Redactor JSON and/or CSS, which should make this a bit easier.


Use function provided by plugin only if plugin is installed and enabled I want to use asset rev in my template, but only if plugin is installed and enabled:

    {% if craft.app.plugins.getPlugin('assetrev') is not null and craft.app.plugins.getPlugin('assetrev').isInstalled %}
        {% set fileName = rev(file) %}
    {% else %}
        {% set fileName = file %}
    {% endif %}

Hovewer when i disable plugin, mere existence of rev function in my template, still causes error.

you can check if the plugin is installed and enabled with:

{% if craft.app.plugins.isPluginEnabled('assetrev') %}
  {% set fileName = rev(file) %}
{% else %}
  {% set fileName = file %}
{% endif %}

you won't need the extra check craft.app.plugins.isPluginInstalled('assetrev') then.

isPluginEnabled():

  Returns whether a given plugin is installed and enabled.


How can I list Entry Types of a single Section? The following outputs all sections and their entry types, but I'm struggling to work out how I output only the entry types from the "blog" section.

{% for section in craft.app.sections.allSections() %}

{{ section.name }}

    {% for type in section.getEntryTypes() %}

{{ type.name }}

    {% endfor %}

{% endfor %}

I thought this would work

{% for type in craft.entries.section('blog').getEntryTypes() %}

{{ type.name }}

{% endfor %}

But I've hit a wall because getEntryTypes() is an unknown method.

You're close – this should work:

{% set blogSection = craft.app.sections.getSectionByHandle('blog') %}
{% set blogSectionEntryTypes = blogSection.getEntryTypes() %}

{% for entryType in blogSectionEntryTypes %}
    <p>{{ entryType.name }}</p>
{% endfor %}

The reason why craft.entries.section('blog').getEntryTypes() didn't work is that craft.entries will actually create an ElementQuery, which is used to query for elements (e.g. entries).

When you use craft.app.sections or craft.app.getSections() (it doesn't really matter which variant you use, although the latter is a micro-optimisation in terms of performance) you're interacting with the Sections service, which is what you need to use to work with sections and their entry types directly, rather than entries.


How do you eager load or join reverse relationships for entries? So I have structures that are related in the follwing way:

Locations has many Providers
Providers has many Health Topics

I know that I can eager load all Locations with related Providers and Health Topics very easily using using something like this:

craft.entries.section('locations').with(['providers.healthTopics']).all()

However how can I eager load the reverse relationship, loading all Health Topics with their related Providers and Locations? The eager loading function seems to go from parent to children but not from children to parent...though I could be missing something there?

Ok so here's how I ended up doing this. Essentially querying everything and adding a sourceId and targetId property to each result. In order to get this query to work though, we need to add a behavior to the Entry component to support two new properties, sourceId and targetId.
// This basically left-joins the the relationship table to our sections. This allows us
// to essentially "eager-load" in reverse.
$relatedQuery = Entry::find()
  ->section(['healthTopics', 'providers', 'locations'])
  ->addSelect('relations.targetId')
   ->addSelect('relations.sourceId')
   // You can query to get the field ids here, I just decided to look them up in the db.
    ->leftJoin(
               '{{%relations}} relations' ,
                '([[elements.id]] = [[relations.sourceId]]) AND ([[relations.fieldId]] = 2 OR [[relations.fieldId]] = 5)'
            )
    ->groupBy('elements.id')
    ->all();

    // Same thing here, just looked up the section ids instead of querying for them.
    $healthTopics = ArrayHelper::where($relatedQuery, 'sectionId', '1');
    $providers = ArrayHelper::where($relatedQuery, 'sectionId', '3');
    $locations = ArrayHelper::where($relatedQuery, 'sectionId', '2');

Next, I needed to add a behavior to the Entry component so that it could support having the two new properties we added, sourceId and targetId.
<?php

namespace foo\behaviors;

use yii\base\Behavior;

class EntryBehavior extends Behavior
{
    public $targetId;
    public $sourceId;
}

Event::on(Entry::class, Entry::EVENT_DEFINE_BEHAVIORS, static function (DefineBehaviorsEvent $event) {
    $event->behaviors['entryBehavior'] = ['class' => EntryBehavior::class];
});


Bad Request: Post Request Required when saving hyperlink in specific redactor field I'm having a strange issue here. I have a site running Craft 3.3.7. I have an entry with a matrix field with several redactor fields in it. In one of those redactor fields, I have a paragraph of text. I can save the entry fine, until I try to add a hyperlink (either via the button or adding it in the html editor) at which point I get a Bad Request: Post Request Required error.

I can add hyper links to the other redactor blocks on the entry and to other entries on the site. I tried simply adding a new block and moving the text to there but I get the same error.

I can save the paragraph without the link, so there doesn't seem to be a strange character throwing it off. And it has nothing to do with the href destination as I tried several and even left it empty and received the error every time.

I found an issue in the Redactor github that looks similar that was related to the HTML Purifier, but that it is switched off for this field.

I've checked with server support and there are no relevant errors displaying on that end.

I've checked the craft error logs and it looks like adding the hyper link is causing the attempt to save to come through as an empty post request, thus the error. Unsure why that is.

2019-12-06 17:38:24 [-][12172][ql7adqo20ana0h4he9iiv3iv30][error][yii\web\HttpException:400] yii\web\BadRequestHttpException: Post request required in /home/[sitename]/vendor/craftcms/cms/src/web/Controller.php:333
Stack trace:
#0 /home/[sitename]/vendor/craftcms/cms/src/controllers/EntriesController.php(311): craft\web\Controller->requirePostRequest()
#1 [internal function]: craft\controllers\EntriesController->actionSaveEntry(false)
#2 /home/[sitename]/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)
#3 /home/[sitename]/vendor/yiisoft/yii2/base/Controller.php(157): yii\base\InlineAction->runWithParams(Array)
#4 /home/[sitename]/vendor/craftcms/cms/src/web/Controller.php(187): yii\base\Controller->runAction('save-entry', Array)
#5 /home/[sitename]/vendor/yiisoft/yii2/base/Module.php(528): craft\web\Controller->runAction('save-entry', Array)
#6 /home/[sitename]/vendor/craftcms/cms/src/web/Application.php(299): yii\base\Module->runAction('entries/save-en...', Array)
#7 /home/[sitename]/vendor/craftcms/cms/src/web/Application.php(566): craft\web\Application->runAction('entries/save-en...', Array)
#8 /home/[sitename]/vendor/craftcms/cms/src/web/Application.php(278): craft\web\Application->_processActionRequest(Object(craft\web\Request))
#9 /home/[sitename]/vendor/yiisoft/yii2/base/Application.php(386): craft\web\Application->handleRequest(Object(craft\web\Request))
#10 /home/[sitename]/html/index.php(21): yii\base\Application->run()
#11 {main}
2019-12-06 17:38:24 [-][12172][ql7adqo20ana0h4he9iiv3iv30][info][application] $_GET = [
    'p' => '500.shtml'
]

$_POST = []

$_FILES = []

From 'p' => '500.shtml' it looks like your server is configured to redirect to a 500.shtml file whenever it encounters an error, which is probably confusing Craft routing and obscuring the real error message.

I'd check to see if you have Suhosin or ModSecurity installed on the server as it's possible the link you're trying to add it tripping up one of their rules.


Dynamic entry template not loading on staging site but works on local.dev I'm having a strange issue where pages aren't loading on the staging site that were all working fine on the local.dev site.

I have a Section called Available Homes and in that section it has two Entry types called Available Homes and Plot which link to two entry templates, that are dynamically called from the main entry.html.twig template, which then links to the sub folder

/entry
  /availablehomes
    availablehomes.html.twig
    plot.html.twig
  default.html.twig

The sections Entry URL Format is as follows:

developments/{counties.first.slug}/{developments.first.slug}/available-homes

and nested entries get the following:

{parent.uri}/{slug}

If I change the template from entry in the control panel to different template then it loads.

This is the entry template code:

{% include [
  "entry/" ~ entry.section.handle ~ "/" ~ entry.type,
  "entry/default"
] %}

Can someone help please?

I'm guessing staging has a case sensitive file system and your local dev site doesn't.

i.e. the section handle in your screenshot is called availableHomes, but the template folder you're referencing is availablehomes.


How do I query for orders that were completed between two dates? I am attempting to get orders that were completed between two dates and the "before" and "after" criteria parameters don't seem to work. Perhaps I am using the wrong syntax? Example of how I am using them:

.after('2017-06-02 00:00:00')

It looks like I figured it out by doing this:

.dateOrdered('and', '>=' ~ startDate, '<=' ~ endDate)


Public url for assets when logged-in I'm creating a website where I want users to be able to login. I'm using https://craftcms.com/docs/templating/login-form to achieve this. No problem so far.

When a user is logged in, I want the user to be able to reach the asset folder (depending on what the rights are for his user-group). When not logged in, I want the asset url to be private.
For this to work I've placed the asset folder outside the webroot, so you can't access the asset folder by default.

I've tried to achieve this with this plugin: https://github.com/tikiatua/internal-assets-plugin
But without any success.

My general config:

'enableTemplateCaching' => false,
    'devMode' => true,
    'siteUrl' => 'http://website.loc/',
    'loginPath' => 'http://website.loc/',
    'environmentVariables' => array(
        'internalAssetsPath' => CRAFT_BASE_PATH . "../media/",
        'internalAssetsUrl' => "http://website.loc/media/"
    )

I can upload a image in my internalAssetsPath, but when I try to show this in front-end, I get a 404.

{% for image in craft.assets.kind('image') %}

{% endfor %}

A solution for the 404 problem would be nice, but a solution for reaching the asset folder when logged in would be great.

Give Digital Download a try... it generates a masked URL for downloadable assets. You can restrict the download to a specific user or user group.

Disclaimer: I'm the plugin author.


User groups in relation to categories I am building a community website that currently have two user groups but it might increase so I am trying to automate everything. The current groups are: 'teachers' & 'candidates'.

I have a channel section named 'Community' and for this channel I have setup a category group called 'Community' that has two categories named as the user groups: 'teachers' & 'candidates'.

I am trying to display a list of all the registered users in a specific group as you are loading the category template.

This is the template that is being loaded:

{% extends "community/index" %}

{% set title = category.title %}

{% block main %}

{{ category.title }}

    {% set group = craft.users.group('{{ category.slug }}') %}

    {% for user in group %}

{{ user.name }}

    {% endfor %}

{% endblock %}

I was thinking that since the {{ category.slug }} has the same name as the user group, it can work but apparently not...

Can someone help me to understand how to relate the two?

I believe your problem lies in the parameter for user group. In Twig, you don't need the brackets if you're already in brackets. You just reference the variable and fields directly. So instead of:

{% set group = craft.users.group('{{ category.slug }}') %}

Try this:

{% set group = craft.users.group(category.slug) %}

You see, the ElementCriteriaModel that's parsing the parameter for group doesn't run all its function arguments through Twig. So you're confusing it by throwing braces in there. Just give it the variable and field without quotes or braces and it should work smashingly, provided that category.slug is the same as a group slug.


Moving site to subdomain I am moving our current site to a subdomain and get this: "Craft CMS requires the PHP multibyte string extension in order to run."

I have updated the $craftPath variable and System->General->SiteUrl CP setting to the updated URL.

Am I missing something?

I'm guessing the site you're setting up on the subdomain is on a new server?

  Craft CMS requires the PHP multibyte string extension in order to run.

That error means that the PHP multibyte extension isn't installed or enabled on your server and both Craft 2 and Craft 3 require it.


Upload file issue on Craft 2.9.2 This issue is occurring on Craft 2.9.2.
The assets are stored on Amazon AWS (S3).
When I try to uploaded a new asset (of any size, even very small), the progress bar moves to 100% position but remains on the screen, and the loader sprite in top right corner keeps going around. The same symptoms are described here. The post was of no help. There was an answer in that post, which links to here. Which was also of no help, as the suggested nginx.conf setting is already in place, and the php settings are more than adequate.
Nothing shows up in the craft error log.
Nothing shows up in the server (php) error log.
Can anyone suggest how I might go about troubleshooting this, or suggestions as to what the cause might be?

I figured out this issue was caused by a permissions issue on Amazon AWS.
The site was not able to write to the S3 bucket, due to AWS blocking public access to the bucket, which was over-riding the policy I'd applied to the bucket.


Subdomain database configuration picking up root domain config So I have this example database config setup

$customDbConfig = array(

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

    'test1.foo.com' => array(
        'server' => 'localhost',
        'user' => 'test1user',
        'password' => '',
        'database' => '',
    ),

    'test2.foo.com' => array(
        'server' => 'localhost',
        'user' => 'test2user',
        'password' => '',
        'database' => '',
    ),

    'foo.com' => array(
        'server' => 'localhost',
        'user' => 'produser',
        'password' => '',
        'database' => '',
    ),

);

It appears that when accessing test1.foo.com, the foo.com environment is being loaded.

Looking at the docs again

  When Craft is comparing your config keys with $_SERVER['SERVER_NAME'],
  it’s only looking for a partial match. So the environment key
  'example.com' will also work if you’re accessing your site via
  www.example.com or any other subdomain. You could even just use the
  TLD if you’re feeling adventurous:

What's the best way to get around this issue, where we want subdomains for dev and test, when they are subdomains of the production domain.

Thanks.

As long as you have the more specific one at the top of your array like you do, it should work.

It looks like your using some custom (non-stock) Craft config logic judging from the $customDbConfig variable.

What happens if you echo $_SERVER['SERVER_NAME']; from the test1.foo.com domain?

If it's an exact match and it is still not selecting the right database, then I'd suspect your custom logic.

Strip all of that out to just Craft's default multi-environment config and see if it works that way.


How can I get tasks to complete when not logged in to the CP? I've noticed that tasks only run when logged into the admin panel, is there anyway to avoid this?

For some context: I have jobs scheduled on a cron to run every 30 minutes, when I log in it seems that all of the items get queued up from the last time I logged in and proceed to run, this isn't terrible - but this app won't be seeing much login activity down the road.

`public function execute($queue)
{
    $section = Craft::$app->sections->getSectionByHandle('orders');
    $entryTypes = $section->getEntryTypes();
    $entryType = reset($entryTypes);

// Create an entry
    $entry = new Entry([
        'sectionId' => $section->id,
        'typeId' => $entryType->id,
        'fieldLayoutId' => $entryType->fieldLayoutId,
        'authorId' => 1,
        'title' => 'Order Number: ' . $this->orderId,
        'slug' => $this->orderId,
        'postDate' => new DateTime(),
    ]);

    $entry->setFieldValues([
        'orderId' => $this->orderId,
        'lineItemMatrix' => $this->lineItemMatrix,
        'couponMatrix' => $this->couponMatrix,
        'amountPayable' => $this->amountPayable,
        'orderTotal' => $this->orderTotal,
        'tax' => $this->tax,
        'sellerDiscount' => $this->sellerDiscount,
        'shipping' => $this->shipping
    ]);
    //check to see if entry exists.
    $existing = Entry::find()->section('orders')->slug($entry->slug)->one();

    if (is_null($existing)){
        return Craft::$app->elements->saveElement($entry);
    } else {
       // don't do anything;
        return false;
    }
}`

To reiterate what has been said in the comments above and to present an answer, the best way to ensure that queue jobs are completed even without the CMS being logged into or the site being visited is using a scheduled cron job.

The following will run all jobs in the queue every 10 minutes:

*/10 * * * * /usr/bin/php /path/to/craft queue/run


Output Radio or Checkboxes with A+M Forms Does anyone know how to output a checkbox or Radio Button Group with A+M Forms using the custom HTML option?  I'm assuming it's some kind of loop through the available options?

My static HTML looks like below and i'd like to retain the structure if possible.

Many thanks

  Choose your class type

<input type="checkbox" value="personal" tabindex="4">One to One Class

<input type="checkbox" value="business" tabindex="5">Business Class

<input type="checkbox" value="smallgroup" tabindex="6">Small Group

I'm confused by what you mean by "output". Do you mean: how do you write custom HTML for checkboxes or radio buttons and have them submit to amforms?

If that's the case, you need to understand the name attribute always needs a fields[] array. StraightUpCraft has a great rundown of how all field types' name attributes should be formatted in order to submit to Craft, no matter if you're using amforms, Sprout, or whatever.

Radio Buttons

Radio buttons are a "single option field", meaning that when the form submits, only one value goes through. Your code should look like this (I stripped out some of the unnecessary markup):

<label>Choose an option
    <input type="radio" name="fields[fieldHandle]" value="Option 1"> Option 1
    <input type="radio" name="fields[fieldHandle]" value="Option 2"> Option 2
    <input type="radio" name="fields[fieldHandle]" value="Option 3"> Option 3
</label>

Checkboxes

Checkboxes are "multi option fields", meaning that when the form submits, any number of values can go through, so you need to submit them a bit differently:

<label>Choose your class type
    <input type="hidden" name="fields[fieldHandle]" value="">
    <input type="checkbox" name="fields[fieldHandle][]" value="Option 1"> Option 1
    <input type="checkbox" name="fields[fieldHandle][]" value="Option 2"> Option 2
    <input type="checkbox" name="fields[fieldHandle][]" value="Option 3"> Option 3
</label>

Pay close attention to each input having an extra [] at the end and the hidden input that collects all their values into a final array.

One very important note

You absolutely need to make sure the values of each input you have in the HTML equal the values you created in the CMS when you created the field. This includes capitalization and spaces.  So if your checkbox field in the CMS, for example, had a handle of breakfast, and each option's Label/Value was set like

French Toast | French Toast
Ham n' Eggs  | ham-n-eggs
Corn Flakes  | c0rnFlaaaake$$

then your input values need to match exactly:

<label>Breakfast Options:
    <input type="hidden" name="fields[breakfast]" value="">
    <input type="checkbox" name="fields[breakfast][]" value="French Toast"> Option 1 (this text can be anything)
    <input type="checkbox" name="fields[breakfast][]" value="ham-n-eggs"> Option 2
    <input type="checkbox" name="fields[breakfast][]" value="c0rnFlaaaake$$"> Option 3
</label>

Craft's expecting these to line up, and if they don't, then either these fields' values will be ignored on submit or, if the field is set to required in the CMS, you'll get a back-end validation error.