How do I query two relationship fields where one relationship MUST be empty? I have two relationship fields. I am trying to query all entries where the first field is related to a particular element and the second field is related to nothing. Here is how I thought it would work but it doesn't.

$criteria->relatedTo = ['and',
[
    'targetElement' => anElementId,
    'field'         => 'relationshipOne'
],
[
    'targetElement' => null, // also tried ":empty:"
    'field'         => 'relationshipTwo'
]];

Splitting the criteria up like this works.

$criteria->relatedTo = [
    'targetElement' => anElementId,
    'field'         => 'relationshipOne'
];
$criteria->relationshipTwo = ':empty:';

Thanks to @carlcs in the Craft Slack channel.


Matrix Entry URL Link Trying to create a page link to entries and can't figure out how to do it.  Here's what I have.  It's just outputting the title, but not the url.  Specifically, I'm talking about {{ block.pageLink.first }} Any help is much appreciated.

{% for block in entry.threeHomepageImages.type('images') %}

                {% if block.image|length %}

                {% endif %}

{{ block.imageTitle }}

{% endfor %}

If pageLink is an Entry field and image is an Assets field, then you're probably looking for something like this:


Why does my base template never reload? I use template inheritance:

In _layout.html every other template is loaded with {% block content %}{% endblock %}

The problem: _layout.html never reloads. I changed the CSS path in the head tag of _layout.html but I never see the change reflected. Why?

restarted MAMP (cache is already disabled)
restarted computer
emptied every cache I know of
cache tags aren't used
used all different browsers
deleted the storage/runtime folder

The above steps have no effect, and any changes on _layout.html don't appear to do anything. Why might this be?

Are you using PHP 5.5?  If so, opCache is enabled by default and that’s probably causing your issue.


How to automatically remove entries after a certain time? I haven't found anything similar to this. But I was wondering if it's possible to delete certain entries after a certain time?
For example: User fills in form and adds contact entry - after 2 weeks this entry gets removed automatically. This way the database won't fill up, and the overview will stay clean.
I was thinking a cronjob every 24h that checks the postdate and when the postdate is over 2 weeks it gets removed. However I'm not sure if this is possible with craft cms?

To only disable an entry, use this:
If entries need to be deleted, you can create a custom plugin, where entries will be deleted when expired or when the postdate is older than 2 weeks..


Is it possible to configure the FileLogRoute? I am trying to debug a "clean template cache" task that gets stuck. However, it only happens intermittently, and whenever I notice any errors has already been rotated out of the log files.

Is there a way to set the maxLogFiles of the FileLogRoute?  either through the config files, or through php code in a plugin?

(Setting $rotateByCopy to true would also be nice!)

Currently not without hacking the core files.

It's on our list to make log routing more configurable for Craft 3, though.


DeleteStaleTemplateCaches job getting stuck We have only two templates leveraging the cache tag and they both have a construct similar to:

{% extends "_layout" %}

{% block content %}
  {% cache globally using key entry.url ~ "relatedArticles" for 1 hour %}
    ... bunch of relational queries ...
  {% endcache %}
  ...
{% endblock %}

Once or twice a day, the DeleteStaleTemplateCaches get stuck and requires manual "killing".  For example, when this occurs, the craft_tasks table indicates say currentStep 1309 of totalSteps 12800...  Then, "error'ing" the task, and choosing the "Retry task", generate a new job but will say only 670 totalSteps...  and of course it succeeds.  Why is the total steps so much different on retry?

There is no clue in the logs.  Only the logs of the "retried task" that show the steps and its successful result.  Nothing about the stuck task that I killed.

Currently, we have 3 nodes sharing a common file system for all (except most of the "runtime folder") and common database but individual memcached server (one per node).  Craft is configured to use memcached.  Could the issue be that more than one node start the delete task at the same time?  i.e. all try to cleanup the same db table?

Beside this specific problem, I would be very grateful if you could explain how the different caching (data, templates, etc.)  works within craft or indicate where I can find the information. i.e. I'm not clear on what is cached in memcached vs the database, vs file system (if anything).

Thanks.

See these for help debugging stuck tasks:

Generating pending image transforms stuck in process

Deleting Stale Template Caches Failed

http://buildwithcraft.com/help/stuck-tasks

As far as what cache gets saved where, template caches (the {% cache %} tag) always get saved in the database.

See here for an explanation on how all of that works.

The cacheMethod config setting, which is what you've set to memcache affects any PHP code in Craft that is using craft()->cache (including plugins).

See these for more discussion on it:

How much data can craft()->cache hold?

Use cache instead of saving to database


Hide the Week Start Day Is it possible to hide the week start day on the 'Account' tab?

I'm about to import 400+ members and don't want to confuse them with this unnecessary setting (from their perspective).

Thanks in advance.

Adam

You could do this using the CP CSS plugin from Lindsey DiLoreto.

Install the plugin then add the following custom css:

#weekStartDay-field { display: none; }

Note that this will hide the field for all users, including you.


Building a filtering system using both OR and AND relations I'm trying to set up a filtering system similar to the one found on the product pages on asos.com. That system has different category groups of filters, where selecting multiple filters inside a particular category group widens the results list (OR / conjuction), whereas filters across category groups narrow the results list (AND / disjunction).

I'm trying to replicate this behaviour in Craft, but I'm struggling to combine AND and OR relations. I currently do the following to build up a list of filters across category groups from a comma separated query string in the form ?regions=22,33&teams=65&sectors=42,43,44:

{% set categoryGroups = ['regions', 'teams', 'sectors', 'topics'] %}
{% set relations = ['and'] %}
{% for group in categoryGroups %}
  {% set filterValueString = craft.request.getParam(group) %}
  {% if filterValueString != '' %}
    {% set filterValues = filterValueString|split(',') %}
    {% set relations = relations|merge(filterValues) %}
  {% endif %}
{% endfor %}

{% if relations | length > 1 %}
  {% set params = params | merge({ relatedTo: relations }) %}
{% endif %}

{% set results = craft.entries(params) %}

This results in a relations array which looks like ['and', 22, 33, 42, 43, 44, 65], and creates a system where adding a filter to an already filtered category group restricts the result set further, instead of widening it to encompass the new filter. I thought perhaps that I could construct relations to look like ['and', [22, 33], [42, 43, 44], 65], and the inner arrays (category groups) would default to an OR (as it would when passing a standard array of element IDs into relatedTo), with the outer relation providing the AND, but this doesn't appear to work.

Is there anyway to get the behaviour I'm looking for?

I've looked at it further and arrived at a solution.

The relations array needed to be in the form ['and', {element: [22, 33]}, {element: [42, 43, 44]}, {element: 65}].

So that could be done using the following:

{% set relations = relations|merge([{element:filterValues}]) %}


Plugin's action URL not working and showing 404 error I created a plugin to schedule some custom email notifications. The action URL is working perfectly on localhost but isn't working on stagings server. Is it related to any server stuff.

There's a 99% chance you're running into a case-sensitivity issue on your file system.

Check your plugin's name, the handle and the action URL for the controller you're trying to hit.

Most likely locally, you've got a case insensitive file system, so it doesn't matter that pluGiNHanDlE is not equal to pluginHandle, but on staging it's case sensitive so it does.


Sorting Matrix Field I realize this is a very general question but is there a way to sort a matrix field? So not alphabetically but a very certain order.

I had not seen this before, but it's the solution to my problem as I was dealing with grouping.  See link below.

Group entries by section


