get entries randomly every minutes? I want to get entries randomly every minutes like setTimeout in javascript. Like below If possible.

            setTimeout({ {% for entry in craft.entries.section('alumni').order('RAND()').limit(6).find() %}

                    {% set asset = entry.profileImage.first() %} {% if asset | length %}

                    {% else %}

                    {% endif %}

                                {{ entry.title }} {{ entry.lastName }}

                        {{entry.graduateYear}}

            {% endfor %} }, 1000);

See below for some twig code to get you started, I omitted the actual HTML output for the individual items to better keep the overview.

Whats happening is, you get all (or a reasonable big amount amount) of your entries, and start looping over them.

The first time, you open a div that will contain 6 items. Afterwards, each time the loop index can be divised by 6 (aka, 6 more items have been looped over) you close the container div & open a new one.

Than finally after the last iteration, you close the container div again.

Making the 6 items hide or display you can do with Javascript. Let me know if you need extra pointers on that.

{% for entry in craft.entries.section('alumni').order('RAND()')}
    {% if loop.first %}

    {% endif %}

    {# Build item output here #}

    {% if loop.index is divisible by(6) %}

    {% endif %}

    {% if loop.last %}

    {% endif %}
{% endfor %}

Info on divisible by


How do I set this up the right way, transferring from Wordpress as CMS? I'm trying to do something I'm used to in Wordpress, but can't really find a right way, or 'correct' way. What I was used to do in Wordpress; every page had a few options, like center content, background image, etc. In page.php (if you know Wordpses this'll make sense) I called a function pageDetails() (defined in functions.php) which returned me some variables for centering content, if it had a background image, etc.

Now I'm trying to do the same in Craft, so I created a section for the pages, added some custom fields to the pages, and now I'm trying to create a likewise method for defining a function once and use that for different 'entry types' to avoid repeating myself for each entry type template. For this, I keep coming back to creating a macro, that I define in _macros/macro.twig (for example). But, I can't get it to return variables.

In short; is there a way to use 'variables' from entry template, to the macro, and have the macro return vars (or array) to the entry template so I can use them in there? Or should I completely rethink this way of doing it?

Macros are intended to output to the page, rather than return data to the caller. If you must return the data, I'd suggest writing a custom plugin (although that's where my knowledge stops!).


Paginate based on date-based starting points I'm working on creating a simple calendar based on only native Craft fields. While coding this, I'm having a hard time getting the pagination to work properly.

The calendar currently lists all upcoming events this current month. Next/Previous should then paginate the calendar 1 full month forward/backward (not 1 month backwards from todays date, but all entries in the next/previous month).

According to Brandon, paginate.prevUrl/nextUrl won't map to specific date-based starting points. So, how do I tackle this problem then?

Here's my current code:

Hva skjer i Filadelfia

            {% set startDateTime = now|date_modify('0:00')|date('c') %}
            {% set endDateTime = now|date_modify('first day of next month 4:00')|date('c') %}

            {% set startDateParam = 'and, >= ' ~ startDateTime ~ ', < ' ~ endDateTime %}

            {% set events = craft.entries.section('calendar').limit('15').startDate(startDateParam).order('startDate asc') %}

{% for event in events %}

{{ event.startDate | date("d") }}.

{{ event.startDate | date("M") }}

{{ event.title }}

{{ event.body | hacksaw(words='75', allow='') }}

{{ event.startDate | date("H:i") }}

{% endfor %}

{% paginate craft.entries.section('calendar').limit(15) as pageEvents %}
    {% for month, entries in pageEvents | group("postDate | date('F')") %}

            {% if paginate.prevUrl %}Previous Month{% endif %}
            {% if paginate.nextUrl %}Next Month{% endif %}

    {% endfor %}
{% endpaginate %}

Instead of using pagination you might want to look into setting up a dynamic route in the format "calendar/[year]/[month]". Adding 'year' and 'month' tags to your route will essentially pass those values as named variables to your template, which you can use to retrieve and display entries, as well as generate navigation to next/previous month's events. If you want the uri '/calendar' (without the 'year/month' uri segments) to link to the current months events you can test for the existence of the 'year' and 'month' variables, and if not defined, set the start month to the first day of the current month.

{% if year is defined and month is defined %}
    {% set startMonth = year ~ '-' ~ month ~ '-' ~ 1 %}
{% else %}
    {% set startMonth = now|date_modify("first day of this month") %}
{% endif %}
{% set nextMonth = startMonth|date_modify('+1 month')) %}
{% set previousMonth = startMonth|date_modify('-1 month')) %}

{% set entries = craft.entries.section('calendar').postDate('and', '>= ' ~ startMonth, '< ' ~ nextMonth %}

{% for entry in entries %}
    {{ entry.title }}
    ...
{% endfor %}

    next month
    previous month

If required, within any month you could also use a pagination tag if you needed to limit the number of events displayed on any one page to 15.

For additional examples see these answers, here and here.


Problem with scope in macro I've written a short macro to get the first image inside a matrix field.

{% macro firstImage(entry) %}

    {% set image = 'hello' %}

    {% if entry.sliderMatrix.total() %}
        {% set block = entry.sliderMatrix|first %}
        {% set image = block.image|first %}
    {% endif %}

    {{ image.url }}

{% endmacro %}

The code throws this error: Impossible to access an attribute ("url") on a string variable ("hello")

{{ image.url }} inside the if statement works fine.

{{ image }} outside the if statement works too.

Is there anything I don't know or it's even a bug?

Hard to say for sure, but here's what I suspect... You may have multiple instances of firstImage being called from your main template.

For some of those instances, entry.sliderMatrix.total is greater than zero. For other instances, entry.sliderMatrix.total is equal to zero. And of course, when entry.sliderMatrix.total is equal to zero, your if statement will be bypassed.

Realistically, you shouldn't have the image.url call outside of your if statement. Because any time the if statement evaluates to false, then the image variable won't be what you want it to be. In fact, you'll get that exact error, since image will still be set to a string.


onBeforeSaveEntry is hanging on import I am using the Import plugin. This question doesn't have to do with the Import plugin which seems to be working swell, but instead with my onBeforeSaveEntry logic which seems to have botched the import process.

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

    craft()->on('entries.onBeforeSaveEntry', function(Event $event)
    {

        if($params['isNewEntry']) {

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

            $criteria = craft()->elements->getCriteria(ElementType::User);
            $criteria->groupId = 1;
            $criteria->AffiliateId = $entry['AffiliateId'];
            $criteria->limit = 1;
            $users = $criteria->find();

            if (!empty($users)) {
                $assignedCoach = $users[0]->id;
                $entry->authorId = $assignedCoach;
                $entry->getContent()->coachId = $assignedCoach;
            }
        }
    });

}

What am I doing wrong here? Also, any idea how I kill the import processes which seem to be hung at the moment?

Your script probably chokes because you're interacting with an undeclared variable $params – i.e. change

if($params['isNewEntry']) {

to

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


Paginate entries with offset / limit when templating I've got the pagination function working nicely for a simple for loop of news entries. However I want to split the template up into the first 2 entries as featured items then the next 6 as smaller items. As I paginate through the entries I'd like to keep that layout, however it seems that I cannot use paginatedEntries.limit(2) or paginatedEntries.limit(6).offset(2). Is there another way of doing this?

{% paginate craft.entries.section('news').limit(8) as paginatedEntries %}

News

        {% for entry in paginatedEntries.limit(2) %}
            {# Show first 2 entries #}
        {% endfor %}

        {% set tagentries = craft.entries.section('news').limit(null) %}
        {% if craft.tags.relatedTo(tagentries)|length %}
            {% import "_macros/_news.twig" as news %}
            {{ news.tags(tagentries, 'News', 'news') }}
        {% endif %}

Search in News

            {% import "_macros/_search.twig" as searchForm %}
            {{ searchForm.simple('news') }}

        {% import "_macros/_util.twig" as util %}
        {% if currentUser %}
            {{ util.link('/member-news', 'Browse Member News Articles') }}
        {% endif %}

    {# 6 entries as grid #}

        {% for entry in paginatedEntries.offset(2) %}
                {# Show next 6 articles #}
        {% endfor %}

        {% if paginate.prevUrl %}Previous Page{% endif %}
        {% if paginate.nextUrl %}Next Page{% endif %}
{% endpaginate %}

As soon as I remove .offset(2) or .limit(2) the code functions correctly without errors.

You could use Twig's Slice function.

{% set firstTwo = paginatedEntries|slice(0,2) %}
{% set lastFour = paginatedEntries|slice(2,4) %}

Then loop over firstTwo for your first items.

{% for entry in firtTwo %}
   {# Show first 2 entries #}
{% endfor %}

Loop over lastFour for your final items.

{% for entry in lastFour %}
   {# Show next 6 articles #}
{% endfor %}


Search Assets in Matrix fields, if they appear in a Section I want to run a search on Assets that are in use within a particular section. The Assets are added to entries via a Matrix field.

The search term is provided via a url parameter:

{% set searchTerm = craft.request.getParam('q') %}

Somewhat optimistically I tried this:

{% set imagesInUse = craft.assets.relatedTo({
  targetElement: craft.entries({
    section : 'agency'
  }),
  field : imageList.keyImage
}) %}

Where imageList is the Matrix field and keyImage is the Assets field. The block name is imageSpread.

This apparently returns nothing.

For the search part, I'm trying to search within 'imagesInUse':

{% for image in imagesInUse.search('*' ~ searchTerm ~ '*').order('score') %} ... {% endfor %}

It looks like a relatively complex query might be required, but I'm not sure where to go from here.

Managed to make this work, corrected a couple of things and tidied up, but the main issue was realising the field param has to be a string (duh), not a variable. My code now looks like this:

{% set entries = craft.entries.type('artistFolio').limit(null) %}

{% set imagesInUse = craft.assets.relatedTo({
    sourceElement: entries,
    field: 'imageList'
}) %}

This gives me a model with all images appearing inside the Matrix field 'imageList' within the entry type 'artistFolio'. I can then search these as so:

{% set searchTerm = craft.request.getParam('q') %}
{% set results = imagesInUse.search('*' ~ searchTerm ~ '*').order('score') %}

{% for image in results %}
    ...
{ % endfor %}


Assets metadata: Matrix required? I'd like to add very basic metadata to assets (Alttext, Caption..)

I noticed in volumes you can add custom field types – but they're not appearing when editing the entry. I found it can be edited in the assets view, but that's too complicated for editors.

If those values should be editable in the entry – should the matrix field type be used?

You could go for a lightweight content-builder. That would mean that you could and would create a matrix blocktype for each of your content elements i.e. one blocktype for image with all the metadata you could chew on as fields, another for say body with some props too and so forth.

That would also give your users some neat control over the document flow.

Then you would saw it seamlessly together on the template layer. Your Content-Editors will not feel a thing.


Best practices for plugin service/controller/etc file names When it comes to naming files within a plugin - is it preferable to follow PluginHandle_SomeController, or stuff everything inside a single PluginHandleController file?

This is probably a subjective question for the most part - but in building out a plugin at the moment, I have 4 different Service files, and I'm not sure if I'm being too pragmatic by breaking each different service type out individually, or if I should just include it within the single file. Each service isn't complex, they're basically a function or two each, but cover different aspects of the plugins feature set.

Any benefit to one way or the other?

At the end of the day, it all comes down to personal preference. Depending on how large and/or complex each of your Service files is, it may make sense to break them up into separate files. Or if you've got less than a dozen service methods total, you could easily combine them into a single service file (if you choose).

For me personally, I try to break it up by where those service methods are being called from. MyPlugin_VariableService and MyPlugin_ControllerService for example... and any methods that are shared would go in the "main" MyPluginService file.

But every developer (and project) is different. You may have some other method of organizing that's better suited to you. So mostly personal preference.

However, the one thing I would definitely suggest... If you build any service methods which you'd like to be triggered from other plugins, then you may want to put those in your main service file. So the other plugins could simply call it like this:

craft->myPlugin->myMethod();

As far as an API for your plugin goes, it's much cleaner. Similarly, for any Controller actions which submit through a front-end form, you may want to have those submit through the "main" controller:

<input type="hidden" name="action" value="myPlugin/myAction">

Lastly, the same thinking applies to your main Variable file:

{{ craft.myPlugin.myVariable }}

Just makes for a cleaner interface for end-users and other devs. :)


404 when clicking on the Disqus embed urls I've just noticed on a site that the Disqus comment embed is suggesting other articles but they're adding a token to the end of the URL, for example:

http://australia.thegospelcoalition.org/article/blessed-to-be-rich-a-biblical-theology-of-blessing?token=_g6RQbb8oD9~uxEUu8u6~c9875m17~jo

But this returns a 404 in Craft. Works fine without that query string.

Any ideas to resolve?

Not sure why they add this param for you; on my own weblog all the suggested links are without ?token. Maybe you previewed that page and had the Disqus embed showing for the preview as well? Best not to include it for previews and older versions.

Anyway, as explained above by default Craft also uses the 'token' param to preview previous versions of the page. That's probably why it's not working now; this token has expired so Craft can't find any version of that page using the requested token anymore and displays a 404 page instead.

The fix is relatively easy: just change the 'tokenParam' config setting to something else:

Craft v2 - https://docs.craftcms.com/v2/config-settings.html#tokenparam

Craft v3 - https://docs.craftcms.com/v3/config/config-settings.html#tokenparam

Then Craft will just ignore it and show the correct page. Just don't forget to also hide the embed for previews otherwise you will get exactly the same problem soon with the new token param.

Edit

Something like this should work to prevent this in the future:

{% if not craft.request.isLivePreview() and not craft.request.getParam( craft.config.get('tokenParam') ) %}
    ... embed code here ..
{% endif %}


How to write query with startdate = now? I'm trying to make a query which has 2 conditions who has to be true both. In PHP I should use && to get this. startdate <= now && enddate >= now. How do I write this in Craft twig?
Tnx in advance!

{% set current = craft.entries.find({
    section:'exhibitions',
    startdate : "<= " ~ now.w3c(),
    enddate : ">= " ~ now.w3c(),
    order:'startdate'})
%}

{% if current|length %}
    Current exhibitions
    {% for exhibition in current %}
        {{ exhibition.title }}
    {% endfor %}
{% endif %}

ElementCriteriaModel parameters always add up to further filter down the results, which means an element has to be truthy for each one of them to be returned.

So your params basically look right for what you're trying to achieve. The only thing that might mess with the results is the for me unusual use of the w3c methods on the DateTime objects, which might output in a format not supportet by the criteria model.

Try one of the following variants instead:

"<= " ~ now.iso8601()
"<= " ~ now|date('c')
"<= " ~ now|date('U')

If you're not interested in ouputting the time, you could also just use:

"<= " ~ now

which outputs the same as "<= " ~ now|date('Y-m-d').


Allow Author to Build Multiple Choice Question? I'd like to allow authors to add a multiple choice question to an entry.

To build the possible answers, they will create answers and mark one as the correct answer. I could then output these as radio boxes on the frontend and allow website users to choose one and get 'marked'.

Since there is only a single question (with multiple answers) per entry, I'd like to avoid using a form plugin (such as Sprout Forms, which may be able to support this).

Anything I've tried did not have the ability to mark one and only one answer as Correct. I first built a table with 'Answer' (plain text) and 'Correct?' (lightswitch) fields in each row; this allowed choosing multiple answers as Correct. I then turned it into a SuperTable and made the 'Correct?' field radio buttons...but could not get all the rows in the table to be a single set of radio buttons such that you could only choose one.

Any ideas? Creative ways of building this differently are welcome. Thanks in advance.

There isn't a field type or plugin I know of that will let an admin choose only 1 correct answer.

One possibility would be to number the correct answer in another field like piotrpog suggests. I would argue this is possibly more confusing and brittle since an admin could accidentally update the answer choices without updating the correct answer field. The two fields aren't linked automatically.

I think it's pretty reasonable to ask admin's to only mark one choice as correct. You could also reinforce this in the field instructions. The lightswitch field makes it pretty easy to scan the column to make sure.


User mysteriously deleted User's account has mysteriously vanished and entries default to another user. This has happened multiple times. Not sure what to do so we can not have this happen again. Any help is warranted.

Thanks!

When a user is deleted from the system via the Craft control panel, they are presented with a model offering them the choice of what they want to do with that user's content.

The options are to 1) transfer it to a different user (which you can select) or 2) delete it entirely.

So the behavior you're describing certainly sounds like someone went through the UI to delete a user and transfer their content.

You might want to consider installing something like the Audit Log plugin to catch the borderline criminal.

The only other time we've seen a user and their content get deleted is from a more convoluted process where a Craft install has users in a "pending" state and they've never authenticated their accounts and they start assigning content to that account (via a custom plugin or some such).  They also have the purgePendingUserDuration config setting set to something other than false (say 1 month), then once the user account has been "pending" for a month, they get deleted along with all of their content.

But it doesn't sound like that's what is happening for you.


migrating from Linux to Windows, but my templates aren't loading Hello I am migrating our craft install from a Linux server to a Windows IIS based server.

So far all is working, however the default template is not loading. Any idea why?

Linux: http:// 70 .32 .84 .65/home
Windows: https://brownbis.com/primer/home

Is there a PHP module on Windows that I need to enable?

Thank you very much for your help

It looks like your craft/templates folder on the Windows box has the default template that Craft ships out-of-the-box with and not the custom templates and front-end resources that you've designed.

Make sure your correct files are actually in craft/templates.


How do I use a Dropdown 'Entries' Field Type in a Front End Form I have an Entries field that I need to have as a drop-down field in my front-end form. The code below is displaying the correct options, although after selecting and submitting the form, the tbdDesignerUrl-field is not populated with the selection in the entry.
It shows as nothing selected. (tbdDesignerUrl is the name of the Entires field I am trying to populate through the form and entry.designerUrl is the field I am using to select the entry in the options.)

{% set entries = craft.entries.section('designers') %}
  <select name="fields[tbdDesignerUrl]" id="fields[tbdDesignerUrl]">
    {% for entry in entries %}
     <option value="{{ entry.designerUrl }}">{{ entry.designerUrl }}</option>
    {% endfor %}
  </select>

Thanks for any help you can give! :)

Simply put, an Entries field is an array containing entry ids, and your form needs to send it that way.

Just replace name="fields[tbdDesignerUrl]" with name="fields[tbdDesignerUrl][]". That way the value gets submitted as an array.

Also replace value="{{ entry.designerUrl }}" with value="{{ entry.id }}", since we need the submitted value to be an entry id.


Image transforms not working properly I have 2 basic JSON files, the only difference between the files is the product.type('')

In my general.php I have turned on 'generateTransformsBeforePageLoad' => true,

The first JSON file (200 products ) loads within 2 second and the image is like this:

http:\/\/mysite.dev\/files\/coins\/_transform\/1763-myImage.jpg

The second file (30 products) takes 10+ seconds to load, and displays the image like this:

http:\/\/mysite.dev\/cpresources\/404?x=CjvOQxsnA

I am using the same image transform for both files.
Why is it that the image in the second file isn't saved, because of this it takes 10+ seconds for the file to load.

I am using the same exact code for generating the transforms so I don't know why this is happening.

If I remember correctly, you will see urls similar to this http:\/\/mysite.dev\/cpresources\/404?x=CjvOQxsnA if you have generateTransformsBeforePageLoad as false.

It could genuinely be the case that the original file is not there so it's 404ing (as the link suggests it is).
If you are running multi-environments, have you got all the assets on your locale env?

Maybe try clear your cache, or, your storage/runtime folder if you have all the assets and try again?


Adding new matrix block will result in wrong locale I have matrix fields where I dont have translation on the whole matrix, but only on the fields within a certain block. Nothing complicated or fancy. When I add a new matrix block in the admin, it will result in a locale that is not the same as the one I'm editing at the moment: I have two locales installed (sv and en). Everything works fine. But its just that when I'm editing the swedish (sv) entries I can see that the locale-indicator next to the matrix text-field says "en". But when I edit the swedish locale, I want to start adding text in the locale that I'm editing at the moment.

I'm using Craft Pro 2.4.2668

Above is a screenshot from the admin, with the locale-indicator (screenshot taken right after klicking the "+ Menu item"-button

This is a UI bug when saving a new Matrix block in an new entry.

If you save, the data is saved into the correct locale and the fields in Matrix blocks will display their correct locales (in your case sv).


Apply updates automatically when available Is it possible to automatically apply Craft CMS updates when they become available?

At the moment, I have to go into the CPanel and apply updates with the one-click option.

Maybe I can do this with a cron job?

It's typically bad practice to allow auto-updates -- at least in a production environment.

That being said, to update Craft, you're required to download the new files (click "Download" on the update page and it gives you a zip file), and then replace them in your codebase. So right now, no you wouldn't be able to do this with a Cron Job.

Craft 3 may be a different story, though.


Restricting access to user groups with Control Panel access only I know I can restrict template output to Admins only with :

{% if currentUser.admin ?? false %}

…and to any logged in user with:

{% if currentUser ?? false %}

And I’m aware of accessCp as a permissions handle.

Can I use that, or similar, to restrict template output to any user group that is allowed to access the CP – without having to cycle through specific user groups in the template?

I tried:

{% if currentUser.accessCp ?? false %}

…but that doesn't work.

I'm using Craft 3.1.29.

I’ve figured out what I was missing. I needed to use can:

{% if currentUser.can('accessCp') ?? false %}

:)


Error when submitting Date Field from the front-end: cannot be blank Am using the Pikaday datepicker to add a Date field to the front-end of a Craft site: https://github.com/dbushell/Pikaday

This is for integration with the Formerly add-on and the date is set to required.

When I try to submit the form I get the following error:

2016/02/03 12:23:54 [warning] [application] Craft\ContentModel->dateTest_testDate failed validation: Test Date cannot be blank.

Are date inputs submitted via the front-end required in a particular format?

also experiencing same problem with Sprout Forms

The input tag presented in the comments above does not appear to use the correct input tag format for the date field. To submit a date field on the front-end, your input fields need to be setup with the following name structure and value format:

<input type="text" size="10" name="fields[fieldHandle][date]" value="10/15/2012">
<input type="text" size="10" name="fields[fieldHandle][time]" value="6:12 PM">

Using your example field handle of child1DateOfBirth this would be:

<input type="text" size="10" name="fields[child1DateOfBirth][date]" value="10/15/2012">
<input type="text" size="10" name="fields[child1DateOfBirth][time]" value="6:12 PM">

To submit any field on the front-end of Craft requires that you use the right format for the input field you are submitting.  Assuming the field submits just fine from within Craft, one way to track down the format you need on the front-end is to use your browser's developer tools and look at the input tags for the respective field in the Craft control panel.

The Craft CMS Field Guide on Straight Up Craft is another resource that gives examples of all the different native Craft fields and examples of input fields for the front-end.

If things currently aren't working, consider trying to hard code these values and confirm that this works at all.  You'll then need to figure out how to get the respective datepicker you are using to format the selected data into the proper input format as described above.

I don't believe this is an issue with any specific form plugin being used.  In the case you wanted to use a dynamic date field with your form (instead of manually creating your form as you describe above), you could extend Sprout Forms and add support for a custom front-end field.


Write to Craft via Element API I’d like to use Craft as a headless CMS for my mobile app (via the Element API plugin). However, in addition to reading data, I’d also like to write data back to Craft.

It looks like this is typically done using an Entry Form on the front-end. Is writing to Craft possible without using Craft’s front-end though (e.g. native inputs in the app that send data via the API instead of a web view with an entry form)? If not, could this be accomplished by forking the Element API and adding that functionality somehow?

I'd caution against trying to adapt the ElementAPI plugin for this purpose, as it was designed to be read-only—it's basically a wrapper around Craft's ElementQuery interface, which does not handle write operations.

In lieu of that, you might take a look at the CraftQL plugin, by Mark Huot. It supports sophisticated queries (reading), as well as mutations (writing).

Otherwise, if the scope of the content you need to update is relatively narrow (i.e. you know what section and fields you need to use), I'd recommend reading through the plugin docs, and determining whether it's something you could build on your own, with a simple Controller and supporting Service(s)!


Filter entry query by a custom field value I have a channel, 'pages'. Within that channel is a dropdown 'navigation'. The values in the dropdown are 'mainNavigation' and 'hidden'.
I'm trying to set an entry query that only pulls entries where the navigation value is 'mainNavigation'.
This is the code I'm using, and I'm getting no results:
{% set nav = craft.entries.section('pages').search('navigation:"mainNavigation"').all() %}
{% for link in nav %}
    {{link.title}}
{% endfor %}

I know this should work. I've done it before. I copied the working code from another site, and copied the field name and value directly from the CP. I've stripped everything else out of the template. But no matter what I do, I get no results.
Has this functionality changed recently?

Your code should work. Make sure that your Settings → Fields → Navigation has Use this field’s values as search keywords checked.
Once you're sure it is checked, run ./craft resave/entries --update-search-index and it should start working.
Note that instead of searching, you could use:
{% set nav = craft.entries()
    .section('pages')
    .navigation('mainNavigation')
    .all() %}


{{siteUrl}} not working on load I am using {{ siteUrl }} for absolute links. It works 95% of the time. But if I press the reload button multiple times in a few seconds (overloading or something) my links look like this:

href="$DEFAULT_SITE_URL/css/order.css"

instead of

href="http://localhost/craft/web/css/order.css"

other Twig commands are working fine at the same time. What's happening?

Try using {{ currentSite.baseUrl }}

I had the same issue when I started using environment variables instead of @web for my sites. I've found the above works for all cases.


Multiple URL Formats per element type (Entries, Categories) I suspect this boils down to a feature request, but I'll start here in case there are any other ideas.

Basically, I want to be able to define multiple URL formats for a single section or category group.

Here is the scenario:

Section gear with URL format gear/{slug}
Category group productTypes with URL format gear/{slug}, {parent.uri}/{slug}
Section reviews with URL format reviews/{slug}.

What I want to do but can't, is define a second URL format for productTypes, with the format reviews/{slug}, and {parent.uri}/{slug}.

Similarly, I want to define a 2nd format for gear, of reviews/{slug}.

So I'd end up with:

gear/gear-entry/
gear/category/
reviews/category/
reviews/gear-entry/
reviews/review-entry/

So I really need Craft to know about those additional formats to avoid crossover URLs.

Routing and assigning the entry and category variables is not a problem, I'm really just concerned with the slug/uri validation.

So semantically, I don’t love the URL format you’re coming up with.  I’d like to see something like /gear/{category}/{entry}

This gives you a few benefits

it’s semantically readable…
it gives you natural breadcrumbs for the hierarchy of content
it’s likely going to be better from an SEO perspective

Relevant feature request: https://github.com/craftcms/cms/issues/1189


Plugin does not exist on 404 page? Before I go into detail and share my error logs and plugin details, I'll ask the simple question first:

When testing my 404 page, no plugin functionality works. Is this intentional?

Just for testing purposes, I tried to include the index template file in my 404 template:

{% include 'index' %}

This pulls in the homepage fine, but still causes an error:

  Variable "pluginName" does not exist in "404"...

The following returns 'yes' when legitmately on the homepage, and 'no' when on a 404 page, which uses the include I just mentioned.

{{ pluginName is defined ? 'yes' : 'no'}}

Any insight would be great.

Mark

Ok, this is what I get for trying to be clever (lazy)...

I've always begrudged typing in 'craft.myPlugin...' every time I wanted refer to my plugin, so I set a Route Variable in my plugin like so:

  craft()->urlManager->setRouteVariables(
    array(
      'myPlugin' => craft()->myPlugin,
    )
  );

It would appear none of my route variables work in the 404 template. That in itself is a bit odd, so to accomodate my laziness I've added this to the top of my 404 code:

{% set myPlugin = craft.myPlugin %}

It would be interesting to know if this choice has any detrimental effects? (besides being looked down upon by my peers)


Issue with tags possibly corrupt Is there a way to delete specific tags from the db? I have one tag that does not seem to work. I have used the following code to see all tags used from a specific section, knowing I have entries using a tag called Logos

{% set test = craft.entries.section('projects').limit(null) %}

    {% for tag in craft.tags.relatedTo(test) %}

{{ tag.title }}

    {% endfor %}

This outputs a list of all tags used in the section called projects, Logos is not listed.

I have a sidebar that outputs each tag a single entry was assigned. Logos is output when viewing an entry that was tagged with Logos. Clicking on the Logos link loads a page that should list all entries that use Logos etc but for this specific tag it doesn't find any entries. I have a feeling this tag is corrupt somehow in the db as this was working fine a while back.

I noticed someone had duplicated this tag... if I start typing Logos in the Add a tag when editing an entry I see four results Logo, Logo, logos, Logos.

Neither logos, or Logos returns entries. And only one of the Logo returns entries.

I then decided to add all of those Logo, Logo, logos, Logos. And renamed the three that didn't work to blank. This then causes the tag to display as "Tag 686" etc. Clicking the tag then loads all of the entries using that tag. So for some reason it just doesn't seem to like the tag being named Logos...

Anyone have any ideas on what could be going on here?

So this seems like a bug to me. I found the issue, and it was caused by another tag group having the same tag name. Here is an example

We have three tag groups.

Default
Industry Tags
Services Tags

Logos was a tag in Default, and also Services Tag group. Once I removed or renamed the tag named Logos from the Default Tag Group. I was then able to find entries using the tag named Logos from a section where entries used the Services Tag Group. This section has a tag field called Services which the source is Services Tags.

I just found another tag called Brand that does not work in the Services Tag Group because Industry Tag Group has the same Brand tag. If I rename the tag named Brand from Industry, then the entries are found in the section that uses the Services Tag Group for the tag named Brand.

Is this normal behavior as it doesn't seem like it to me. Easy solution would be to just not use tag groups but that would be a lot of refactoring tags for all entries.


Group entries by Category and then in each category by related entry field I have a channel with categories and an entries field. I need to first group all entries by their category. This is working fine.

{% set entries = craft.entries.section('publicationsChannel') %}
{% set relatedCats = craft.categories.relatedTo(entries) %}

{% for category in relatedCats %}
   {{ category.title }}

  {% for entry in relatedEntries %}
    {# this list of entries needs to be grouped by the regionCountry field #}
    {{ entry.title }} <br>

  {% endfor %}
{% endfor %}

However what I now need to do is take the list of entries and further organize them according to a relationship field handle regionCountry

There are only 3 entries in that channel Canada, US, UK and they need to be grouped in that order.

I can't seem to wrap my head around the logic needed to do this.

What I need finally is.

Category 1

Canada

entry 1

entry 2

US

entry 1

entry 2

UK

entry 1

entry 2

Category 2

Canada

entry 1

entry 2

US

entry 1

entry 2

UK

entry 1

entry 2
etc...

I figured this out in part with @syversen answer, but it need some tweaking

Here's the simplified working code. This

{% set countries = craft.entries.section('countries') %}
{% set publications = craft.entries.section('publicationsChannel') %}
{% set categories = craft.categories.group('documentCategory') %}

{% for category in categories %}
{# list categories #}

{{ category.title }}

    {# inside categories list countries #}
    {% for country in countries %}

      {{ country.title }}

          {# finally output entries that are in the category and country #}
          {% set relatedEntries = publications.relatedTo([
          'and',
          {targetElement: category},
          {targetElement: country, field: 'regionCountry'}
          ]) %}

            {% for entry in relatedEntries %}

 {{ entry.title }}

            {% endfor %}

    {% endfor %}

{% endfor %}{# end categories #}


Get entries by custom matrix / date time field I want to list all entries in a section by custom date time fields.

A training course has a From field and a To field. These fields are inside a Matrix field.

The field name storing this info is called trainingDateTime.

The Matrix block is called trainingDateTimeDateTime.

The Matrix fields in this block are called and dateTimeFrom and dateTimeTo both datetime fields.

My entries loop so far is:

{% set entries = craft.entries.section("training") %}

I know you can do order entries by a custom datetime field using something like:

{% set entries = craft.entries.section("training").customDateTime.('>= ' ~ now).order('customDateTime DESC') %}

But since I'm using a matrix field I'm unsure how to approach this.

I'm wanting to show all upcoming training courses from the current month up till the next 2 months.

I found the solution by using the following:

{% set startDate = now %}
{% set endDate = (now | date_modify("+2 months")) %}
{% set allTraining = craft.lowblocks.blocks.fieldId(72).type("trainingDateTimeDateTime").order("dateTimeFrom").limit(null) %}
{% set entryIds = [] %}
{% for course in allTraining %}
    {% if (course.dateTimeFrom >= startDate) and (course.dateTimeFrom <= endDate) %}
        {% set entry = course.owner %}
        {% set entryIds = entryIds | merge([entry.id]) %}
    {% endif %}
{% endfor %}
{% set entries = craft.entries.section("training").id(entryIds).fixedOrder(true).status("live,pending") %}


Changes made in home page not displaying I am new on Craft CMS and it's the first CMS I am trying. Hey guys, I apologies is this question was asked before. I went through lot of articles and I didn't get anything helpful yet. I added  in home.html, made changes to var.scss and home.scss so that the background color of the  can be gray.

When I open the project in the browser the  is not displaying but it's visible during inspection.

How can I fix this problem?

Have you read this?

SCSS needs to be compiled and the page is loaded with the compiled CSS files, the SCSS references are used only for easier debugging and development. Seeing a change during inspection, does not necessarily mean that the CSS file changed, maybe there was a compilation error or something.


Get local's URL for index page I have two menus.
One with countries, one with navigation.

Navigation menu must to have a index link of a active locale.
So if I'm at example.com/uk/section and I go to navigation menu and click at index link, I get index of /uk

My countries menu code is:

{% set locales = ['en', 'en_gb', 'sk'] %}
    {# Check if locale equals the requested page locale #}
    {% if locale == craft.locale %}
        {% set current = true %}
    {% else %}
        {% set current = false %}
    {% endif %}
    {% set locale = craft.i18n.getCurrentLocale() %}
      {% for locale in locales %}

           {{ craft.i18n.getLocaleById(locale).name }}

When I try to copy

{{ craft.i18n.getLocaleById(locale).name }}

and put it to my navigation menu I get

Internal Server Error    array_key_exists(): The first argument should be either a string or an integer

Is it fixable or any other way around?

I probably don't fully understand what you're trying to acchieve, but to get to the index page of your current locale, you'd simply use siteUrl().


Simple search using two categories I have a venue search tool which has two categories - event type and event size. How do I create an entries loop that returns entries that have both categories assigned?

Use the relatedTo method and pass an array using the and parameter.

 {% set venueEventType = craft.request.getParam('catVenueEventType') %}
 {% set venueEventSize = craft.request.getParam('catVenueEventSize') %}

 {% set entries = craft.entries.section('venues').relatedTo(['and', venueEventType, venueEventSize]) %}


Show related entries grouped by category with category title and description Anyone able to direct me on this?
I have a page that allows you to pick related entries (cables) within the page I want to output the related entries (cables) but group them by their category. I have the following code by this is adding each cable into each category and not just the cable within the right category.

    {% set categories = craft.categories.group('cables') %}

    {# {% set cables = craft.entries.section('cables').order('title').limit(null) %} #}

    {% set cables = entry.cables %}

    {% for entry in cables %}
        {{ entry.title }}
    {% endfor %}

    {% for category in categories.relatedTo(cables) %}

{{ category }}

                {{ category.description }}

                {% for entry in cables %}

{{ entry.title }}

                {% endfor %}

            {% for entry in cables.relatedTo(category) %}

                            Close

                                {{ entry.title }}

{{ entry.cableDescription }}

            {% endfor %}

    {% endfor %}

Your example is a trifle confusing, but in answer to your general question about grouping entries by a category field, Tim Kelty's groupBy plugin may help.

For example:

{% set groupedEntries = allEntries|groupBy('myCategoryField.title', 'Oddments') %}
{% for categoryTitle, categoryEntries in groupedEntries %}
    <h2>{{ categoryTitle }}</h2>

    {% for categoryEntry in categoryEntries %}
        {{ categoryEntry.title }}
    {% endfor %}
{% endfor %}


Correct way to include include scripts I am including head.html and scripts.html in my template. Most of the scripts load except for 2 yet the path is the same for all of them. I {% include %} them.

If I change foundation.min.js to foundation.js it works. The min file exists.

Update:
This is because JS files are checked for errors before being loaded. For example, if I visit those URL's directly it will show me an error. Any way to stop that?

http://craft.dev/bower_components/foundation/js/foundation.min.js

Update:

<script src="/bower_components/jquery/dist/jquery.min.js"></script>
<script src="/bower_components/foundation/js/foundation.min.js"></script>
<script src="/bower_components/imagesloaded/imagesloaded.pkgd.min.js"></script>
<script src="/bower_components/velocity/velocity.min.js"></script>
<script src="/bower_components/velocity/velocity.ui.min.js"></script>
<script src="/bower_components/wookmark-jquery/jquery.wookmark.min.js"></script>
<script src="/js/app.js"></script>

One way to include JS (or CSS) files, is to use the includeJsFile tag.
This tag will queue your file and append to the end of the <body>.
If, for some reason, you don't want this (say you want to include JQuery in the <head>), I would just use <script src=""> etc.

This might also solve your second problem.


How to add dynamic watermarks to images in Craft/Twig I'm wondering if something is possible in Twig/Craft CMS that I used to do in ExpressionEngine and CE Image.

I want to output company logo images, but as they're all different shapes and sizes, I want to merge them with a white rectangle background image so that the page looks neat and tidy, e.g. like this.

This is how I did this in EE (using CE Image's watermark feature, so the logo is essentially a watermark on the white background):

{exp:ce_img:pair src="{my_logo_image}" width="250" height="150" allow_scale_larger="yes" parse="inward"}
  {exp:ce_img:single src="{my_white_rectangle_background_image}" width="300" height="200" crop="yes" allow_scale_larger="yes" watermark="{made}"}
{/exp:ce_img:pair}

Any ideas on how I'd do this in Craft at all? I'm not even sure where to start. I'm currently using the following, but this just outputs the logos/images, without even trying to merge them with the white rectangle background image, so any help on this would be appreciated, thanks.

{% set thumbnailImage = {
  mode: 'fit',
  width: 300,
  height: 200,
  quality: 80
} %}

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

You'd definitely need a plugin for this. Craft's native abilities don't cover watermarks.

I've never attempted it myself, so these are just "best guesses"... but give the following plugins a shot:

https://github.com/fruitstudios/AviaryImageEditor/
http://michaelrog.com/craft/imagesmith

As always, you can find a full list of existing plugins here:

  https://straightupcraft.com/craft-plugins

If none of those work for you, you may need to develop your own custom plugin to handle it.


Exposing current Commerce2 Cart via the Element API I want to be able to retrieve the current users Cart via a JSON API endpoint, so I can loop through the products in the cart in JS on the front end.

I've got the Element API plugin installed, but I am not understanding how to grab the current cart from inside the endpoint via PHP. Any help much appreciated.

<?php
use craft\helpers\UrlHelper;
use craft\commerce\elements\Product;
use craft\commerce\elements\Order;

function requireLogin() {
    $currentUser = Craft::$app->user->getIdentity();

    if(!$currentUser) {
        throw new \yii\web\ForbiddenHttpException("You are not logged in");
    }
}

function requireCart() {
    // TWIG would be: {% set cart = craft.commerce.getCarts().getCart() %}
    $currentCart = Craft::WHAT?;
    $cartId      = $currentCart->id;

    if(!$currentCart) {
        throw new \yii\web\ForbiddenHttpException("You don't have a cart yet");
    }
}

return [
    'endpoints' => [
        'cart.json' => function() {
            requireLogin();
            requireCart();

            \Craft::$app->response->headers->set('Access-Control-Allow-Origin', '*');

            return [
                'elementType' => Order::class,
                'criteria'    => ['id' => $cartId],
                'transformer' => function(Order $order) {
                    $items = [];

                    foreach($order->lineItems as $lineItem) {
                        $items[] = [array(
                            'itemTitle' => $lineItem->title
                        )];
                    }

                    return [
                        'items' => $items
                    ];
                }
            ];
        }
    ]
]
?>

The cart is not baked into \Craft, but craft\commerce\Plugin.

Try the following:

$cart = craft\commerce\Plugin::getInstance()->getCarts()->getCart();

Uses the following function:

/**
 * Get the current cart for this session.
 *
 * @param bool $forceSave Force the cart to save when requesting it.
 * @return Order
 * @throws Exception
 * @throws \Throwable
 * @throws \craft\errors\ElementNotFoundException
 */
public function getCart($forceSave = false): Order


How to set CC or BCC emails to EmailModel? Below is my code for sending mail and this is working fine but when i set cc or bcc mail is not sent them.

    $email = new EmailModel();
    $emailSettings = craft()->email->getSettings();

    $email->fromEmail = $emailSettings['emailAddress'];
    $email->replyTo   = $message->fromEmail;
    $email->sender    = $emailSettings['emailAddress'];
    $email->fromName  = $settings->prependSender . ($settings->prependSender && $message->fromName ? ' ' : '') . $message->fromName;
    $email->toEmail   = $toEmail;
    $email->cc   = explode(',', $message->fromEmail);
    $email->subject   = $settings->prependSubject . ($settings->prependSubject && $message->subject ? ' - ' : '') . $message->subject;
    $email->body      = $message->message;

    if ($message->attachment)
    {
        $email->addAttachment($message->attachment->getTempName(), $message->attachment->getName(), 'base64', $message->attachment->getType());
    }

    craft()->email->sendEmail($email);

please correct me where i wrong.

Thanks

The way you do it now only adds email addresses as an array. You'll have to specify both email and name keys too, so it becomes like this:

$email->cc = array(
    array('email' => 'email@email.com', 'name' => 'Name')
);


Error when trying to update Craft I'm pretty new to CraftCMS and am trying to install updates for a client. I am getting this error and I don't really know what it means. Any help of brief explanation for this would be appreciated.

Error: The "https://asset-packagist.org/packages.json" file could not
be downloaded: allow_url_fopen must be enabled in php.ini (https://
wrapper is disabled in the server configuration by allow_url_fopen=0
failed to open stream: no suitable wrapper could be found) Output:
Loading composer repositories with package information.

Type php --ini in your server environment, it should tells you where the .ini files are getting loaded.
Then set
allow_url_fopen = 1


Is there a CacheService equivalent in Craft 3? CacheService is exactly what I need to cache a custom API endpoint in PHP, but I don't see it in Craft 3. What would be the correct way to do this in Craft 3?

It's still there, but you're working at the Yii2 layer: The Definitive Guide to Yii 2.0: Data Caching


Switch Matrix block on handle rather than type I've got a matrix with a Block type called textBlocks which Craft seems to be having trouble seeing.

The error is:

Craft\MatrixBlockModel and its behaviors do not have a method or closure named "textBlocks".

My template code is:

{% for block in entry.clientsContent %}

 {% switch block.type %}

{% case "text" %}

{{ block.blockTitle }}

{{ block.blockContent }}

{% case "images" %}

  {% for asset in block.images %}

  {% endfor %}

 {% case "textBlocks" %}

  {% for row in block.textBlocks %}

{{ row.title }}

{{ row.content }}

  {% endfor %}

{% endswitch %}

{% endfor %}

Am i getting this right here? When you do switch block.type is block.type the Block Type name?

See pic for my Matrix setup:

I think you already spotted it.

Change:

To:


Custom field filtering Why does this work fine

{% paginate craft.entries().limit(7).section('events').eventStartDate('>= ' ~ 2014 ~ '-' ~ 09) as entriesOnPage %}

But this does not

{% paginate craft.entries().limit(7).section('events').eventStartDate('>= ' ~ 2014 ~ '-' ~ 09) as entriesOnPage %}

I get this http://d.pr/i/NRvg

I also get errors when simply using '<' so it seems to require only either a less than or equal to or a greater than or equal to operator.

Can someone point to some kind of documentation for what is allowed within the custom field filter -------------> this part ('<= ' ~ 2014 ~ '-' ~ 09)

You shouldn't need to use string concatenation here:

.eventStartDate('>= ' ~ 2014 ~ '-' ~ 09)

If you're hard coding the year and month, just use:

.eventStartDate('>= 2014-09-01')


Are Yii plugins compatible with craft? Specifically, I'm looking at https://github.com/yiiext/shopping-cart-component. Can Yii extensions be made to work with Craft (or work out of the box)?

I'm unfamiliar with both, so I'm having a hard time approaching adding a shopping cart to this project, and I think rolling my own would turn out to be a mistake

No.  Yii's extensions and Craft's plugins are different things, although it's not that difficult to port a Yii extension to a Craft plugin.


Category as select dropdown box Im trying to setup a front end user form with a category as a select box.  The box looks right but when i submit the form i get a new entry and other fields are filled out but the catgory fields are blank?

This is for a fieldgroup named borough and the field on the section is also called bourough

<form method="post" action="" accept-charset="UTF-8">
  <input type="hidden" name="action" value="entries/saveEntry">
  <input type="hidden" name="redirect" value="account/jobs?added={id}">
  <input type="hidden" name="sectionId" value="9">
  <input type="hidden" name="enabled" value="0">

<!-- other form fields -->

  {% set boroughs = craft.categories.group('borough') %}

  <select name="fields[borough]" class="form-control">
       {% for category in boroughs %}
           <option value="{{category.id}}">
             {{category}}
           </option>
       {% endfor %}
  </select>
</form>

So looks like I was just missing the extra [] in the name.

fields[borough][]

Since categories are arrays the name also needed to be an array!


How to save entry to the current site from the front end? I have a multi site setup and a front facing entry form, which saves entries always to the same site (and not the current one which is weird).

Is there a way to define to which site the current entry should be saved? Something in the lines of:

{{ csrfInput() }}
<input type="hidden" name="action" value="entries/save-entry">
<input type="hidden" name="sectionId" value="1">
<input type="hidden" name="site" value="{{ currentSite.id }}"

The parameter is called siteId

<input type="hidden" name="siteId" value="{{ currentSite.id }}">


Saving a SuperTable field within a Matrix Field I am trying to save a SuperTable field that sits within a Matrix field.

I have followed the docs as far as I can but for some reason the SuperTable data is not getting saved.

My steps are as follows:

Get the SuperTable field id:

$matrixBlocks = Craft::$app->getFields()->getFieldByHandle('eventPerformances')->getBlockTypeFields();
$ticketBlockId = $matrixBlocks[2]['id'];

Check that the field has content and loop over it to get the array of data:

if ($event['schedules'][0]['performances'][0]['tickets']) {

    $ticketsMatrix = array();
    $i = 1;

    foreach ($event['schedules'][0]['performances'] as $performance)

    {
        foreach ($performance['tickets'] as $ticket) {
            $ticketsMatrix['new'.$i] = array(
                'type' => $ticketBlockId,
                'enabled' => true,
                'fields' => array(
                    'ticketType' => $ticket['type'],
                    'minPrice' => $ticket['min_price'],
                    'maxPrice' => $ticket['max_price'],
                    'currency' => $ticket['currency'],
                ),
            );
            $i++;
        }
    }
} else {

    $ticketsMatrix = '';
}

Pass this array through when saving the parent Matrix field

$performancesMatrix = array();
$performances = $event['schedules'][0]['performances'];

$i = 1;

foreach ($performances as $performance) {

    $performancesMatrix['new'.$i] = array(
        'type' => 'performance',
        'enabled' => true,
        'fields' => array(
            'performanceDate' => date_create($performance['ts']),
            'duration' => $performance['duration'] / 60,
            'tickets' => $ticketsMatrix
        ),
    );
    $i++;
}

The performanceDate and duration fields get saved as expected but the $ticketsMatrix data is not saving in the nested SuperTable field.

Any assistance would be appreciated!

Finally figured this out, I had to delve into the matrix field and get the individual block ids for the Supertable fields.

$matrixBlocks = Craft::$app->getFields()->getFieldByHandle('eventPerformances')->getBlockTypeFields();
$ticketBlockId = (int)$matrixBlocks[2]['id'];
$linkBlockId = (int)$matrixBlocks[3]['id'];

$ticketsField = Craft::$app->getFields()->getFieldById($ticketBlockId);
$ticketsBlockTypes = SuperTable::$plugin->getService()->getBlockTypesByFieldId($ticketsField->id);
$ticketsBlockType = $ticketsBlockTypes[0];

$linksField = Craft::$app->getFields()->getFieldById($linkBlockId);
$linkBlockTypes = SuperTable::$plugin->getService()->getBlockTypesByFieldId($linksField->id);
$linksBlockType = $linkBlockTypes[0];

After casting these to integers and then using that value as the type value when saving the matrix block, it all works!

Full code below, hopefully it will help others out in this situation:

$matrixBlocks = Craft::$app->getFields()->getFieldByHandle('eventPerformances')->getBlockTypeFields();
$ticketBlockId = (int)$matrixBlocks[2]['id'];
$linkBlockId = (int)$matrixBlocks[3]['id'];

$ticketsField = Craft::$app->getFields()->getFieldById($ticketBlockId);
$ticketsBlockTypes = SuperTable::$plugin->getService()->getBlockTypesByFieldId($ticketsField->id);
$ticketsBlockType = $ticketsBlockTypes[0];

$linksField = Craft::$app->getFields()->getFieldById($linkBlockId);
$linkBlockTypes = SuperTable::$plugin->getService()->getBlockTypesByFieldId($linksField->id);
$linksBlockType = $linkBlockTypes[0];

$performancesMatrix = array();
$ticketsMatrix = array();
$linksMatrix = array();
$performances = $event['schedules'][0]['performances'];
$i = 1;

foreach ($performances as $performance) {

     if (array_key_exists('tickets', $performance))
     {
         $t = 1;

         foreach ($performance['tickets'] as $ticket)
         {

             $ticketsMatrix['new'.$t] = array(
                 'type' => $ticketsBlockType->id,
                 'enabled' => true,
                 'fields' => array(
                 'ticketType' => $ticket['type'],
                 'minPrice' => (array_key_exists('min_price', $ticket) ? $ticket['min_price'] : ''),
                 'maxPrice' => (array_key_exists('max_price', $ticket) ? $ticket['max_price'] : ''),
                 'currency' => (array_key_exists('currency', $ticket) ? $ticket['currency'] : ''),
                 ),
             );
             $t++;
         }
     }

    if(array_key_exists('links', $performance))
    {
         $l = 1;
         foreach($performance['links'] as $link)
         {

             $linksMatrix['new'.$l] = array(
                 'type' => $linksBlockType->id,
                 'enabled' => true,
                 'fields' => array(
                     'linkType' => (array_key_exists('type', $link) ? $link['type'] : ''),
                     'linkUrl' => (array_key_exists('url', $link) ? $link['url'] : ''),
                 ),
             );
             $l++;
         }
     }

     $performancesMatrix['new'.$i] = array(
         'type' => 'performance',
         'enabled' => true,
         'fields' => array(
             'performanceDate' => date_create($performance['ts']),
             'duration' => (array_key_exists('duration', $performance) ? $performance['duration'] / 60 : ''),
             'tickets' => $ticketsMatrix,
              'performanceLinks' => $linksMatrix
         ),
     );
     $i++;
 }

$entry->setFieldValue('eventPerformances', $performancesMatrix);


Issues accessing Control Panel with iPad on iOS 7 I'm having issues accessing the Control Panel using an iPad on iOS 7.0.4. When loading the Dashboard and any subsequent pages, 6 popup alerts will appear with the message:

Safari cannot open this page because the address is invalid

After dismissing this alert 6 times, it'll disappear until you visit another CP page. I can confirm that there are no issues using iOS 8.1.2. I've tested on numerous sites without any plugins installed, along with a brand new Craft Demo site, and the issue persists.

Any ideas what could be causing this?

As @RitterKnight points out, it does seem to be an issue with Garnish. I've managed to narrow it down to garnish-0.1.js:1020, which is to do with resize detection as adapted from http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/

As one of the comments points out, changing the following line fixes the issue:

var obj = elem.__resizeTrigger__ = document.createElement('object');
to
var obj = elem.__resizeTrigger__ = document.createElement('iframe');

I'm not sure if this has any adverse effects on anything else, so would be keen to see if this is something already tested by the P&T team.

EDIT: This has now been fixed in Craft 2.4.2691.


redirect to url and set variable in template In a plugin, I am trying to redirect to a url, and set some values on the template. It's not working. Here is a simplified (not working) test case:

Template lives at templates/test.twig:

someVar is defined? {{ someVar is defined ? 'yes' : 'no' }}

<form method="post" action="" accept-charset="UTF-8">
  {{ getCsrfInput() }}
  <input type="hidden" name="action" value="site/test">
  <input type="hidden" name="redirect" value="/test">
  <button type="submit">Submit</button>
</form>

Controller code (which does get called):

public function actionTest() {
    craft()->urlManager->setRouteVariables(array(
        'someVar' => 23
    ));
    $this->redirectToPostedUrl();
}

What I expect, is that when I first visit the page, someVar isn't defined, but when I submit the form and revist the page, someVar will be defined (and equal 23). But it is not defined.

If you want to reload the form, you don't need to (indeed, shouldn't) redirect to the posted URL. That's why the form's action attribute is empty.

This should work:

public function actionTest() {
    craft()->urlManager->setRouteVariables(array(
        'someVar' => 23
    ));
}


Pocket API authorization loop Setting up a plugin using Pocket API and I'm currently in a authorization loop.

Index template calls the init function. Init function gets requestToken (successfully) and then redirects to Pocket for app authorization (authorizeToken function). After authorization, redirected to callback.

From here, I need to convert the token to a 'Pocket access token', but when the controlller fires it seems to call the init function before the accessToken function and I end up in an endless loop.

Can anyone explain why this is happening? Am I going about this the right way?

Index template:

{% extends "_layouts/cp" %}
{% set title = "Pocket Articles"|t %}

{% set offset = craft.request.getParam('offset') %}
{% set start = craft.pocket.init() %}

{% set content %}
    {{ start }}
{% endset %}

Service:

public function init(){
    $token  = $this->requestToken();
    $auth   = $this->authorizeToken($token);
    return;
}

public function accessToken($code){
    $url                    = $this->getSetting('access_path'); //https://getpocket.com/v3/oauth/authorize
    $requirements['code']   = $code;
    $requirements['key']    = $this->getSetting('consumer_key');

    $curl = $this->initCurl($url, $requirements);
    $results = curl_exec($curl);

    echo "<pre>";
    print_r($results);
    echo "</pre>";

    curl_close($curl);

    return $results;
}

private function authorizeToken($token){
    $auth_path      =$this->getSetting('auth_path'); //https://getpocket.com/auth/authorize?
    $redirect_path  =$this->getSetting('callback_path');
    $actionUrl = UrlHelper::getActionUrl('pocket/callback');

    $url = $auth_path.'request_token='.$token.'&redirect_uri='.$actionUrl;

    header("Location:".$url);

    return $url;
}

Controller:

public function actionCallback(){

    //call pocket server for acccess token
    if(craft()->httpSession->get('code')){
        $code   = craft()->httpSession->get('code');
    }else{
        $code   = "no code";
    }

    $access_connection = craft()->pocket->accessToken($code);
    $variables['access_token'] = $access_connection;

    $this->renderTemplate('pocket/control_panel', $variables);

}

Callback template:

{% extends "_layouts/cp" %}
{% set title = "Pocket Articles"|t %}

{% set offset = craft.request.getParam('offset') %}

{% set content %}
    {{ dump(access_token) }}
{% endset %}

The init method is automatically called whenever a service class is instantiated. Think of it as akin to a constructor.

If this is not want you want, just rename the method (to initialize, for example).


How to set cookie and redirect to page one time How can I redirect a member to account page on first visit with a cookie set? My redirect is looping now.

{% if currentUser %}
   {% set name = currentUser.firstName %}
   {% do craft.lj_cookies.set('account', name) %}

   {% set redirect = craft.lj_cookies.get('account') %}

   {% if redirect == name %}
       {% redirect name %}
   {% endif %}

{% endif %}

It's not possible to visit any other URL anymore.

Try this:

{% if currentUser %}
    {% set name = currentUser.firstName %}
    {% if craft.lj_cookies.get('account') != name %}
        {% do craft.lj_cookies.set('account', name) %}
        {% redirect name %}
    {% endif %}
{% endif %}

In you're original code you're setting the cookie before getting it into the redirect variable, so the {% if redirect == name %} conditional is always true.


How can we use TaxJar with CraftCommerce? Is there anything akin to a presave event or postsave event where we can make a call to TaxJar API to get calculate and report sales tax? I find the integrated tax system impractical at the moment. I would like to create a plugin that can access the existing tax api platforms, but need to know the best insertion points for this.

The onBeforeSaveOrder event runs before all of the adjustments are calculated (including taxes), so it seems like that's what you're looking for.


Select dropdown not going to option url I have a pop up box on a siteplan image that includes a select dropdown to let people select the apartment that they want. However, I can't get the it to go to the url when it's selected. So need some help please.

Currently when you select Plot 18 from the dropdown options it goes to:

websitename/developments/surrey/knowle-hill-park?sitemap=%2Fplot-18

however it needs to go to:

websitename/developments/surrey/knowle-hill-park/available-homes/plot-18

Can someone help show what i'm doing wrong in the form below:

<form action="{{ category.url }}">

      <select id="sitemap" class="form-control" name="sitemap" onchange="this.form.submit()">
        <option value="">Select Plot No</option>
          {% for entry in craft.entries.section('availablehomes').relatedTo(category).level(2).order('plotPrice desc') %}
          {% if entry.plotType == 'apartment' %}
          <option value="/{{ entry.slug }}">{{ entry.title }} - {{ entry.floor.label }} - {% if entry.plotAvailability == 'available' %}{{ entry.plotPrice|currency('GBP', true) }}{% else %}{{ entry.plotAvailability.label }}{% endif %}</option>
          {% endif %}
          {% endfor %}
        </select>

  </form>

What you're currently seeing is the correct URL for a GET form submission.

You'll need to update the onsubmit handler to construct the URL you wish to visit, based on the selected option.

Here's how to do that, using the omnipresent jQuery. You could probably do the same in plain JS, but I have no idea which browsers you're targeting:

(function ($) {
    $('#sitemap').on('change', function (event) {
        var $select = $(this);
        var $form = $select.closest('form');
        var url = '/desired/path/to/development' + $select.val();

        window.location.href = url;
    });
}(jQuery));

Don't forget to remove the current handler from the markup.


How do I edit a dropdown field in the charge.onCharge hook? I have an invoice that is sent to stripe to be paid. When the thanks.html is shown, I would like the invoices section's invoicePaid dropdown field to change from "No" to "Yes" using the charge.onCharge hook.
I tried the following( and variations ) without success.

 {
    craft()->on('charge.onCharge', function(Event $event) {
        craft()->on('entries.onSaveEntry', function(Event $event ){

            //Is the entry in the section 'invoices'?
            if ($event->params['entry']->section == 'invoices') {

            //Replace values
            $event->params['entry']->getContent()->invoicePaid = 'Yes';
            }
        });

    });
}

Where am I going wrong, or is there a better way to go about this?

In your current example, you are not actually saving an entry. You are just setting up an onSaveEntry event listener. To save the entry you will need to actually save the entry using the [saveEntry][1] method.

UPDATE: I'm not exactly sure what your setup is — but some variation on the following should work for you.

In the CMS, add a field called 'invoiceID', which you will use to store the invoice entryId to the charge (or 'invoiceEntryId' or whatever you want to call it).
Add the 'invoiceId' field to the charge field layout in charge->settings->fields.
In the charge form, add the 'invoiceId' field to your form (this assumes that you are making the charge from the invoice entry page, otherwise you will need to use a reference to the invoice entry id through whatever relationship you have set up):

<input type="hidden" name="fields[invoiceId]" value="{{ entry.id }}"/>

In your plugin, add the onCharge event to grab the 'invoiceId' from the charge event, then retrieve, update, and save the entry.

craft()->on('charge.onCharge', function(Event $event) {

    // get the charge model
    $charge = $event->params['charge'];

    // retrieve the invoiceId (aka entryId) saved on the charge model
    $entryId = $charge->invoiceId;

    // uncomment to test, if needed
    //LogicPlugin::log('Invoice ID: '.$charge->invoiceId, LogLevel::Info);

    // get the invoice entry from the invoiceId
    $entry = craft()->entries->getEntryById($entryId);

    // update the invoicePaid field (in this case I'm using a switch)
    $entry->getContent()->invoicePaid = '1';

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

    // log errors
    if (!$success) {
        LogicPlugin::log('Couldn’t save the entry "'.$entry->title.'"', LogLevel::Error);
    }

});


What is the best way to exclude an array of entries? I have done a "Is featured" switch on articles which works great. I can list the latest 4 featured articles but after that I would like to list the others (Of course they may be featured too). What is the best way to exclude an array of elements when getting elements? Or is there a better solution?
Update 1
{% set allArticles = craft.entries.section('articles').find() %}
{% set featuredArticles = craft.entries.section('articles').featured(1).limit(4).find() %}
{% set notFeaturedArticles = allArticles|without(featuredArticles) %}

This is the code and the notFeaturedArticles returns with the same entries as the allArticles.
Update 2
{% set featuredArticleIds = craft.entries.section('articles').featured(1).limit(4).ids() %}
{% set featuredArticlIdsString = featuredArticleIds | join(', ') %}
{% set notFeaturedArticles = craft.entries.section('articles').id('not '~featuredArticlIdsString) %}

In this case only the first entry is excluded from the not featured articles.

Craft documentation describes how to exclude entries with a given value. In this case, we want a string that looks like: 'and, not id1, not id2, not id3, not id4'

So we need a string that is all of the featured article ids separated by , not. First, get them as an array using ids():

{% set featuredArticleIds = craft.entries.section('articles').featured(1).limit(4).ids() %}

Then convert that array to a string, using twig's join filter:

{% set featuredArticleIdsString = featuredArticleIds | join(', not ') %}

Then, fetch all the articles, but not the featured ones:

{% set notFeaturedArticles = craft.entries.section('articles').id('and, not '~featuredArticleIdsString) %}

[thanks to carlcs for crucial fix]


Retrieve Matrix Field from Related Category in Element API I have an API endpoint set up for a category group. This currently provides some details of all entries that have been assigned that category (i.e. related entries). That works well for some high level details, but I now need to add support for a Matrix field that those related entries contain. Here's the current setup:

'series.json' => function() {
            return [
                'elementType' => Category::class,
                'criteria' => ['group' => 'series'],
                'paginate' => false,
                'transformer' => function(Category $entry) {
                    $entries = Entry::find()
                        ->relatedTo($entry)
                        ->select(['slug','title','field_rating AS rating','field_pageCopy AS desc','postDate AS date'])
                        ->asArray()
                        ->all();

                    $typeArray = array_map('strval', $entry->mediaType->all());

                    return [
                        'id' => $entry->id,
                        'slug' => $entry->slug,
                        'title' => $entry->title,
                        'type' => strtolower($typeArray[0]),
                        'desc' => $entry->blurb,
                        'entries' => $entries
                    ];
                }
            ];
        }

However, if I try to add the Matrix field to the select() argument it doesn't work. If I remove select() I can see why: it isn't a listed field. If I remove asArray() then I can see all the relevant fields, but I can't limit the ones available, which is undesirable as it exposes a lot of excess information.

I feel like their might be a better way to format my transformer to begin with, but I'm at a bit of a loss when it comes to the docs.

I've found a workaround for now. It's not ideal and I feel like it will probably be too intensive at scale but, for my uses, it will work.

Rather than using select() to reduce the data being returned from the initial query, I'm simply returning everything:

$related = Entry::find()
   ->relatedTo($entry)
   ->all();

I'm then looping over the returned object using foreach(), within which I'm dealing with the Matrix blocks in a seperate foreach(). At both levels I just pass back the data I want, something like this:

$reviews = [];
foreach ($related as $relatedEntry) {

   // Condense matrix blocks
   $critiques = [];

   foreach($relatedEntry->critique as $block) {
      $critiques[] = array(
         'title' => $block->seriesTitle,
         'copy' => $block->review,
         'date' => $block->date,
         'viewCount' => $viewCount,
      );
   }

   $reviews[] = [
      'id' => $relatedEntry->id,
      'slug' => $relatedEntry->slug,
      'title' => $relatedEntry->title,
      'critiques' => $critiques,
   ];
};

The output $reviews[] array is therefore equivalent to what I was doing with select() but not contains subarrays of my matrix field. Incidentally, I have managed to nest that one further with a SuperTable field within a matrix field. It needed another nested foreach() but it worked easily enough.

Once you have all of that, you can just pass it back to the endpoint like normal, so the whole thing (with above sections of code collapsed) looks like this:

'api.json' => function() {
   return [
      'elementType' => Category::class,
      'criteria' => ['group' => 'series'],
      'paginate' => false,
      'transformer' => function(Category $entry) {
         $related = Entry::find()
            ->relatedTo($entry)
            ->all();

         // Loop over related entries to extract just the information wanted
         $reviews = [];
         foreach ($related as $relatedEntry) {
            {...}
         };

         return [
            'id' => $entry->id,
            'slug' => $entry->slug,
            'title' => $entry->title,
            'reviews' => $reviews,
         ];
      }
   ];
}

As I say, not ideal so I'm leaving this unanswered. If anyone has a more elegant solution I'd love to know.


Update multiple database entries via controller I've inherited a Craft site that is a mix of a custom plugin (the main site) plus a Laravel Dingo plugin (behind which the bulk of the data in the db lives), plus Solr, and I'm trying to untangle it.

I want to add a function to my controller that updates multiple entries in the database but I can't figure it out. I'll post a snippet of a working existing code along with my attempt:

//Controller
==working, existing code===
public function actionUpdateGuide() {
    $this->requirePostRequest();

    $attr = craft()->request->getPost('guide');
    $request = craft()->MyPlugin_guide->updateGuide($attr);

    if ($request && $request->isSuccessful()) {
        $this->clearCachedAsset($attr['id'], 'guide');
        $this->redirectToPostedUrl();
    } else {
        $this->hydrateInvalidForm($request, $attr);
    }
}

==not-working, my function===
public function actionPositionGuide() {
    $this->requirePostRequest();

    $attr = json_decode(craft()->request->getPost('guide.json'), true);
    $neworder = array();

    foreach($attr as $row) {
        $guide = array(
            'id' => $row['name'],
            'position' => $row['value']
        );

        array_push($neworder, $guide);
    }

    $request = craft()->MyPlugin_guide->positionGuides($neworder);

Then

//Service
==working, existing code===
public function getGuideLocations($id, $page) {
    $url = $this->getUrl() . "/" . $id . "/locations?page=$page";
    $response = craft()->laravel_plugin->send('get', $url);

    if (!$response->isSuccessful()) {
        return array("error" => $response->getStatusCode(), "msg" => "get_guide_locations_error");
    }

    return $response->json();
}

==non-working, my function==
public function positionGuides($attr) {

    foreach($attr as $guide) {
        craft()->laravel_plugin->update($attr);
    }
}

I'm confused because I assumed the normal workflow was controller->service->model->database, but this seems to be controller->service->anotherplugin-service.

Looking in the controller for this Laravel plugin, I see:

public function update($id) {
    $guide = Guide::find($id);

    if (is_null($guide)) {
        return 'error';
    }

    $locations = Input::get("locations", array());
    if(!empty($locations)) {
        $locations =  Location::whereIn('id', $locations)->lists('id');
    }

    $guide->locations()->sync($locations);

    $guide = $guide->fill(Input::all());

    if (!Input::has('image_id')) {
        $guide->image_id = null;
    }

    return $guide->save() ? $guide : $guide->getErrors();
}

And here is the laravel_api model for it:

protected $table = "guides";
protected $fillable = ["name", "city", "type", "image_id", "description", "status", "updated_by", "document", "position"];
protected $dates = ['deleted_at'];
protected $rules = ["name" => "required"];
protected $appends = array('location_detail');

protected $searchable = ['name', 'description', 'subtitle'];

public function locations()
{
    return $this->belongsToMany('Location');
}

Any advice would be appreciated.

OK, I managed to figure it out and I'll post the solution for those who run into similar problems.

Essentially, what's happening is Twig template->Plugin controller->Plugin Service->Laravel API->Laravel Controller->Database

The code:

//Plugin controller
public function actionPositionGuide() {
    $this->requirePostRequest();
    $attr = json_decode(craft()->request->getPost('guide.json'), true);
    $neworder = array();
    foreach($attr as $row) {
        $guide = array(
            'id' => $row['name'],
            'position' => $row['value']
        );
        array_push($neworder, $guide);
    }
    $request = craft()->myplugin_guide->positionGuides($neworder);

}

Then

//Plugin service
public function positionGuides($attr) {
    $url = $this->getBaseUrl() . "/guides/position";
    return craft()->mylaravel_api->send('post', $url, $attr);

}

Then add a route to the Laravel routes.php file

Route::post('guides/position', 'GuidesController@position');

Then the Laravel controller:

public function position() {
    $data = Input::all();
    $response = ["msg" => "success", "status" => 200];

    foreach($data as $guide) {

        $oldguide = Guide::find($guide['id']);

        if (is_null($oldguide)) {
            $response = ["msg" => "error", "status" => 500];
        }

        $oldguide->position = $guide['position'];

        $oldguide->save() ? $oldguide : Log::debug($oldguide->getErrors());
    }

    return Response::json($response["msg"], $response["status"]);
}

Error handling is not great but if anyone has suggestions for improvement, I'm all ears.


Ignore Twig's variable and transform it to Polymer's variable. I've encountered on a problem with escaping, where I want some parts of code, not being translated by Twig.

Straight to the problem.

Polymer, uses the same marking for variables as Twig, and I'm not sure, if it's possible to escape variable as a Twig's variable and transform it to a Polymer's variable

By Twig's documentation, I've end up with this:

<iron-media-query query="(min-width: 600px)" query-matches="'{{'{{queryMatches}}'}}'">

where it translates to:

<iron-media-query query="(min-width: 600px)" query-matches="'{{queryMatches}}'"></iron-media-query>

The goal is:

<iron-media-query query="(min-width: 600px)" query-matches="{{queryMatches}}"></iron-media-query>

You forgot to remove the outer single quotes in your first example

<iron-media-query query="(min-width: 600px)" query-matches="{{'{{queryMatches}}'}}">

Try the raw filter if that doesnt work. More info on it here


How do I link an image to its own page? I'm new to Craft CMS and can't figure out how to link images with the code below to its own page. Any suggestions?

{% for asset in entry.mainImages %}

{% endfor %}

In Craft assets do not get "their own page" by default, but you can easily create them with a Dynamic Route. So go to Settings → Routes and add a new route with a number token, e.g. assets/<number> and route those URIs to a new template, e.g. assets/_entry.

With this route set up you can now link to an asset's entry page like so:

In your assets/_entry.html template you do now query for your asset via its ID, which is now available as a variable named "number". Use the exit tag to 404 the request in case no asset was found for the given ID.

{% set asset = craft.assets.id(number).first() %}

{% if not asset %}
    {% exit 404 %}
{% endif %}

{{ asset.caption }}


Pass a nested array to the params argument inside Craft's url() function I have a list of checkboxes in a GET form which results in a URL with a querystring like ?q=&cat=&city%5B%5D=28&city%5B%5D=26&sort=asc&order=name when submitted. The Object/Array behind this string looks like:

Array
(
    [q] =>
    [cat] =>
    [city] => Array
        (
            [0] => 28
            [1] => 26
        )
    [sort] => asc
    [order] => name
)

I'm trying to create a link with one of those GET params changed, but I can't find a way to update a single value. So now I'm rebuilding the URL by creating an object based on the given query params.

If I pass this object (as shown above) to the second argument inside Craft's url() function to use this URL on a simple <a> tag, I get an Array to string conversion error.

I seems Craft can't handle nested arrays in this function. Is there another method to generate an URL from such an object?

Yeah, looks like Craft's url() method doesn't support nested array syntax for querystring params.

If you still want to use it, then you'd need to flatten it with unique keys such as:

Array
(
    [q] =>
    [cat] =>
    [city0] => 28
    [city1] => 26
    [sort] => asc
    [order] => name
)

Alternatively you can manually build the URL yourself in Twig in whatever format you'd like.


Cannot go to site URL while logged in without index in URL For some reason I can no longer go to my default site URL while I am logged in.

Going to http://localhost:3001/craft-site/web/ gives me the following message in Chrome:

  ERR_TOO_MANY_REDIRECTS

Trying to refresh the site gives me this strange error message from Craft:

  HTTP 404 – Not Found – yii\web\NotFoundHttpException

  Template not found: $DEFAULT_SITE_URL/$DEFAULT_SITE_URL

I can still go to http://localhost:3001/craft-site/web/index while logged in and it works fine. The most interesting thing is that the file index.twig is completely empty.

For Documentation out of the comments:
'loginPath' => '/' was present in config/general.php, after removal of this line the website started working again.
Conclusion:
Don't set the Admin Backend or any other type of URL which requires a login (or is special in any way really) to "/" or an empty string, this can and will very likely cause major issues such as a completely non-functioning site unless index.php is in the URL (at all times).
Sidenote
I once faced a similar issue, the cpTrigger in config/general.php to an inexistant .env variable, eg $cpTr1gger, but since that wasn't present in my .env and I used getenv('cpTrigger') which returns empty strings if the requested var isn't found, it completely broke my website, similar to the above mentioned issue, it only worked with index.php in the URL.


How to handle client expectations regarding page building and layout within Craft I love Craft CMS and use it for nearly every site I build. There isn't a better tool (in my opinion) for managing custom data.

And using a matrix field as content builder solves the majority of my client's publishing needs.

But with so drag and drop page building tools on the market, I find that sometimes clients expect to find the same drag and drop page layout ability within Craft as they would find in Squarespace or Weebly or Mail Chimp Templates.

Other than educating a client that Craft is not a layout tool and there are times when you use different tools for different jobs, what solutions do you suggest?

Is there a way to accomplish minimally viable layout with becoming very dependent on plugins?

Is there are way to use a 3rd party page builder and embed the content in Craft?

Or is best not to even try?

Have you approached handling client's layout expectations within Craft CMS?

This question comes up in support tickets every so often from client users.

We like to say that Craft fills the space between where WordPress ends and Enterprise begins. It's meant for designers and developers to build bespoke websites for clients. That would include Squarespace-like website building services as well.

If your design, technical, and business requirements exceed what Squarespace can offer then they naturally exceed what a drag/drop website builder can provide. If there's anything a client wishes for in the control panel then they can ask their agency or developers about feasibility. Craft is extensible enough to make most thing possible; it's just a matter of effort and cost.


Show Live Preview even if whole page is disabled The whole page is disabled in the backend. Like in this screenshot:

Now I can't see anything in the Live Preview.

My code starts with: {% for entry in craft.entries.section('aboutus') %}

If I set .status(null) I see everything in the Live Preview, but also the entries which are disabled.

So is it possible to show a disabled page in a Live Preview but not the disabled entries of this page?

UPDATE

In the Live Preview I can see all outside of this for loop {% for entry in craft.entries.section('aboutus') %} but nothing inside.

I uploaded my code here.

You can combine .status( null ) with the isLivePreview property on craft.request. More info can be found in the docs.


Access handle value using element API I'm using the Element API and would like to return content based on it's handle. The two handles I am trying to return are called appLogo and appVideo:

'api/featured-apps.json' => [
  'elementType' => 'Entry',
  'criteria' => [
    'section' => 'apps',
    'appFeatured' => '1',
  ],
  'transformer' => function (EntryModel $entry) {
    return [
      'title' => $entry->title,
      'logo' => $entry->appLogo,
      'video' => $entry->appVideo,
    ];
  }
],

This does not work, do I need to access images/videos in a different way? Ideally, I'd like the relative path returned for both logo and video.

I ended up doing it like this:

'api/featured-apps.json' => [
  'elementType' => 'Entry',
  'criteria' => [
    'section' => 'apps',
    'appFeatured' => '1',
  ],
  'transformer' => function (EntryModel $entry) {
    $logos = [];
    foreach ($entry->appLogo as $image) {
      $logos[] = $image->url;
    }

    $videos = [];
    foreach ($entry->appVideo as $video) {
      $videos[] = $video->url;
    }

    return [
      'title' => $entry->title,
      'logo' => $logos,
      'video' => $videos,
    ];
  }
],


How can I use a reference tag with a global set using the handle (not the ID) https://craftcms.com/docs/reference-tags

In my tests, only using the ID with globalsets work, e.g {globalset:34:address}.

I'd like to do {globalset:misc:address}, with misc being the global set handle.

Currently, you can't.  Only element IDs will work for the reference part of the reference tag when using a global set.

Only entries get two additional formats for the reference part of the tag.

entry-slug
sectionHandle/entry-slug


unsucessful setFieldValues after programatically creating field on a migration as part of a migration script I'm trying to:

create 2 new fields,
add them to a field group
add the new fields to a specific tab on an entry type
Update the values of the new fields

What I have so far works up until point 4, in the database the fields exist on the entry, I can see them there when I browse to an entry in the CMS, I can save new values to them, but, I cannot set a value with setFieldValues straight after. Can anyone suggest what I've done wrong here?
Here is my code so far:
public function safeUp()
{
    // Get contact field group
    $groupId = 31; // contact field group
    $fields = Craft::$app->getFields(); // Get fields
    $fieldGroup = $fields->getGroupById($groupId); // Get contact field group

    // Create heading field
    $headingFieldHandle = 'contactThanksHeading';
    $headingField = new PlainText([
        'groupId' => $fieldGroup['id'],
        'name' => 'Contact Thanks Heading',
        'handle' => $headingFieldHandle,
        "instructions" => "Larger heading text for the contact form's thanks message",
        "required" => false,
        "placeholder" => "Thank you",
        "charLimit" => 300,
        "multiline" => false,
        "initialRows" => "4",
    ]);
    // Save heading field
    Craft::$app->getFields()->saveField($headingField);

    // Create copy field
    $copyFieldHandle = 'contactThanksCopy';
    $copyField = new PlainText([
        'groupId' => $fieldGroup['id'],
        'name' => 'Contact Thanks Copy',
        'handle' => $copyFieldHandle,
        "instructions" => "Smaller copy text for the contact form's thanks message",
        "required" => false,
        "placeholder" => "One of our team will get back shortly...",
        "charLimit" => 300,
        "multiline" => true,
        "initialRows" => "4",
    ]);
    // Save copy field
    Craft::$app->getFields()->saveField($copyField);

    // Get contact single section
    $contactSection = Craft::$app->getSections()->getSectionById(2);
    // Get the section's entry types
    $contactEntryTypes = $contactSection->getEntryTypes();

    // Find entry type 2
    foreach ($contactEntryTypes as $entryType) {
        if ($entryType->id === '2') {
            $contactEntryType = $entryType;
            continue;
        }
    }

    // Get the field layout for entry type 2
    $contactFieldLayout = $contactEntryType->getFieldLayout(2);
    // Loop on tabs to find common
    foreach($contactFieldLayout->tabs as $tab) {
        if ($tab->name === 'Common') {
            $contactCommonTab = $tab;
            continue;
        }
    }

    // get the common tab's existing fields
    $tabFields = $contactCommonTab->getFields();

    // Set the sort order of the new fields to append them to the tab
    $headingField->sortOrder = count($tabFields);
    $copyField->sortOrder = count($tabFields)+1;

    // Add new fields to Common tab array
    $newFields = array_merge($tabFields,[$headingField, $copyField]);
    // Save fields to tab
    $contactCommonTab->setFields($newFields);

    // Set the tabs on the field layout
    $contactFieldLayout->setTabs($tabsForSaving);

    // Save the contact field layout
    Craft::$app->fields->saveLayout($contactFieldLayout);

    // get the contact entry
    $contactEntry = Craft::$app->entries->getEntryById(8);
    // Set the contact entry values
    $contactEntry->setFieldValues([
        $headingFieldHandle => '1',
        $copyFieldHandle => '1',
    ]);
    // save the contact entry
    Craft::$app->elements->saveElement($contactEntry);
}

The main issue here ended up being a Craft bug (craftcms/cms#6651), which has been fixed for the next release (3.5.5).
There are a couple ways your code could be improved as well, though:

$fieldGroup is a craft\models\FieldGroup object, not an array, so you should access its ID via $fieldGroup->id, not $fieldGroup['id']. (Or just use the $groupId property.)

Avoid using === for numeric properties like id, unless you know for certain what the type is going to be. IDs should be casted as integers, not strings, and places where they are strings should be considered a minor bug. (It’s due to how MySQL returns the data, but not an issue in PostgreSQL, and we are working toward always ensuring that they are typed as ints correctly even for MySQL.) Safest thing for you to do is replace === with == on this line:
if ($entryType->id === '2') {

Your two continue statements should be break. continue just tells the loop to move onto the next cycle of the loop; break tells it to completely break out of the loop.

$tabsForSaving is never defined. I’m surprised that’s not causing a PHP error for you.


Replace # with entry.title Good morning and thank you in advance. How can I replace '#' with the entry.title. I have tried everything and I keep getting hash errors. Current code is this:

{{ wordBoldTitle|replace({'#':'{{entry.title}}'} )|raw }}

Trying to concatenate the  with the entry.title.

In Twig, you never want to use delimiters inside other delimiters (e.g. {{ ... {{ ... }} }}).

Here's how you would format it instead:

{{ wordBoldTitle | replace('#', '' ~ entry.title ~ '') | raw }}

What we're doing here is using Twig concatenation (via the ~ operator) to combine our first string (), whatever string entry.title results in, and then our second string ().

Alternatively we can use string interpolation to achieve this; however string interpolation requires double-quotes, so to do this we'll need to escape the double quotes already in our string:

{{ wordBoldTitle | replace("#", "${entry.title}") | raw }}

I also changed your replace filter from using a hash (e.g. {'#':'xxx'} to the simpler (at least in this case) comma-separated parameters. The hash works well if you need to replace multiple items, but the comma-separated parameters looks cleaner in my opinion when you only need to replace one item. You can find more about the replace filter formatting here.


In Craft 3, how to clear stuck "Deleting Stale Template Caches" I've got 12 pending tasks, and can't get rid of the first stuck one.

CP->Utilities->Clear Caches doesn't seem to help.
In the database, in craft_queue there were five rows, the first one seeming to be the stuck one. I deleted all of those

Still the first task is stuck, and by now there are 14 tasks waiting.
I see that craft_templatecachequeries has over 11,000 rows. Would those be helpful to delete?

The answer was, to delete the first row of the queue table in the correct database.
Also, it helped to increase max_execution_time in /etc/php/7.1/apache2/php.ini


Commerce product order/sort options What are all the available options that products can be ordered by?

craft.commerce.products({ order: '???' })

I have found this reference https://craftcommerce.com/docs/products-fields#templating but it does not list the available options.

Bonus points if it includes the key that sorts by sales (aka popularity).

When you call craft.commerce.products you're asking Craft for an Commerce_ProductModel.

So you could sort by:

title (alpha)
defaultPrice
type
promotable (sale products on top)
postDate (newest products)
.. etc.

To sort by sales (popularity), you might consider something like BonFire's Popular Products plugin which keeps track of how many purchases were made and how many times the product was viewed, very similar to Ben Croker's EntryCount plugin.


Are there any advantages of updating from PHP 5.4.40 to 5.6? Simple question, are there performance gains or any other benefits to make it worth the effort of updating the server?

Short yes! You can find a detailed Benchmark on http://www.lornajane.net/posts/2014/php-5-6-benchmarks. If possible i would try to update from PHP 5.4.40 direct to PHP 7. The performance from PHP 5.4 to PHP 7 is massiv. A change to PHP7 made our Craft installation twice as fast. You can find some further information here -> https://pixelandtonic.com/blog/php-7


Use default Craft error/exception layout in Plugin Is it possible for me to use the default Craft error-handling/exception-throwing/debug-showing template layout for my own plugin? Let's say something goes wrong and I want to show that to the user in the same style as any other "code related error" for my Plugin.

Could/how would I achieve this?

If I'm understanding your question correctly, then you get that behavior by default.

If you:

throw new Exception('Uh oh.');

Then you'll get the same error handling layout and logic that Craft uses.

You can read here for more information on how that works.