GoogleMaps plugin marker setOptions error There's something that I'm missing in the migration from smartMaps to GoogleMaps. I have a series of points that represent different types/outcomes/modes of transportation crashes. I'm setting options on the markers and then trying to push that back into the googleMaps markers.
This worked with smartMaps but my JS-skillz are not super strong and I'm getting an error:
Example:
Uncaught TypeError: Cannot read property 'mapAlpha.5981.address' of undefined
What am I missing here?
 {% set locations = craft.entries.section('crashes').all() %}

  {% set options = {
    id: 'mapAlpha'
  } %}

  {{ googleMaps.map(locations, options).tag() }}

  <script>

    var crashMarkers = Array();

    {#  Loop through entries and add settings to markers #}
    {% for entry in locations %}
      var markerId = 'mapAlpha.{{ entry.id }}.address';

      // Uncaught TypeError: Cannot read property 'mapAlpha.5981.address' of undefined

      googleMaps.marker[markerId].setOptions(
          {
              'icon': '{{ icon }}',
          }
      );

      crashMarkers.push(googleMaps.marker[markerId]);

    {% endfor %}

</script>

Icon management is handled a bit differently in the new Google Maps plugin. Now, you set icons before the map is rendered, even in Twig!

Official guide for Setting Marker Icons

{# Get all bars & restaurants #}
{% set bars        = craft.entries.section('locations').type('bars').all() %}
{% set restaurants = craft.entries.section('locations').type('restaurants').all() %}

{# Create a dynamic map (with no markers) #}
{% set map = googleMaps.map() %}

{# Add all bar markers #}
{% do map.markers(bars, {
    'icon': '/images/bar-icon.png'
}) %}

{# Add all restaurant markers #}
{% do map.markers(restaurants, {
    'icon': '/images/restaurant-icon.png'
}) %}

{# Display map #}
{{ map.tag() }}


How do I group matrix blocks into batches of 4? I am building a site which uses one content type as its primary holder for content. This is to make content editing easier on the content editor.

All URL's are primarily accessing this one content type, 'events'.

Within 'events' I have a matrix field 'authors'. Authors contains 1 block (also 'authors') with 4 fields, Name, Image, Bio and URL.

I am able to output the matrix blocks fine, but I am not familiar with a way to call all event entries without running them through a for loop first. Doing so causes my row/col layout to break but without batching them into groups of 4, my column layout also breaks.

I have attempted all solutions shown on stackexchange but none of them are suited for this scenario (calling all entries from a section) and my attempts at rewriting it to fit my solution has failed. Any help would be greatly appreciated.

{% for event in events %} {# loop through all events #}
    {% if event.startDate|date('Y') == now|date('Y') %} {#check to see if the event's start date is happening this year #}
        {% for row in event.authors|batch(4) %} {# use batch to create rows #}

                {% for block in row %}
                    {% switch block.type %}
                        {% case "author" %}

                                {% set image = block.image.first() %}
                                    {% if image|length %}

                                     {% endif %}

{{ block.authorName }}

                                {% if block.twitterHandle|length %}

@{{ block.twitterHandle }}

                                {% endif %}
                                 {{ event.startDate|date('m/d/y') }} @ {{ event.startDate|date('g:ia') }}

{{ block.bio }}

                    {% endswitch %}
                {% endfor %}

        {% endfor %}
    {% endif %}
{% endfor %}

This is as close as I've gotten, but unfortunately this just creates rows for each entry as opposed to every 4 blocks.

You could use your own variable to count the matrix blocks in your loop. The code could look like this:

{% set rows = 0 %}

    {% for event in events %} {# loop through all events #}
        {% if event.startDate|date('Y') == now|date('Y') %} {#check to see if the event's start date is happening this year #}
            {% for row in event.authors %}
                    {% for block in row %}
                        {% switch block.type %}
                            {% case "author" %}

                                {% if rows == 4 %}

                                    {% set rows = 0 %}
                                {% endif %}

                                    {% set image = block.image.first() %}
                                        {% if image|length %}

                                         {% endif %}

{{ block.authorName }}

                                    {% if block.twitterHandle|length %}

@{{ block.twitterHandle }}

                                    {% endif %}
                                     {{ event.startDate|date('m/d/y') }} @ {{ event.startDate|date('g:ia') }}

{{ block.bio }}

                               {% set rows = rows + 1 %}

                        {% endswitch %}
                    {% endfor %}
            {% endfor %}
        {% endif %}
    {% endfor %}

It's important to set the variable outside the for loop, otherwise it does not work.


Access entry content in _layout.html I have some content I wish to output in the main parent _layout.html template. Seems like something simple to achieve but can't seem to figure it out. If I call {{ entry.bannerLabel }} etc it throws twig runtime errors.

I'm wondering if it's because it's outside of the {% block content %} section of the template?

My bad. Total n00b error. Made the content a global so it can exist outside of specific template and solved it


How do I change a user's password programmatically in a plugin? I'm new to Craft and (attempting to) create a plugin so that I can import existing users from CSV.

I'm referencing this method:

https://docs.craftcms.com/api/v2/craft-usersservice.html#method-changepassword

In my function, I'm using the following code:

$user = craft()->users->getUserById(6);
$user->newPassword('mynewpassword123');
craft()->users->changePassword($user);
craft()->users->saveUser($user);

Am I completely misunderstanding what this is supposed to do?

You shouldn't need to call changePassword() at all.  Try this:

$user = craft()->users->getUserById(6);
$user->newPassword = 'mynewpassword123';
craft()->users->saveUser($user);

If it's not updating correctly, then there is likely a validation error somewhere.  You can check that with:

$user->getErrors();

Which will return an array of properties that failed validation and their error messages.


Element API -- getting table data from a matrix I'm using element API to pull JSON, and I have it working pretty well with a matrix field, but I need to pull a single column out of a table field inside of the matrix, and I don't even know where to start.

We're using this as a headless way to pull data into a game, and I need to pull the flavor text, and just have it output one field in the table, not everything.

'api/locations/<slug:{slug}>.json' => function($slug) {
        return [
            'elementType' => Entry::class,
            'criteria' => ['section' => 'locations', 'slug' => $slug],
            'pretty' => true,
            'one' => true,
            'transformer' => function (craft\elements\Entry $entry) {
                $bodyBlocks = [];
                foreach ($entry->dataMatrix as $block) {
                    switch ($block->type->handle) {
                        case 'theData':
                            $bodyBlocks[] = [
                                'zone' => $block->zone,
                                'zoneName' => $block->zoneName,
                                'alternateZone' => $block->alternateZone,
                                'zoneBanner' => $block->zoneBanner,
                                'backgroundAsset' => $block->backgroundAsset,
                                'propAsset' => $block->propAsset,
                                'flavorText' => $block->flavorText,
                            ];
                            break;
                    }
                }
                return [
                    'data' => $bodyBlocks,
                ];
            }
        ];
    },

This is currently giving me this output for the table field:

"flavorText": [
            {
                "col1": "1",
                "col2": "Arbitrary flavor text here",
                "col3": "",
                "title": "1",
                "text": "Arbitrary flavor text here",
                "icon": ""
            }
        ]

All I want is the stuff in the 'text' field, nothing else. There is no documentation anywhere on how to deal with Table Fields in the Element API, much less how to do it within a matrix. I'm also not sure how to loop through fields inside of a matrix that require loops to pull the data normally.

Anyone have any idea how I can get this output?

The table field contains an array of all columns, I don't really see where you problem is since you could just do data[0].flavorText[0].text in your template and as you already explained you can see the direct output so you can just address the index in the array.

$block->flavorText[0]->text

will return you the text within the first column

In order to get the values from all columns you'll have to loop through them

$values = [];
foreach($block->flavorText as $column){
    $values[] = $column['text'];
}


Front End Asset Management - Upload New Photos without Deleting/Overriding Existing I'm trying to create a front end system where users can create and manage listings with multiple photos. Everything saves as a draft until approved by an admin.

In the front end edit page, uploading multiple assets works and I'm able to display those assets to the user from their draft. However, when trying to upload additional assets, the existing ones are 'removed' and replaced by the new uploads.

I've tried just about everything I can think of and searched through a ton of documentation but haven't figured out how to make it work.

Here's what I have so far:

<form method="post" accept-charset="UTF-8" enctype="multipart/form-data">
    {{ getCsrfInput() }}
    <input type="hidden" name="action" value="entryRevisions/saveDraft">
    <input type="hidden" name="redirect" value="...">
    <input type="hidden" name="sectionId" value="...">
    {% if drafts %}
        <input type="hidden" name="draftId" value="{{ entry.draftId }}">
    {% endif %}
    <input type="hidden" name="entryId" value="...">
    <input type="hidden" name="enabled" value="1">

...

    {% if entry.photos|length %}
    {% for photo in entry.photos %}

Here is where I think something should be happening to save existing photos...

    {% endfor %}
    <input type="file" id="photos" name="fields[photos][]" class="upload" multiple>
    {% else %}
    <input type="file" id="photos" name="fields[photos][]" class="upload" multiple>
    {% endif %}

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

I'd also like to be able to display the existing photos and give users the option to manually remove photos they've already uploaded, but that's step 2. Need to get past this point first. Any help or links to appropriate documentation would be much appreciated. Thanks!

You're right that your template needs some adjustments. Whenever you're saving an Assets field, you need to have all of the Asset id's not just the new ones. You're looking for something like

{% if entry.photos|length %}
    {% for photo in entry.photos %}
        <input type="hidden" name="fields[photos][]" value="{{ photo.id }}" />
    {% endfor %}
{% endif %}

<input type="file" id="photos" name="fields[photos][]" class="upload" multiple>


Where are the E-Mail Templates? Am I completely stupid or have the e-mail settings been removed after an update?
I am searching for the text E-Mails they are sent if a new User is created, someone has his Passwort forgotten and so on… I am really sure that i saw this already but where?

Thanks for any help!

These were moved to "Utilities" so they now have their own permission and users can have access to them without needing be have admin rights.


Why am I getting "Variable "entry" does not exist" This seems random to me, as it was not a problem until today...

I am getting the template error Variable "entry" does not exist with a reference to line06 below.

This is a template for social icons that I include on each page.

The code template below is included in my site template.  It works on the index page, but it works no where else other than an actual entry (post) page.

You can provide some fallbacks for pages that don't have en entry like this

{{entry.title|default('here is your fallback')}}

You can do this multiple times, chaining fallbacks. Inside the fallback you can provide a global or maybe set a page at the top of your template like this:

{% set entryFallback = craft.entries.id(1).first() %}
{{entryFallback.title}}

Edit

In your specific case where you just want to return the url from the page you are on to create a twitter share button, you can just get the current Url:


Store a redirect URI for use after login I need to pass the current page's URI into either the HTTP headers or as a URL query string so that after being taken to the login page and successfully logging in, the user will be sent back to where they came from.

I think that by attaching a query to any login button around the site I can then tell the login page where to go. The Login button is part of many of my templates / partials show when conditionally displaying content depending on if user is logged in.

By using <a href="members/login?p={% craft.request.path %}">

For example I thought that:

{% if craft.request.getQuery('p') and craft.request.getQuery('p')|length %}
    {% set p = craft.request('p') %}
{% else %}
    {% set p = '/' %}
{% endif %}

would set me up to redirect if the url contains http://craft.fira/members/login?p=/members/directory/json. However that results in a 404. Is there a safe way to pass a path into a url query?

Secondly, I then need to know how to deal with this after logging in successfully.

All help greatly appreciated, thank you!

First – your Twig syntax is a little off. Here's how you could add the current URL/request path to a link, as a query parameter p:

Log in

Notice that the syntax/tag for printing a value/variable is {{ value }}, not {% value %}.

Second, since the redirect in this case should happen when the login form is successfully submitted, it makes sense to add the redirect URL to the form as a redirect input:

<input type="hidden" name="redirect" value="{{ craft.request.getQuery('p')|default('/') }}" />

Note that craft.request should be all lowercase; in Craft almost all variables or service names follow the camelCase naming convention (the craft.request variable refers to the HttpRequestVariable class, which wraps the HttpRequestService).

Additionally, the above example demonstrates use of the default filter, which will print the declared value (in this case, /) if the value preceding the default statement is null or false. In this case, using default will save you an if statements and several lines of code.

Finally, if you want to do a (conditional) redirect outside of a form submission, you can make use of Twig's redirect tag:

{% set redirectUrl = craft.request.getQuery('p') %}
{% if redirectUrl %}
    {% redirect redirectUrl %}
{% endif %}


How to get asset URL from field in template I'm new to Craft and having a very hard time calling the URL from a field I created called imagePrimary

I've read this extensively but still no luck. https://craftcms.com/docs/assets-fields

{% include 'header.html' %}

{% block content %}

{% for entry in craft.entries.section('projects').limit(500).find() %}

{{ entry.studio }}{{ entry.title }}

{% endfor %}

{% endblock %}

{% include 'footer.html' %}

Hey Jeremy give this a shot to see if it works (from craft.assets)

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

If this doesn't clear it up, I'd double check the field Handle to make sure it's spelled correctly and there is an image within one of your entries.


Return entries with startDate or endDate within a calendar year I have two date fields in my entry and I want to return those entries with either a start date OR and end date within a calendar year.

I can get those with a startDate within the calendar year using:

{% set nextyear = year +1 %}
{% set yearbegins = '1 January ' ~ year %}
{% set yearends = '1 January' ~ nextyear %}
{% set unixbegins = yearbegins | date("U") %}
{% set unixends = yearends | date("U") %}

{% set entries = craft.entries.section('events').limit(null).startDate('and', '>= ' ~ unixbegins, '< ' ~ unixends) %}

How to I then run a test on endDate to further filter them down?

You could do two queries to get the Ids of the desired entries, merge the Ids and then query the entries with these Ids:

{# Get Ids of desired entries #}
{% set startDateIds = craft.entries.startDate('and', '>= ' ~ unixbegins, '< ' ~ unixends).ids() %}
{% set endDateIds = craft.entries.endDate('and', '>= ' ~ unixbegins, '< ' ~ unixends).ids() %}

{# Merge queried Ids #}
{% set filteredIds = startDateIds|merge(endDateIds) %}

{# Get entries with Id paramenter #}
{% set filteredEntries = craft.entries.id(filteredIds) %}

.

Another idea is to query all potential entries, loop those and filter within the loop. This is probably the way to go if you need to combine your conditionals with other logic then the and operator:

{# Get all potential entries #}
{% set allEntries = craft.entries.section('events').limit(null).find() %}

{# Define array before loop #}
{% set filteredEntries = {} %}

{# Loop all entries #}
{% for key, entry in allEntries %}

    {# Set conditionals to filter for desired entries #}
    {% if ( entry.startDate >= unixbegins and entry.startDate < unixends ) and ( entry.endDate >= unixbegins and entry.endDate < unixends ) %}

        {# Merge entries #}
        {% set filteredEntries = filteredEntries|merge({ (key): entry }) %}
    {% endif %}

{% endfor %}


Plugins page inside CP Settings not working I get an error when trying to access CP/Settings/Plugins:

Fatal error: Class 'Craft\PluginVariable' not found in folderpath/craft/app/variables/PluginsVariable.php on line 47

Any Ideas?

Sounds like an FTP upload or an unzipping operation didn't finish properly.

Try downloading a fresh copy of Craft from http://buildwithcraft.com and replacing the old craft/app folder with the new one.


Change profile in frontend with ajax I'm trying to update some checkbox fields through the frontend with ajax.
After clicking / change of the checkbox the form needs to update the profile.

Template code:

<form class="form-horizontal form-ajax" method="POST" action="" accept-charset="UTF-8" id="notificaties">
{{ getCsrfInput() }}
<input type="hidden" name="action" value="/users/saveUser">
<input type="hidden" name="redirect_" value="account">
<input type="hidden" name="userId" value="{{ user.id }}">

            Ontvang updates over leuke nieuwe producten

                <input type="hidden" name="fields[emailUpdates]" value="0">
                <input class="ajaxcheck" type="checkbox" id="fields_emailUpdates" name="fields[emailUpdates]" value="1" {% if user is defined and user.emailUpdates %} checked="checked"{% endif %}>

            Ontvang email updates over geinteresseerde kopers

                <input type="hidden" name="fields[emailReactie]" value="0">
                <input class="ajaxcheck" type="checkbox" id="fields_emailReactie" name="fields[emailReactie]" value="1" {% if user is defined and user.emailReactie %} checked="checked"{% endif %}>

            Ontvang wekelijks een upate over de producten van jou favoriete verkopers

                <input type="hidden" name="fields[emailFavorieten]" value="0">
                <input class="ajaxcheck" type="checkbox" id="fields_emailFavorieten" name="fields[emailFavorieten]" value="1" {% if user is defined and user.emailFavorieten %} checked="checked"{% endif %}>

            Ontvang email updates van de reacties van jou producten

                <input type="hidden" name="fields[emailComments]" value="0">
                <input class="ajaxcheck" type="checkbox" id="fields_emailComments" name="fields[emailComments]" value="1" {% if user is defined and user.emailComments %} checked="checked"{% endif %}>

 </form>

JS code:

 $(".ajaxcheck").click(function(){
    var data = $(this).parents('form').serialize()

    $.ajax({
        context: this,
        method: "POST",
        dataType: "json",
        url: "/actions/users/saveUser",
        success: function(data, response){
            $(this).parents('.account-item').remove();
            console.log("success", response, data);
        }
    });
});

But it gives me an error: GET http://shop.craft.dev/actions/users/saveUser 400 (Bad Request)

The form gets updated. So it works. But it still gives me this error:

In my craft.log file:

exception.Craft\HttpException.400
Message exception 'Craft\HttpException' in /Volumes/HDD Drive/Sites/Shop/app/controllers/BaseController.php:191

The 400 error you’re getting is coming from BaseController::requirePostRequest(). It’s happening because this line:

type: "post",

should be:

method: "POST",


Image transform with either width or height I'm looking to create an image transformation where either the height is (e.g.) 180px, or the width is 180px depending on whether the image is portrait or landscape.

So, if the image is landscape the dimensions should be (WxH): 180 x AUTO
If the Image is portrait, the dimensions should be (WxH): AUTO x 180

Maybe I'm missing something obvious. Or maybe this could be a CSS issue?

Thanks!

A similar question has already been asked here: Is there a way to find out if images (assets) are landscape or portrait?

You will need to create the two asset transforms you mentioned in your question, and then in your template code use an if/else statement to determine which transform to use, depending on if the asset is portrait or landscape.

Thanks to Josh for the code, this is taken from his answer:

{% set myImage = entry.imagesField.first %}

{% if myImage.getWidth() < myImage.getHeight() %}
  {# portrait #}
{% elseif myImage.getWidth() > myImage.getHeight() %}
  {# landscape #}
{% else %}
  {# square #}
{% endif %}


Craft 3 Call Own Service I created a plugin for Craft 3 at pluginfactory.io.

I want to call it in my template variable

public function exampleVariable()
{

    // hint   AdminBar::$plugin->editLinks->exampleService()
    //$result = FacebookPageConnector::$plugin->eventsService->fetchEvents();
      $result =  FacebookPageConnector::$plugin->facebookPageConnectorEventsService->exampleService();

    //$result = FacebookPageConnector::$plugin->eventsService->fetchEvents();
    return $result;
}

But whatever I try to name my service, I get an exception like this:

  Getting unknown property: boscho87fbconnector\facebookpageconnector\FacebookPageConnector::facebookPageConnectorEventsService

What are the correct naming conventions?

I saw an example here: https://github.com/wbrowar/craft-3-adminbar/blob/master/src/services/EditLinks.php#L48,  but this did not work for me.

But when I call the predefined service from the pluginfactory: FacebookPageConnector::$plugin->facebookPageConnectorService->exampleService(),  it works fine .

here images with my code

In your plugin's composer.json, add the service to extra.components to make it available on the plugin instance. You should see the predefined service already listed there.

You might need to empty the vendor folder of your craft website and reinstall your composer dependencies as Craft appears to cache this information.


Another AJAX CSRF question I have quite a simple registration form, something like this:

    <form id="registerUser" method="post" accept-charset="UTF-8" class="flex-stack" novalidate @submit.prevent="userFormValidation()">
                        <input type="hidden" name="action" value="users/saveUser">
                        <input type="hidden" name="redirect" value="user/registration-success">

                        {{ "Username (no spaces)"|t }} *
                        <input id="username" type="text" name="username" v-model.lazy.trim="user.userDetails.userName" :class="{ 'error-field': usernameHasError }" required>
    </form>

It gets passed to VueJS (which works). There I have the default code I find in every AJAX post on Craft StackExchange:

var data = $('#registerUser').serializeArray();

            //--- Add CSRF token to data
            data[window.csrfTokenName] = window.csrfTokenValue;

            $.ajax({
                type: "POST",
                data: data,
                url: "",
                success: function(data, response){
                    console.log("success", response, data);
                },
                error: function(response) {
                    console.log("error", response);
                }
            });

This works when the CSRF is disabled in the config, but when enabled, I always get a bad request, CSRF token invalid error.

What am I doing wrong here? There's no Craft caching going on.

Thanks to Robin Schambach. The answer was as simple as serialize the form data with the CSRF in there already by using the default {{ getCsrfInput() }}

  serializeArray won't produce data in a way Craft CMS will proceed it.
  It's not a good idea to do that. Besides that why don't you include
  the token in your form from the beginning? Because this is never the
  default code you can find in every ajax request – Robin Schambach 14
  hours ago


Element API return a type of Category I'm just wondering when it comes to Element API is there a way of returning a type of Category.

I'm returning all the other information fine.

'fees.json' => [
    'elementType' => 'Entry',
        'criteria' => [
            'title' => craft()->request->getQuery('title'),
            'section' => 'fees',
        ],
        'transformer' => function(EntryModel $entry) {
            foreach ($entry->fee as $block) {
                $matrixSections[] = [
                    'first' => $block->firstInstallment,
                    'second' => $block->secondInstallment,
                    'full' => $block->full,
                    'grant' => $block->feeCategory
                ];
            }
        return [
            'title' => $entry->title,
            'menu' => [
                'sections' => $matrixSections
            ]
        ];
    }
]

The Element API plugin returns JSON, so you'll need to be specific about what you want to return for your categories – i.e. you can't return a CategoryModel (or an array of CategoryModels) in full directly from a Categories field.

The easiest option is to use array_map() like this:

'first' => $block->firstInstallment,
'second' => $block->secondInstallment,
'full' => $block->full,
'grant' => array_map(function (CategoryModel $category) {
    return [
        'id' => $category->id,
        'title' => $category->title,
    ];
}, $block->categoriesField->find()),

Of course, if your individual category has a lot of fields, you can always create an external function in your elementapi.php file and use that for the array_map call, instead of inlining the function (the external function needs to live above the return ['endpoints']... part):

function getCategoryData(CategoryModel $category)
{
    return [
        'id' => $category->id,
        'title' => $category->title,
        ...
    ];
}

...

'grant' => array_map('getCategoryData', $block->categoriesField->find()),

Also, there's the $category->getAttributes() method which can be handy if you want to return all stock attributes (i.e. id, dateUpdated etc – pretty much everything sans the title, for some reason):

function getCategoryData(CategoryModel $category)
{
    return array_merge($category->getAttributes(), [
        'title' => $category->title,
        'someCustomField' => $category->someCustomField,
    ];
}


How do I store code in Craft I need to store Javascript/HTML code in some of our entries. I have tried to put the code in plaintext but cannot get the code to render through twig. I cannot store this stuff on the filesystem. It really needs to be attached to an entry if possible.

Any ideas?

Store it in a plaintext field, then when you output it, do: {{ entry.myfield | raw }}


Icons not loading in admin In some instances of my websites the icons don't load properly.  Everything else in the website works, but the icons don't load.  The other websites on the same server with the same php.ini file don't have this issue, just this one website.

I've had that happen before and it was just a matter of refreshing the page a few times to clear it up. If that doesn't work try clearing the control panel resources cache (or just deleting the cpresources folder from your webroot).


Why would getEntryTableAttributeHtml(EntryModel $entry, $attribute) not return proper labels? I have getEntryTableAttributeHtml(EntryModel $entry, $attribute) setup in my plugin file.  I have attributes defined in defineAdditionalEntryTableAttributes().  However when the page loads $attribute returns field:85 instead of one of the expected labels. Why might this occur?

I did a little digging in the source, and here's what's going on:

When Craft builds an element index, it pulls all available element attributes from the ElementIndexesService, where the method getAvailableTableAttributes adds all custom fields to the available attributes, with keys 'field:'.$field->id.

The ElementIndexesService class was added in Craft 2.5.2750, when a lot of things changed related to element indexes (this is when the Customizable Element Indexes feature was added).

Before 2.5, things worked differently – custom attributes weren't "pre-fetched" by Craft, but had to be added manually using the modifyEntryTableAttributes hook, where the $attribute variable passed to getEntryTableAttributeHtml would be a custom field handle, not the current field:{fieldId} value.

It's unfortunate that the official docs for getEntryTableAttributeHtml appear to not having been updated since Craft 2.4, as its current example code won't actually work (for custom fields) since 2.5.

Either way, here's a workaround which should make things a little bit easier in customizing the HTML for custom field attributes:

public function getEntryTableAttributeHtml(EntryModel $entry, $attribute)
{

    // If custom field, get field handle
    if (strncmp($attribute, 'field:', 6) === 0)
    {
        $fieldId = substr($attribute, 6);
        $field = craft()->fields->getFieldById($fieldId);
        $attribute = $field->handle;
    }

    // Get html by attribute (field handle)
    switch ($attribute)
    {
        case 'customFieldHandle' :
            return '<span>'.$entry->$attribute.'</span>';
            break;
    }

}


Where are tags stored in the database? Seeing as there currently isn't a way of deleting / managing tags in Craft3, I was wondering if someone could point me to where in the database these tags are stored so I can delete them manually.

Thanks in advance :)

edit:
Looks like tag management through the CMS is also on the agenda for version 3 as seen in this git issue.

https://github.com/craftcms/cms/issues/820

Tags are Elements and are stored in multiple places in the database, so editing the db directly may not be as easy as just finding the Tags you want and deleting them.

The tag itself is stored in multiple places including the tables:

content
elements
elements_sites
tags

You'll find the Tag Name that you recognize in the content table in the title column. However, the only way to delete the references to a given tag in all of the tables would be to delete it by it's Element ID in the elements table, which would cascade through the other tables and clean them up as well.

Quite possible to do via the db directly, but probably not advisable or convenient in many situations. Be sure to backup your database before you try, if you dare.

In the case this must be done manually, you could consider the following steps:

Export all tags from the db into a CSV file. Select all the ones you wish to delete. Use your spreadsheet to combine all the Element IDs of the tags you want to delete into a comma-delimited list. Then return to your database program and delete all the Tags by their Element IDs:

DELETE FROM elements
WHERE id IN (1, 3, 5, 7, 9);


Commerce Custom Shipping Methods via Plugin I'm looking to add additional shipping methods through a plugin, using the documentation here: https://craftcommerce.com/docs/shipping-methods

I'm a little bit lost about how to hook things up, according to the docs I'm supposed to do:

public function commerce_registerShippingMethods()
{
    return [new CustomShipper_CourierDeliveryMethod()];
}

The docs don't really cover where and how to do this, other than to include it in the base plugin file. That part I can follow. Could someone help me understand what file to create, the basics of what it should include and how to connect it (referring to new CustomShipper_CourierDeliveryMethod())?

This is new to me for Craft Plugin development - I'm used to connecting to files using something like:

return [craft()->pluginHandle_serviceName->function_name()];

Which obviously is very differently than the above. Any help would be HUGELY appreciated.. thanks!

Ok, so what you're doing is returning a new instance of a shipping method class - this class must meet the Shipping Method interface - documented here: https://craftcommerce.com/docs/shipping-methods#shipping-method-interface

That is, you must implement each of those functions as defined by the interface in your shipping method class.

You'd define this class in a file of it's own named after the class, and in your base plugin file you require this class definition to bring it in to scope.

The same goes for your shipping rules - you again create a class that meets the interface and then require that in your main plugin file (or wherever you need to access the rule).


multi-select OR values to filter entries preface: i'm new to craft so may get terminology incorrect

basic idea: i would like to show entries of a particular channel which have multi-select field values which intersect with another set of values. e.g. given set ['a','c','e'] it would show entries with values such as ['a','b',c'] and ['e'] but not ['b','d'].

what i have done so far:

my basic ElementCriteriaModel for entries in the past is defined:

{% set results = craft.entries({
    section: ['mysection'],
    when: ' <= ' ~ now,
    order: 'when desc',
}) %}

{% for entry in results %}
.... blah blah do stuff

and what i would like to do is add another criteria on there for the multi-select field. however, from what i am reading and have tried it doesn't seem like that kind of filtering is available. please stop now and prove me wrong if this is not the case!

i was able to filter matching a single option of the multi-select by using:

{% for entry in results if entry.myMultiSelect.contains('a') %}

but was unable to determine syntax to "OR" the results with another contains(). really not much documentation that i could find on that method.

alternately i possibly could use a search, but sounds like that relies on indexes that may get out of date which i would like to avoid. wouldn't be a huge deal, but looking for the "right" answer before i settle on brute forcing it by just looping through the multi-select values inside the loop to check for a match.

Not an expert myself, but you can try .contains('OR', 'a', 'b', 'c', 'e')

However, rather than first fetch all entries and then filter them, I would look into using relations when looking them up, so that the initial result only contains the entries you're after.

Have a look at https://craftcms.com/docs/relations to get started, and don't be afraid to ask for help if you can't quite figure them out (I found them a little tricky myself when first attempting to use them).


Can you get the baseUrl for site by handle or id? I am making a super simple language switcher. And I was wondering if there is a way to get the baseUrl for a site by id or handle, something like this:

DEDeutsch

What I'm trying to avoid doing is:

DEDeutsch

Or is that just how to you do?

{% set site = craft.app.getSites().getSiteById(1) %}
{% set site = craft.app.getSites().getSiteByHandle('handle') %}
{{ site.baseUrl }}

But I would rather suggest you to grab the entries URL for a certain site in your language switcher

{% set entryInOtherSite = craft.entries.id(entry.id).siteId(2).one() %}
{{ entry.getUrl() }}

I'm not sure why you even ask this question since everything is well documented here since you "answered" that question


Handling non-image uploads when updating user photo from front-end form We have a front-end form that allows users to update their profile photo. If a user attempts to upload a non-image file, instead of the actionSaveUser controller failing and throwing an error, it gets to $this->_processUserPhoto and then throws an Exception

             {
200                 // Invalid SVG. Maybe it's missing its DTD?
201                 $svg = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>'.$svg;
202                 $this->_image = $this->_instance->load($svg);
203             }
204         }
205         else
206         {
207             $imageInfo = @getimagesize($path);
208
209             if (!is_array($imageInfo))
210             {
211                 throw new Exception(Craft::t('The file “{path}” does not appear to be an image.', array('path' => $path)));
212             }

Is there a more graceful way to handle this so I can return an error to the user instead?

Update:

As of the next (post 2.4.2702) Craft release, Craft will now return a validation error on the UserModel if a non-image is uploaded for the user's profile photo.

I consider this a bug in Craft and we've already got a ticket open to address it.

Until then, I can think of two options work work around it, either of them particularly pretty. 1. Hack core Craft files to do the detection. 2. Have some JavaScript on your upload form that detects the extension of the file they're trying to upload.


Craftnet API package query Does querying composer packages via the Craftnet API need authentication?
Ref https://docs.api.craftcms.com/packages.html
Querying the Craft CMS package itself is fine, eg https://api.craftcms.com/v1/package/craftcms/cms. However trying to query any plugins is throwing a 404, eg https://api.craftcms.com/v1/package/craftcms/contact-form

Turns out there was a bug with package names that contained -s. Just fixed that, so /v1/package/craftcms/contact-form works now.


Cache not invalidated on publishing new entry I'm using {% cache %} to cache pages, but it seems that the caches are not invalidated after posting new content, which is what I thought should happen.

I've investigated the situation and what I think is happening is this:

Post a new entry
Caches are then deleted (this process takes a looong time: I noticed that templatecacheelements table was up to something like 450,000 rows)
The page in question is accessed by a visitor while the cache is being invalidated, and so the template is cached again before it has been purged

Because Craft doesn't know about the access to the template during emptying of the caches, I suppose it never will until the cache is purged manually.

Is there anything I can do to improve this situation?

Not the answer you'd be hoping for but the advice I got was to create a plugin to listen and clear the cache when a new entry was published https://twitter.com/craftcms/status/541968671300911104


Craft 3 RC Upgrade killed the WYSIWYG Editor I just finished upgrading to Craft 3 RC and all text on the site is gone. The WYSIWYG Editor has been replaced with this message:

Unable to find component class 'craft\fields\RichText'.

What can I do?

With RC1 the rich text editor was moved to a plugin. You can find the Redactor editor (the previous richtext field) in the plugin store along with a new CKEditor editor as well.

You can read about this in the docs, too: https://docs.craftcms.com/v3/changes-in-craft-3.html#rich-text-fields


Custom redactor.css file I would like to override or include a custom redactor.css file so that I can match the typography of the rich text editor contents with the site's stylesheet.

The path to redactor.css is hard-coded into the application (craft/app/fieldtypes/RichTextFieldType.php - line 281), and obviously I don't want to change this file or the redactor.css file.

Is there at least a way to inject a custom css file into the admin pages so that the core/base styles can be overridden?

UPDATE: Both plugin solutions below worked, but because craft includes redactor.css after the plugin's css include is inserted, the trick is to make your css selectors more specific, i.e.:

.redactor_.redactor_editor h1 { font-size: 48px !important; }

You can override the control panel's CSS with a plugin. Use the popular "Control Panel CSS plugin" by Lindsey DiLoreto or make your own little one.

Make use of the includeCssResource() function and include a CSS file with your custom redactor styles:

myRedactorCssPlugin.php:

public function init()
{
    if (craft()->request->isCpRequest())
    {
        craft()->templates->includeCssResource('myRedactorCss/redactor.css');
    }
}

resources/redactor.css:

.redactor_editor h1 {
  font-weight: normal !important;
}
.redactor_editor p {
  background-color: #eee;
}


How do I restore a site from backup I broke permissions in a critical craft install. My solution was to install a new version of the craft, move all of the templates from the old site to the new site and restore the MySQL database.

Problem is that craft wants to run the setup installer.

Can anyone provide me a quick recipe for restoring a craft3 site from backups? I have the database and all of the assets/templates etc.

If you've copied the Craft files to a new place on the server, then you can either leave the database connection information the same and have it keep on pointing to the current database instance, or edit craft/config/db.php (or your .env file if that's how you're setup) to point to a new database instance.

If the new one is a blank database, the Craft installer will want to run.  If you want a copy of your old database on the new one, you'll need to do a database dump from the old one and restore it to the new one.  If you do the latter and you're still getting Craft to prompt to run the installer, then there is something wrong with the database connection settings between Craft/PHP and the database and those should be adjusted.


Split entries in columns I'm trying to build a feed of entries in a column grid. Something like that:

 First entry
 Fourth entry

 Second entry
 Fifth entry

 Third entry
 Sixth entry

How do I achieve that? In my head .batch(3) only works horizontally for rows.

Edit: To make it more clearly, that's my goal and the reason for columns instead of rows:

There's no easy twig function available to do this, but the code from this answer should be able to help you.

{% set columns = 3 %}
{% for entry in entries %}
    {% if loop.first or loop.index0 is divisibleby(columns) %}

    {% endif %}

    {{ entry.title }}

    {% if loop.last and loop.index is not divisibleby(columns) %}
        {% for n in range(low=columns - (loop.index % columns), high=1, step=-1) %}
            &nbsp;
        {% endfor %}
    {% endif %}

    {% if loop.last or loop.index is divisibleby(columns) %}

    {% endif %}
{% endfor %}


Printmaker Plugin — Some Questions Why he generate the PDF again and again when nothing changes? Is there a hidden option for that?
I tried to use it with the Google Font Rubik but no chance. Any Ideas?
Is it possible to Save the generated PDF in an Asset field to the Post?

I've a preparse Field at the Moment but I've nothing what I can prompt if it's exist or not. He also regenerate the PDF on every Save. No cool :/

Here is my Preparse Field

{% spaceless %}
  {% if not entry.preparsePrintmakerCertificate|length %}
    {% set html %}

        <meta http-equiv="content-type" content="text/html; charset=utf-8"/>

          {{ entry.title }}

          {{ entry.postDate.format('M') }}
          {{ entry.postDate.format('d') }}

          {{ entry.postDate.format('Y') }}

    {% endset %}

    {% set settings = {
        filename : 'bestwebsite-gallery_sotd_' ~ entry.postDate.format('Y-m-d') ~ '_' ~ entry.slug|kebab
    } %}
    {% set pdfUrl = craft.printmaker.pdfFromHtml(html, settings).url %}
    {{ pdfUrl }}
  {% endif %}
{% endspaceless %}

Unfortunately, Printmaker must regenerate the PDF on every save... It can’t simply check to see whether a certain PDF file already exists, because the underlying content or template may have changed that PDF was last generated. You can use Craft's template caching to capture PDF URLs/filenames, to avoid unnecessarily generating the PDF if you know the underlying content hasn't changed.
You can use Google Fonts (or any other external web font) by linking an external stylesheet, or by including the @font-face directive in your inline styles.
Printmaker saves PDF to files in a cache directory that you specify, but it doesn't create or update an Asset element. You could write a custom plugin to do that, leveraging Printmaker's API. Alternatively, you can commission Top Shelf Craft to develop the functionality you need.

Feel free to write support@topshelfcraft.com or post additional questions here on SE if I can be of further help!


SPA style entry rendering, SEO implications I'm working on implementing a layout that involves a listing page, that when an entry is clicked, the content slides in from the side and fills the screen.

Doing this in the style of an SPA via ajax or Vue.js is fairly straightforward, but I'm unclear on how to implement in Craft while maintaining SEO "crawlability" via something like server-side pre-rendering or such.

I'm not even sure where to start, any direction would be much appreciated!

The best solution is to create actual pages for the content that is being loaded. Not only will this help with SEO, it will act as a fallback for anyone who is not using javascript. You can link to these pages from your current links so that search engines can crawl through them, but for those with javascript you can load the content asynchronously.


Sort Entries by Value from Dropdown I have a list of students and can sort them by name, sport, and school. The name and sport portions are easy, I'm grabbing the values without issue.  Where I'm struggling is the school value is from a Dropdown field.
Using the following code results in no students being listed let alone being sorted by school.
   {% set usersSchoolQuery = craft.users().group('athlete').all() %}
   {% set usersBySchool = usersSchoolQuery|group('schoolAttended.one()') %}
   {% for users in usersBySchool.all() %}
   {% for user in users %}

This should work but isn't. Could someone see where I'm going wrong here?

Edit: I've misunderstood the question! It sounds like Schools aren't related Elements, but just a dropdown value?

I think there are a couple of missteps, here:

The .group() method on a UserQuery actually applies a filter, narrowing the results by a User Group with that handle. (Maybe that's understood, but I wanted to note the difference between this and the next couple of notes!)
(An aside that will help optimize this for #3) I recommend eager-loading your related School elements by calling .with(['schoolAttended']) on your main User query.
The | group(…) filter takes an array and groups it by a property, closure, or Twig expression. In this case, I think you actually want to be more explicit about how the grouping is happening, so I'd use | group(u => (u.schoolAttended | first).id). This ensures the key used for grouping is consistent and unique.
usersBySchool.all() is calling the .all() method on an array, which won't work (it'll only be present on ElementQuery instances)—your Elements are already loaded after the first statement, and grouping just takes the resulting array and re-organizes it! This for loop should probably just be: {% for schoolId, athletes in usersBySchool %} … {% endfor %}.

So, altogether:
{# Load all “athlete” users: #}
{% set athletes = craft.users({
  group: 'athlete',
  with: ['schoolAttended']
}).all() %}

{# Group by their School's ID: #}
{% set athletesBySchoolId = athletes | group((u) => (u.schoolAttended | first).id) %}

{# Fetch Schools and index by ID. Note that we have the IDs ready, via the grouping operation, above—we can just take the keys off that array! #}
{% set schoolsById = craft.entries({
  section: 'schools',
  indexBy: 'id',
  id: athletesBySchoolId | keys
}).all() %}

{% for schoolId, athletes in athletesBySchoolId %}
  {# Look up the school for this group via our secondary Schools query (which, again, is indexed by ID): #}
  {% set school = schoolsById[schoolId] %}

{{ school.title }}

    {% for athlete in athletes %}

{{ athlete.getFullName() }}

    {% endfor %}

{% endfor %}


Multiple actions in a form? I have two plugins that I want to use in a single form.  One is a Guest Entry plugin to save the data submitted in the form, and the other is a Plugin that sends an email notification when the form is submitted.

I want to use both of these in the same form but I'm not sure how.  If I have

<input type="hidden" name="action" value="guestEntries/saveEntry">
<input type="hidden" name="action" value="formNotification/getForm">

It won't work since both have the name "action"
and I can't change the name or the functions never get called.

What can I do to make both of them work?

It’s not possible for a form to simultaneously invoke two controller actions.

You would need to write a plugin that provides its own controller, which in turn could be used to invoke the other controller actions.

class MyPluginController
{
    public function actionSaveEntryAndSendNotification()
    {
        // Save the entry
        craft()->runController('guestEntries/saveEntry');

        // Send the notification
        craft()->runController('formNotification/getForm');
    }
}

If "FormNotificationController" is already your own custom plugin, then it might make more sense to just call craft()->runController('guestEntries/saveEntry'); from the top of actionGetForm(). Or just save the entry yourself from the controller action – the Guest Entries plugin is really pretty simple; most of the heavy lifting is provided by the EntriesService - saveEntry() API.


Enforce password change every 90 days (3 months) I am currently building an intranet for a client and one of their requirements is that staff must update their passwords every 90 days.

I assume I would need to build a plugin for this, but what would be best to way to approach this? I was hoping it might work whereby this was set 90 days after the last password change, rather than a fixed date for every user.

Thanks

$date90DaysAgo = (new \DateTime())->modify('90 days ago')->format('Y-m-d H:i:s');
foreach(\craft\elements\User::find()->lastPasswordChangeDate('<='.$date90DaysAgo)->all() as $user){
    Craft::$app->getUsers()->sendPasswordResetEmail($user);
    $user->newPassword = // generate some temp password, so the user can't login with his/her anymore
    $user->setScenario(User::SCENARIO_PASSWORD);
    Craft::$app->getElements()->saveElement($user);
}

get the date 90 days ago, find all users where lastPasswordChangeDate is smaller than this date, send them a new password reset email and change their password to something else, so they can't login anymore.


Error pages in multi site setup I have a multi site setup for supporting multiple languages in Craft 3.

'/' => German
'/en/' => English

In my general.php I have 'errorTemplatePrefix' => 'error/',

When I enter '/notexisting', my error/error.twig gets called. But when I enter '/en/notexisting', then the default Craft error message gets displayed "Page Not Found, Template not found: notexisting"

How do I get my error.twig called also for other sites?

There are several things that might be the issue in such cases, I'll list a few of them

Did you change your index.php so maybe Craft is unable to detect the current site?
Are there different index.php files in different folders in order to do the multisite setup instead of the single one? -> You should only have one for all
Do you have any plugins that might interfer and offer their custom error page / error behaviors?
Do you have any other events in your own custom plugin/module that includes a custom error handling?
Is your error template in the templates roots folder and not in a site/site group subfolder so Craft only selects it for a single site instead of globally?
Make sure dev mode is off


Restricting file size for an Assets Volume I have a use case where I want to limit the allowed file size for a certain Assets Volume to 20kb. All other volumes should be allowed files no matter the size.

I have looked at some other threads already that suggest developing a plugin to do this, or use the Yii event system for file uploads.

I have made other simple plugins before that interacted with entries, but I cannot understand how to make a plugin that latches onto the file uploading event.

Does anyone have any good documentation for where to begin with this? It is version 3.0

There's no way for the moment to limit filesize by Volume, but your can create a custom module with the EVENT_BEFORE_SAVE hooked on Assets.

Here's a related post.


Could I use categories for users instead of user groups? I'm developing a sports league site. The roles I'm setting up are admins, coaches, and players - with myself being the "super" admin.

This is my first Craft project, so right off the bat I started developing the site by distinguishing the capabilities of each role through the user groups. I'm currently having issues with registering coaches & players to their respective user groups through plugins, though.
No one other than myself will be using the Craft CP. I'll be creating their own back-end dashboard to manage their own teams, user profiles, etc...

Which leads me to the question: Should I even be designating the users to different user groups? Or just throw them into specific categories & check against those with the current logged user?

Theoretically they would have all the permissions through Craft, but I'd limit what they can accomplish through the dashboard I create for them.

If the users will never have access to the Craft CP then you can use categories or any other applicable field type (i.e. dropdown, radio buttons, tags, etc.) to create differentiation between the users. It really just depends on how accessible and/or 'static' you want the groups or sudo-groups to be. Categories and tags for example can be created dynamically, without having field editing privileges like a drop-down field would require. But since you are currently the only admin, it probably won't make much difference in the end. I would however, at a minimum create groups that differentiate between users that have different access privileges to the CP, otherwise it's totally up to you — whatever makes most sense and is easiest to manage.


Get all available fields in plugin setting page I am trying to get all the fields created by admin in my custom plugin setting page.

As we can get entries , in same way can we have option to get the available fields.

 {{ forms.elementSelectField({
    label: 'Entry Select Field',
    id: 'entries',
    name: '',
    elementType: 'craft\\elements\\Entry',
    elements: [craft.entries.one()],
    selectionLabel: 'Select an entry',

}) }}

  I tried to look in core file :/vendor/craftcms/cms/src/services/Fields.php

$fields = Craft::$app->fields->getAllFields();

But there is no such method which return the list of existing fields.

Update:

Now i am able to get the list of all the existing fields.

$fieldsData = [];

$fields = Craft::$app->fields->getAllFields();

foreach ($fields as $field)
{

    $fieldsData['name'][] = $field->name;
    $fieldsData['handle'][] = $field->handle;
}

In setting the template of plugin I want to give admin an option to select multi fields (handles ) on the plugin setting page. For this, I am trying to fetch all the created fields first and then pass that array to form micro so that it can populate the multi-select.

  But can we populate multi-select like?

{{ forms.multiselectField({
    label: 'Multi Select Field',
    name: '',
    options: {
      fields['handle']: fields['name'],
    },
    values: '',
}) }}

  Or if we create our custom multi-select fields how we can save the user ( admin) input? as in micro, it saves by itself.

The fields service does include a method getAllFields:

$fields = Craft::$app->fields->getAllFields(false);


Getting started with Craft Commerce 2 subscriptions using Stripe I’m new to Craft Commerce and am really having trouble getting started with subscriptions.

I used the example from the docs and nothing happened. When reloading the cp though, it kept telling me "Unable to start the subscription. Please check your payment details." I learned from the docs that "Subscribing a user to a plan requires that the user have a stored payment source." So I added the getPaymentFormHtml bit. Without any success. Not to mention error messages of any kind.

This is my template so far:

{% for item in craft.session.getFlashes() %}

{{item}}

{% endfor %}

{% set plans = craft.commerce.getPlans().getAllPlans() %}

<form method="POST">
    <input type="hidden" name="action" value="commerce/subscriptions/subscribe">

    {{ csrfInput() }}

        {% for plan in plans %}
            <input type="hidden" name="planUid" value="{{ plan.uid|hash }}"/>

            {# Display only if the user does not have a payment soure saved #}
            {{ plan.getGateway().getPaymentFormHtml({})|raw }}

        {% endfor %}

    <button type="submit">{{ "Subscribe"|t('commerce') }}</button>
</form>

I’ve set up a subscription in the cp, added store information and tried a valid testing card from the stripe docs. But even then it keeps giving me the above flash notice.

Could anybody shed some light here? Am I missing anything obvious?

So I had trouble with the demo's also. But if you head into the Craft Demo Store Templates you will find the following demo page you can use. Here's what I used to get it working.

{% set plans = craft.commerce.getPlans().getAllPlans() %}

{% if currentUser and plans|length%}
    {% for plan in plans %}

{{ plan.name }}

                {% set information = plan.getInformation() %}

                {% set subscriptions = plan.getActiveUserSubscriptions(currentUser.id) %}
                {% if subscriptions|length == 0 %}

You have no subscriptions to this plan.

                {% endif %}
                {% if subscriptions|length > 1 %}

You have multiple subscriptions to this plan.

                {% endif %}
                {% for subscription in subscriptions %}
                    {% if subscription.isCanceled %}
                        Your subscription was canceled on {{ subscription.dateCanceled|date('Y-m-d') }} and will expire on {{ subscription.nextPaymentDate|date('Y-m-d') }}
                    {% else %}
                        You are subscribed and your next payment is due on {{ subscription.nextPaymentDate|date('Y-m-d') }}
                    {% endif %}

                    Manage subscription

                {% endfor %}

        {% if loop.last %}

        {% endif %}
    {% endfor %}

Available plans

            {% for plan in plans %}
                <form method="POST">
                    <input type="hidden" name="action" value="commerce/subscriptions/subscribe">
                    <input type="hidden" name="planUid" value="{{ plan.uid|hash }}">
                    {{ redirectInput('shop/services') }}
                    {{ csrfInput() }}

{{ plan.name }}

                    <select name="trialDays" data-plan="{{ plan.id }}">
                        {% for i in [0, 3, 7, 14] %}
                            {% if i == 0 %}
                                <option value="{{ (plan.uid~':0')|hash}}">No trial period.</option>
                            {% else %}
                                <option value="{{ (plan.uid~':'~i)|hash  }}">Trial for {{ i }} days</option>
                            {% endif %}
                        {% endfor %}
                    </select>

                    {% set paymentSources = craft.commerce.getPaymentSources().getAllGatewayPaymentSourcesByUserId(plan.gateway.id, currentUser.id ?? null) %}

                    {% if not paymentSources|length %}

                            {{ plan.gateway.getPaymentFormHtml({})|raw }}

                    {% endif %}

                    <button type="submit">{{ "Subscribe"|t }}</button>
                </form>
            {% endfor %}

{% endif %}


Download images uploaded in backend with Sprout Form Plugin I'm using sprouts form for craft and I built a form with a file upload field. It works fine but the problem is that in the backend form entries, I can only see the uploaded image as a thumbnail (img attached).

Is there anyway to download the image from the backend? or at list get the link to open it with the browser in full size?

Here's a plugin that will add Download (well, open in new tab) links to files in the Assets fields when editing entries.

AssetLinks


Query returns nothing on matrixBlock I'm a bit confused by the way that Craft now handles Matrix blocks. I've read the documentation a few times and I'm still not sure if I have it.

Here's what I have:

{% set myMatrixBlockQuery = craft.matrixBlocks().ownerId(4).type('block__artists') %}
{% set matrixBlocks = myMatrixBlockQuery.all() %}
{% for block in matrixBlocks %}
  <li>{{ block.id }} / {{ block.artistName }}</li>
{% endfor %}

But all that gets output is:

8 /
9 /
10 /

Where 10 (etc) is the ID of the block. It's not outputting the artistName despite that field existing and having content. Is my query wrong?

I think you need to add the fieldId() param to your query as per https://github.com/craftcms/cms/issues/1789


Entry translation differences Craft 2 and Craft 3 In the middle of a Craft 3 build and the client has requested locales like their Craft 2 multilingual site. I am confused by Craft 3 localisation.
It appears I have to add a site as a language before I can localise/translate any content?

In Craft 2 the adding of translated content could be done directly in the entry via the panel above the slug field - here all the locales for Craft 2 would appear. (On the right in desktop use)

But despite options of Translation method, site, group, language the old method of swapping between entry content language within the entry on the right hand panel is not there. This makes it difficult to see / swap to what has been translated.  It appears changing language is done in the list view of entries. Am I missing something :( ?

Here is a shot of Craft 2:

Here is a shot of Craft 3:

It appears I have to add a site as a language before I can localise/translate any content?

Yes. If you want to add a new language, you have to add a new site in Craft 3.

  It appears changing language is done in the list view of entries.

Changing the language is a matter of changing the site, which is done via the site dropdown in your 2nd screenshot.

Relevant docs:

https://docs.craftcms.com/v3/sites.html

https://docs.craftcms.com/v3/localization.html

If you have suggestions for enhancements/improvements, feel free to share them here: https://github.com/craftcms/cms/issues


Front-end entry field validation problem I have this simple code:

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

    <input type="hidden" name="action" value="entries/saveEntry">
    <input type="hidden" name="redirect" value="services/{slug}">
    <input type="hidden" name="sectionId" value="3">
    <input type="hidden" name="enabled" value="1">

    Service <input type="text" name="fields[service]">

    {# Entry field (required) #}
    Client <input type="text" name="fields[client][]">

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

</form>

{% if entry is defined %}

{{ dump(entry.getErrors()) }}

{% endif %}

The client field is set as required.

Submitting the form with empty client field I get no validation error but a CDbException.

If I remove the line with the client input field I get a validation error as expected:

  array(1) {   ["client"]=>   array(1) {
      [0]=>
      string(23) "Client cannot be blank."   } }

What am I missing?
How can I validate entry fields?

You'll need to make sure the entries title is set otherwise that will throw an error. You can do this using a field in your form or set it in the Control Panel to automatically be set using another field.

Currently you are setting the client field to save using an array with [client][] but the form input is set to text which only provides string values.

This means that when you leave the field blank it uses an empty array as it's value ( [""] ) hence why you don't get the required validation error.

If you want to provide an array of clients you'd need to use a different input type and also make sure that your client fieldType is set to something that can store arrays.

Code suggestion:

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

  <input type="hidden" name="action" value="entries/saveEntry">
  <input type="hidden" name="redirect" value="services/{slug}">
  <input type="hidden" name="sectionId" value="3">
  <input type="hidden" name="enabled" value="1">

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

  Service
  <input type="text" name="fields[service]">

  Client
  <input type="text" name="fields[client]">

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

{% if entry is defined %}

{{ dump(entry.getErrors()) }}

{% endif %}


Stripe Bitcoin Support for Craft Commerce Curious if anyone knows how we would setup Bitcoin support for Craft Commerce.

We know how to handle it on the user and Stripe site to enable the checkout but will we need a custom payment handler on the PHP side to handle the responses or will the built in Stripe support work the same way?

Not necessarily Craft Commerce per se, but you could use Charge 2 to integrate with Stripe with Craft. In Charge 2, configuring Stripe Checkout to use Bitcoin is trivial, but could also be made to work with Stripe.js, which is where the deep integration with Craft CMS comes into play.


Using language specific variables inside section URL settings When i use some kind of variable in url settings of section, it always uses default language version of this variable.

For example, blog has two languages, english (default) and german. If i use these settings in URL settings for single post section, in german version:

{{craft.entries.section('archive').one().uri}}/{slug}

It returns english (default, not german) version o archive section uri.

Is it expected behaviour?

Maybe include the .site in your query craft.entries.section('archive').site('YOUR_SITE_HANDLE').one()

What is the section type of your "Archive" entry ? If its a single, maybe it will be more effective to write the handle down manually instead of doing a Query every time.

Note: You can also use .siteId() instead of .site()


How can I count current indexing inside a loop? Is it Possible to count current indexing in a loop which starts from indexing 1 as well as 0?

Twig offers special loop variables that makes it easy to know indexing of a loop.
You can use loop.index to count your current indexing of the loop, which will starting at 1.
If You want to start your indexing from 0 so simply add 0 after loop.index like loop.index0.
There are other loop variable as well.
Like:

loop.revindex
loop.revindex0
loop.first
loop.last
loop.length


Redactor - formattingAdd isn't changing code I added a custom formattingAdd to my Standard.json file in my Redactor config. It's supposed to add the attribute data-aos="fade-right" to a paragraph tag. The "Animate" format option is showing up in the CP, but when I select that format the code doesn't change (it stays just a normal p without the data-aos="fade-right attribute).

{
"buttons": ["html", "formatting", "bold", "italic", "unorderedlist", "orderedlist", "link"],
  "plugins": ["fullscreen", "video"],
  "linkNewTab": true,
  "toolbarFixed": true,
  "formatting" : ["animate", "h1", "h2", "h3", "h4", "h5", "h6", "p"],
  "formattingAdd": {
    "animate": {
      "title": "Animate",
      "args": ["p", "data-aos", "fade-right", "toggle"]
    }
  }
}

I've tried this with classes as well, like this:

"formattingAdd": {
  "note": {
    "title": "Note",
    "args": ["p", "class", "note"]
  }
}

but the note class isn't added to the p tags either.

Any ideas why the attribute and class aren't showing up in the p tags?

Try this for data attributes:

"formattingAdd": {
    "add-animate": {
        "title": "Animate",
        "api": "module.block.format",
        "args": {
            "tag": "p",
            "attr": {
                "data-aos": "fade-right"
            },
            "type": "toggle"
        }
    }
}

This for classes:

"formattingAdd": {
    "add-note": {
        "title": "Note",
        "api": "module.block.format",
        "args": {
            "tag": "p",
            "class": "note"
        }
    }
}

redactor settings formatting


Did a crtitical update now getting errors My customer clicked the update button and updated number 2.6.2791

now we are getting errors trying to save new images to the site.

Internal Server Error

Could not resolve the subpath “project-images/{slug}”.

I wonder if this is a permissions thing?

regards

Hugh

Most likely you've got an Assets field inside of a Matrix field somewhere on your site and you're referencing project-images/{slug} in that field's upload location setting when it should be project-images/{owner.slug}.

At some point, those settings were more loosely enforce, but now the error you're getting will be shown if it is incorrect.

See here for more info: https://craftcms.com/docs/assets-fields#dynamic-subfolder-paths


Invalid username or password After installing Craft 3 successfully, I can't access the admin panel while using the correct credentials. I get an "invalid username or password" message.

I ran into two different issues that prevented me from logging into Craft CMS:

1) By default, Craft CMS uses PHP sessions and my PHP installation (via homebrew) had a blank value under "session.save_path". I updated my php.ini file and searched for "session.save_path", it was commented out, so I uncommented it. It now looks like this: session.save_path = "/tmp"

2) The second thing I noticed is that Craft CMS 3 uses the Yii 2 framework, diving into that framework I found a condition that checks a user's IP address. If the IP address is empty, then it rejects the user from logging in. In my case, I was using the built-in PHP local webserver (php -S localhost:8000) so my IP address wasn't being sent along in the requests. To fix this, I changed my setup to use NGINX instead.


Display number of variants as a value Is it possible to display the number of variants a product has?

This would be in order to achieve the following:

  This product is available in 3 colors

Assuming you've already got the product (which is a ProductModel) in Twig, it's a simple as:

This product is available in {{ product.variants|length }} colors.


URI / Slug auto generation limitation Craft seems to have a limitation when generating unique URI for > 100 entries with the same title.....

I have a channel with YouTube videos in and some are spread across 140 parts all with the same title, and craft auto appends a -1 -2 etc. on the slug but fails when it reaches 3 digits.

Is there anyway to change this limitation?

At the moment it just responds with this:

Internal Server Error

Could not find a unique URI for this element.

To resolve this we added a new config setting for the upcoming 2.2 release called maxSlugIncrement.

It defaults to 100, but you can bump it if you need it to keep finding more unique URIs.


list entries by category, including uncategorized entries I have a channel that is essentially a list of companies participating in an event.

Within that channel is a category group of sponsorship levels.

Companies that are sponsors are assigned a category. Companies that are just participants are not categorized.

I need to output a list of companies beginning with the categorized entries, and then the rest of the uncategorized entries.

The code I'm using below outputs the categorized list, but then I'm doing another loop for all companies (not just uncategorized).

Is there a better way, where I can exclude the categorized companies from the second loop (or include the uncategorized companies in the first loop?

{% set allCompanies = shuffle(craft.entries.section('companies').all()) %}
{% set sponsorCats = craft.categories().group('sponsors').relatedTo(allCompanies) %}

{# Loop the categories #}
{% for category in sponsorCats.all() %}

    {# Get and loop through entries related to this cat #}
    {% set sponsors = craft.entries.relatedTo(category) %}

    {% for entry in sponsors.all() %}
        entry details
    {% endfor %}
{% endfor %}

{% for entry in allCompanies %}
    entry details
{% endfor %}

You could do something like this:

{# Fetch all entries in postDate and category/structure order #}
{%  set entries = craft.entries().section('companies').order('dateCreated DESC').all() | multisort(e => e.yourCategoryField.one().lft ?? 1000) %}

{# Group entries by categories and set a group name for non-categorised one #}
{% set allEntriesByCat = entries|group(e => e.yourCategoryField[0] ?? 'The non categorised one') %}

    {% for groupName, entries in allEntriesByCat  %}

{{ groupName }}

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

        {% endfor %}
    {% endfor %}

{% endblock %}

Change yourCategoryField to your own field handle, of course. The Order of your sponsorship levels ({{ groupName }}) is the one you will define by drag/dropping in your Control Panel → Categories.

Note that this won't show an empty sponsorship level if there is no company attached to it.


Craft folder deployment outside public folder I would like to commit my craft project to bitbucket en deploy it with the help of Deploybot.

The plan is to put the templates (in craft folder) and public assets (public folder) under version control and deploy it with Deploybot. But how do i get the files published into the right directories on the live/staging server.

My craft folder is outside the public root and the public files/assets are inside the public root. So i have two source directories and two destination directories, and this isn't an option with Deploybot. Is there someone with the same setup and a solution?

Thnx in advance!

Dennis,

I use deploybot with Craft and easily deploy. So on your server settings you'll have this:

name: your site name

Host: ip address or domain.com

port: 22 or similar

destination path: /path/to/site_username/

in the destination path set it to be just above public and then you'll deploy /site_username/craft and site_username/pubic


Redirect user to language site of choice On this multi-language site (NL, FR, EN) we're using the saml plugin to single sign on users into the craft site. That part is working fine. Every user has a preferred lanuage returned into a user custom field userLanguage.
What I'm trying to do is simply redirect the French language users to https://mysite.com/fr and the English language users to https://mysite.com/en
In my index template I have the following

{% requireLogin %}

{% if currentUser %}
    {% switch currentUser.userLanguage %}

      {% case "NL" %}
        {% redirect 'https://mysite.com'  %}
      {% case "FR" %}
        {% redirect 'https://mysite.com/fr'  %}
      {% case "EN" %}
        {% redirect 'https://mysite.com/en'  %}
      {% default %}
         {% redirect 'https://mysite.com'  %}

    {% endswitch %}
{% endif %}
{# rest of homepage template here #}

On visiting https://mysite.com/ I'm redirected to the sso page and after login back to https://mysite.com/ and there I get a "too many redirects" error, in firefox it's "The page isn’t redirecting properly Firefox has detected that the server is redirecting the request for this address in a way that will never complete."
What am I missing here?

The answer here was to redirect to another url using a different template rather than hitting the index template again, which was what was causing the loop.


How can I set dynamic absolute Asset URLs? I'm working on my first subfolder-based Craft site, so I'm relying on Asset URLs based on the {{ siteUrl }} variable. I cannot, however, manage to get them working. Any tags I add to the URL field in the control panel get printed literally (not parsed) in the template output.

My config.php looks like this:

return array(

    '*' => array(
    ),

    'foo.craft.dev' => array(
        'siteUrl' => 'http://foo.craft.dev/',
        'devMode' => true
    ),

    'foo.bar.com' => array(
        'siteUrl' => 'http://foo.bar.com/',
        'devMode' => true
    ),

    'example.com' => array(
        'siteUrl' => 'http://example.com/foo',
        'devMode' => false
    ),

);

My Logos Asset settings look like this:

And a relevant chunk of template looks like this:

    {% for logo in logos.logoImages %}
        {{ logo.companyName }}
    {% endfor %}

The background-image URL above renders out as {siteUrl}assets/logos/logo.gif, which isn't parsed as I would expect.

What have I done wrong?

If you want to use the {siteUrl} tag in your Asset source settings, you'll still additionally need to define it in your environment variables as well.

See here as well.


Unknown error occurs on every AJAX call in CP I was working on a plugin with a hook on onBeforeSaveEntry in my dev environment (which is configured exactly like my live environment).

I had a var_dump with an exit in the hook to check output of some variables on save.

After deleting the var_dump and exit from the code the control panel now gives a unknown error on top of every page (which has an AJAX request).

I've deleted any entry I've made today since the code changes but still no effect.

After inspecting the logs the exception seems to be thrown in the BaseController class:

/**
 * Throws a 400 error if this isn’t an Ajax request.
 *
 * @throws HttpException
 * @return null
 */
public function requireAjaxRequest()
{
    if (!craft()->request->isAjaxRequest())
    {
        throw new HttpException(400);
    }
}

Log output:

2016/08/15 21:05:16 [error] [exception.Craft\HttpException.400] exception 'Craft\HttpException' in /...myserverpath.../craft/app/controllers/BaseController.php:217
Stack trace:
#0 /...myserverpath.../craft/app/controllers/BaseElementsController.php(30): Craft\BaseController->requireAjaxRequest()
#1 /...myserverpath.../craft/app/controllers/ElementIndexController.php(66): Craft\BaseElementsController->init()
#2 /...myserverpath.../craft/app/framework/web/CWebApplication.php(281): Craft\ElementIndexController->init()
#3 /...myserverpath.../craft/app/etc/web/WebApp.php(815): CWebApplication->runController('elementIndex/ge...')
#4 /...myserverpath.../craft/app/etc/web/WebApp.php(285): Craft\WebApp->_processActionRequest()
#5 /...myserverpath.../craft/app/framework/base/CApplication.php(185): Craft\WebApp->processRequest()
#6 /...myserverpath.../craft/app/index.php(58): CApplication->run()

When I comment out the line:

throw new HttpException(400);

Everything is working fine.
Because it seems to be an AJAX error, I tried another browser as well but the same error occurs.

Anybody got any ideas?

This will be a environmental configuration issue. The only reason you could get that error is if your web server either isn't setting the global $_SERVER['HTTP_X_REQUESTED_WITH'] variable or it is setting it and it's a value other than XMLHttpRequest.

https://github.com/yiisoft/yii/blob/1.1.17/framework/web/CHttpRequest.php#L679

I'd check the server config and make sure there's nothing odd in your .htaccess files (if on Apache) that might be interfering.


Ugly Redactor II and how to fix it with some CSS Redactor II uses Trebuchet as font, has ugly paddings, giant font sizes and other things.

This must be fixed...

Here is my eye-friendly code:

/* Redactor|Fonts */
[class^="redactor-"], [id^="redactor-"] {
    font-family: inherit !important;
}

/* Redactor|Toolbar */
ul.redactor-toolbar a {
    padding: 12px 13px !important;
    height: auto !important;
}
div.redactor-dropdown, ul.redactor-dropdown {
    font-size: 13px !important;
}
a.redactor-dropdown-h3 {
    font-size: 18px !important;
}

/* Redactor|Tooltip */
span.re-button-tooltip {
    z-index: 1 !important;
    bottom: -18px !important;
    background: none !important;
    color: #333f4d !important;
    font-size: 10px !important;
}

/* Redactor|WYSIWYG-Editor */
div.redactor-layer {
    padding: 20px !important;
    font-size: 15px !important;
    line-height: 22px !important;
}
div.redactor-layer h3 {
    font-size: 20px !important;
}

/* Redactor|HTML-Editor */
div.redactor-box textarea.open {
    padding: 20px !important;
    border-top: 1px solid #e3e5e8 !important;
    border-left: none !important;
    border-right: none !important;
    border-bottom: none !important;
    background-color: #333f4d !important;
    color: #fff !important;
    font-size: 12px !important;
    line-height: 18px !important;
}

Just paste it into the Control Panel CSS plugin.


What's the best way to manage a large number of uploaded photos? I have a news website build with free version of Craft 2.3. It's obvious that a news website will have a lots of entries and lots of photos per entry. It will have at least one per entry and could go up to 10 or more.

So after few months I will have 100s of photos and I was thinking how I can manage this? Will this slow down the system when accessing the assets folder?

Should I use a field with a subfolder which contains variables like {slug} or {author.username}? But the problem is that I cannot search on assets subfolders or see all the subfolders at the same time so I can search within folder and its subfolders.

Anyone came accross to this problem? I'm coming from EE and I love craft just trying to make the transition. In EE I was using devdemon channel images which was creating a subfolder per upload but it had the option to search the subfolders.

Thanks in advance

Sounds like a feature request is in order. It'd be nice to be able to search subfolders for sure.

Regardless, everyone has their own way to organize but you might create folders based on department or whatever category the news is in—sports, politicians, people, religion, places, etc. and then set up the asset to save automatically in that folder based on the category, for example.

As someone who's on that content editing side as well, whatever system you setup, keep it consistent, make sure everyone uses it, is on board with it, and sticks with it. This is not just a technology problem but a people problem. Technology is only as good as the people who are using it.

When I worked for a local TV station doing over the shoulder graphics years ago, we'd have our goto images that we used and I've found over the years doing web it's the same way—people are creatures of habit.

When the site first launches, you throw tons of content at it but down the road, I've found people tend to reuse a lot of stuff. I mean how many different shots of the grand canyon do you need? I don't think every story, every time is going to have a new image thrown at it, but they will recycle a fair amount, so keep that in mind.

There's also a plugin called Introvert that you can setup so you can see reverse entries. That might be helpful to see which other entries that an asset is using. If it's been used by a lot of other entries, it might be time to say "hey we need another image of this..."


Borked upgrade from 1.3 to 2.3 I'm trying to upgrade an Craft site from 1.3 to 2.3 and have gotten into a broken state.

The update button failed, so I tried a manual update. This noted that I needed at least version 2.1, which I then downloaded and tried. It throws the following error and reverts:

CDbCommand failed to execute the SQL statement: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'edition' in 'field list'

When I revert back to 1.3 the admin screen is now blank.

The relevant versions/schema info:

Version: 1.3, Build: 2486, Schema: 1.3.15 (blank login)
Version: 2.1, Build: 2570, Schema: 2.1.2 (SQL error)
Version: 2.3, Craft Build: 2635, Schema: 2.3.4 (desired version)

The craft_info table shows that I'm running 1.3. The site is up, but I can't access the backend.

Any help greatly appreciated!

In between borked update attempts, are you restoring the database to the pre-update state? By default, Craft will create a database backup and place it in the craft/storage/backups folder during an update that you can use.

If you look at your craft/storage/runtime/logs files you'll be able to 1) see the error that originally happened to cause the failed update and 2) see the error that's preventing the CP from loading.


How long will it take Pixel and Tonic to release Craft 3? I am just wondering, when will Pixel and Tonic release Craft 3 stable version?

I asked them on twitter regarding this yesterday and got the following answer:

  Hope to have Craft 3 in beta by the end of year.


Loop through all entry types, separate each group type by line rule (hr) I'm looking for shorter way of doing this:

dog dog dog

––––––––––––––––––––––––––

cat cat cat

––––––––––––––––––––––––––

hamster hamster hamster

Currently, I have to run 3 independent loops to group pet types together, and insert a line rule between them.

How can I group pet types together and separate using a line rule?

      {% for pet in entries %}
            {% if pet.kind == 'dog' %}
                {% include '_partials/animalOrgChart' with {
                  title: pet.title,
                  subTitle: pet.jobTitle,
                  img: pet.headshot|length ? pet.headshot[0],
                  url: pet.url,
                  portrait: true
                } %}
            {% endif %}
      {% endfor %}

          {% for pet in entries %}
                {% if pet.kind == 'cat' %}
                    {% include '_partials/animalOrgChart' with {
                      title: pet.title,
                      subTitle: pet.jobTitle,
                      img: pet.headshot|length ? pet.headshot[0],
                      url: pet.url,
                      portrait: true
                    } %}
                {% endif %}
          {% endfor %}

          {% for pet in entries %}
                {% if pet.kind == 'hamster' %}
                    {% include '_partials/animalOrgChart' with {
                      title: pet.title,
                      subTitle: pet.jobTitle,
                      img: pet.headshot|length ? pet.headshot[0],
                      url: pet.url,
                      portrait: true
                    } %}
                {% endif %}
          {% endfor %}

You can use the group filter

{% set allEntries = craft.entries.section('pets').all() %}
{% set allEntriesByType = allEntries|group('type') %}
{% for type, pets in allEntriesByType %}

     All Pets of Type {{ type }}

     {% for pet in pets %}
         {% include '_partials/animalOrgChart' with {
             title: pet.title,
             subTitle: pet.jobTitle,
             img: pet.headshot|length ? pet.headshot[0],
             url: pet.url,
             portrait: true
         } %}
    {% endfor %}

    <hr class="line" />
{% endfor %}


responsive sizes with imager plugin I’m trying to setup responsive images with the imager plugin, that has 100% width on mobile sizes and then the images are in a 3 column grid on tablet and desktop. But although I’ve got the code outputting the three sizes, the browser is only showing the largest one at all sizes. So can someone see what I’ve done wrong in the following code

      {% set image = row.image.first() %}
      {% set transformedImages = craft.imager.transformImage(image,
          [
              { width: 360, ratio: 4/3 },
              { width: 294, ratio: 4/3 },
              { width: 720, ratio: 4/3, jpegQuality: 60 },
          ],
          {
              format: 'jpg',
              allowUpscale: false,
              mode: 'crop',
              jpegQuality: 80,

              interlace: true
          }
      ) %}
      {% if image | length %}
      <img class="img-responsive"
           src="{{ transformedImages[1].url }}"
           sizes="(min-width: 768px) 33vw, 100vw"
           srcset="{{ craft.imager.srcset(transformedImages) }}"
           alt="{{ image.title }}"
           width="100%">
      {% endif %}

I’m assuming it’s to do with the sizes="(min-width: 768px) 33vw, 100vw" So the 360 width is desktop, and the 294 width is tablet, and the largest size of 720 width is mobile to account for the 2x density.

This is all pretty well documented here: Creating Optimized Images in Craft CMS

But if you need general help on srcset and <picture> elements check out Responsive Images Done Right: A Guide To  And srcset and Don’t use  (most of the time)