Showing and playing video's in Twig templates I want to be able to upload and play videos on my Craft CMS website.
I created a volume and field to hold these videos.
So far so good, but whenever I want to output the video in a video tag I'm not sure how to get the URL of the video.
My code:
{% set video = component.video %}
{% if video %}
   <video width="800" height="500" controls>
      <source src="## VIDEO URL ##" type="video/mp4">
   </video>
{% endif %}

You're close!
Because an asset field can potentially contain multiple items you need to explicitly select the first one, so:
{% set video = component.video.one() %}
But that doesn't get the actual url of the video, to get that you need to request it:
{{ video.url() }}
So in your case:
{% set video = component.video.one() %}
{% if video %}
   <video width="800" height="500" controls>
      <source src="{{ video.url() }}" type="video/mp4">
   </video>
{% endif %}

If you do find yourself needing to show multiple files, then you'd wrap it within a loop:
{# Get all the files #}
{% set videos = component.video.all() %}

{# Check to see if videos has anything in it with '|length' #}
{% if videos|length %}
    {% for video in videos %}
       <video width="800" height="500" controls>
          <source src="{{ video.url() }}" type="video/mp4">
       </video>
    {% endfor %}
{% endif %}


YouTube embeds playing wrong videos I have two modals with embedded video on this page…
http://staging.wenzelspine.com/products

Everything was working fine until I started converting the HTML to Craft templates, but now they are not playing the correct videos… depending on which you click first.

For example, if you load the page and click Play Video under VariLift-LX it is correct, but if you then click Play Video under VariLift-C it plays the VariLift-LX video. If you reload the page and click for VariLift-C first, it plays the correct video.

Don't have enough reps to comment - but it does not seem to be a Craft issue - but rather a Bootstrap modal issue. It seems like when you open the video, it updates the id of the video.

Based on past experiences - I would look into destroying the modal instance and reloading new content in one modal, as opposed to having multiple modal for multiple content.

Update: Just looked a little more into your code and how it's reacting - it seems like on modal close (of either modals), it updates the value of the video embed code to the varilift-lx video.

^ Caused by scripts.js - Line 2172 - 2174

$('.modal').on('hidden.bs.modal', function () {
    $('.video-container iframe').attr("src", $(".video-container iframe").attr("src"));
});

It is grabing the first video container and updating it to that value.


Can an integer be formatted as a telephone number using Twig? Can an integer be formatted as a telephone number using Twig filters or other methods?

I have looked at the 'number_format' filter but it seems to be limited to controlling the number of decimals and how to delimited thousands.

Example; Integer variable from cms '20304050', output to HTML in twig like this: '20 30 40 50'.

Assuming that you always want to add a space after every two digits, something like this using Twig's split and join filters should work:

{% set splitArray = "20304050"|split('', 2) %}
{% set formattedString = splitArray|join(' ') %}

If you want a different format, like 203 04 050, then you could use slice:

{% set firstSeg = "20404050"|slice(0, 3) %}
{% set secondSeg = "20404050"|slice(3, 2) %}
{% set thirdSeg = "20404050"|slice(5, 3) %}

{% set formattedString = firstSeg ~ ' ' ~ secondSeg ~ ' ' ~ thirdSeg %}


Assign User to Group While Importing on Sprout Imports we are trying to import users into a specific group but cant figure out how the json should go. Currently we have:

[
    {
        "@model": "User",
        "attributes": {
            "username": "name@example.com",
            "firstName": "john",
            "lastName": "smith",
            "email": "name@example.com",
            "pending": "0",
            "lastLoginDate": "2017-08-11 04:12:06",
            "dateCreated": "2017-11-06 12:04:04",
            "dateUpdated": "2017-11-06 12:04:04"
        },
        "content": {
            "fields": {
                "customField": "00000"
            }
        },
        "settings": {
            "groups": {
                "groupId": "1"
            }
        }
    }
]

We've tried several variations on settings, permissions, and putting groups under content and attributes but nothing has worked so far.

Sprout Import for Craft 3 supports importing Users and assigning them to User Groups. See the Users page of documentation for more info.

To do so, you just need to assign the User Group ID to the groups attribute:

[
  {
    "@model": "barrelstrength\\sproutimport\\importers\\elements\\User",
    "attributes": {
      "username": "username",
      "firstName": "First",
      "lastName": "Last",
      "email": "user@website.com",
      "pending": 1,
      "lastLoginDate": "2014-12-11 04:12:06",
      "dateCreated": "2014-04-09 12:04:04",
      "dateUpdated": "2015-04-04 06:04:08",
      "admin": "1",
      "groups": [1,2]
    }
  }
]

LEGACY RESPONSE:

Sprout Import does not yet support importing to User Groups.

While we do hope to add this feature in the future, we currently don't have an ETA. Please feel free to reach out to us directly if you'd like to discuss custom development options to help get this feature implemented.

You can add comments to or follow this feature here.


How to render entries on a singles page in a specific pattern/order? On my homepage I have one entry that is constantly there. Below that entry I want to display 2 different types of entries in an alternate order (gallery, update, gallery, update...).

Right now I have it so that I'm getting all the sections, setting it to a variable and looping through doing a entry.type check so it renders according to it's type. What would happen now is that it would display everything according to the posts' time.

Thoughts? Ideas?

Thanks.

my code

{# story #}
 {% for entry in craft.entries.section('stories').limit(1) %}

{{ entry.title }}

Posted on {{ entry.postDate.format('F d, Y') }}

        {{ entry.body.getPage(1) }}

Continue reading

{% endfor %}
{# end of story #}

{% set entry3 = craft.sections.getAllSections() %}

{% paginate craft.entries(entry3).limit(2) as entries %}
{% for entry in entries %}
{% if entry.type == 'carousels' %}

{{ entry.title }}

Posted on {{ entry.postDate.format('F d, Y') }}

                    {# {{ entry.body.getPage(1) }} #}

                    {% for block in entry.gallery.limit(3).find() %}
                    {% set asset = block.galleryImage.first() %}
                    {# {% set asset2 = block.galleryImage.nth(2) %} #}

                    {% endfor %}

Continue reading

{% elseif entry.type == 'updates' %}

{{ entry.title }}

Posted on {{ entry.postDate.format('F d, Y') }}

                    {{ entry.body.getPage(1) }}

Continue reading

{% endif %}

{% endfor %}
{% endpaginate %}

How are the entries ordered (by date in a channel, manually in a structure or other?)

Are you using the entries anywhere elsewhere at all?

There are a couple of ways you could go, If the Galleries are related to the Updates, you could create a relationship from one to another using an entries field, and then just have the parent render the child in the same loop to different single page entry templates.

Depending on how the URLs need to be, you could use two different entry types in the same channel or structure.  If you need different URL structure you could always use {type} in the 'Entry URL Format' setting and then use custom routes if needed.

Hope this helps :)

I don't think you need to get as complex with arrays or anything.


Single-sign on for multiple Craft sites Does Craft support any form of single sign-on across separate installations? I don't think there is a native way of doing this, but does anyone have any idea how I would approach this?

What I need is for users of Site A and Site B to be kept in sync in some way so they can use the same username and password to sign-on to both sites. Bonus points if they can automatically signed into to Site B if they are already signed into Site A.

Note that using some form of social sign-on (e.g. Facebook, Twitter, etc.) is not an option for this client.

No, Craft doesn't have any native notion of SSO.

(You can technically run multiple sites from the same Craft instance. If you had sites sharing the same server, you could run them from the same Craft installation, thereby enacting a de facto shared user roster by virtue of the shared database. If such sites also shared a root domain, you could gracefully maintain a persistent session between them. However, for the purpose of this answer, I'm assuming such a circumstance does not apply.)

Nonetheless, you could enable a limited/simple SSO-ish setup using a custom plugin...

  What I need is for users of Site A and Site B to be kept in sync in some way so they can use the same username and password to sign-on to both sites.

Trying to keep user records perfectly in sync across multiple sites would not be simple. However, you probably don't need records to be perfectly in sync. Rather, you only need one site to serve as the authoritative source of truth, and the other site(s) only needs to keep track of a unique reference (i.e. a username, or even better, a UUID.):

Master/Slave setup

Let's say Site A is the master, Site B is the slave.
All user registration takes place on the Master site. (User registration is not allowed on the Slave site.)
Login on Master uses Craft's native users/login controller method.
Login on Slave uses a custom controller method that submits a username/password combo to Master, receives back a response, and logs in the user if Master says their credentials are valid. (If a record for this user doesn't already exist on Slave, one is created 'just-in-time' and logged in.)

Caveat — If profile values are allowed to change, then we do need to create a mechanism for the Master site to notify its Slave sites of any changes. (We don't care about the slave sites' copy of the user's password, because only the Master site ever needs to do any authentication. We might care about keeping username/email/profile values in sync, because the Slave sites may want to display User info in templates or something.) This can be accomplished using a custom controller action (authenticated by some secret key, perhaps) by which the Master site triggers the Slave site's users/saveUser method with new/updated content.

  Bonus points if they can automatically signed into to Site B if they are already signed into Site A.

If the sites share a root domain...

Craft decides that a user is "still signed in" by matching a known session ID (stored in the craft_sessions table) to the cookie sent by the user's client.

If your sites share a root domain (e.g. mysite.com and other.mysite.com) then they will be able to share cookies. (You'd use the defaultCookieDomain setting to cause both sites to store cookies under the root domain.) That means the Slave site can read the user's CraftSessionId cookie, validate it with the Master site, and log the user in as appropriate.

If the sites don't share a root domain...

Alas, due to cross-domain restrictions, sites not sharing a root domain are not allowed to receive/read each other's cookies. Automatic multi-site login might still be possible, but it'd involve bouncing the user back and forth in a series of [hopefully imperceptible] redirects between Master and Slave that would accomplish something basically single-sign-on-y (Kerberos, anyone?). It'd be convoluted and weird and I don't have brainpower to think about it anymore tonight.  :-P


Enable the user to upload background Image How do you enable a user to upload a css background Image?

Do you write some inline css in the page header with twig markup?
Do you write some twig markup inside a css file?

Or do you fake a background image by add an image and then position it absolute?

What's the best practice there?

You can simply add it inline to your body tag like so:

<body style="background-image: url({{ myGlobal.myAssetsField.first().url }})">

If you want to only use it with selected templates, you'd better use Craft's includeCss tag:

{% set bodyCss %}
    .myBodyClass {
        background-image: url({{ myGlobal.myAssetsField.first().url }});
    }
{% endset %}

{% includeCss bodyCss %}


Why are PNG images bigger in file size on the (S3) server? We've got quite a few PNG image files for a site build, so naturally we're running them through tinypng to reduce size. This works great locally, but when we upload them to assets (S3) the file size is getting huge again.

Pic: https://cl.ly/152u2C2D3g2n

193kb to 440kb in this example ^ which is typical.

Any thoughts?

I agree with Brad's comment, this is very similar to those two other threads.

That being said, here is an important quote which is buried on one of those threads...

  When an image is first uploaded, Craft will "sanitize" the image for any malicious code by re-saving the image out to a new file. It jumps through some pretty significant to ensure that the sanitized image is as close to possible as the originally uploaded image in both quality and file size, which usually explains the differences people see in file sizes.

I believe this is what the OP is experiencing.


Craft 3 Database Backup Why do I have to activate the PHP functions: "proc_open" and "proc_close" to backup the database?
I got the error logs:

[error][yii\base\Exception] yii\base\Exception: Could not create backup: proc_open() has been disabled for security reasons in /home/velolade/craft3veloladen_daten/vendor/craftcms/cms/src/controllers/UtilitiesController.php:383
[error][yii\base\Exception] yii\base\Exception: Could not create backup: proc_close() has been disabled for security reasons in /home/velolade/craft3veloladen_daten/vendor/craftcms/cms/src/controllers/UtilitiesController.php:383

After activating these functions in my hoster's PHP settings, it worked.
Is this a security problem for my website?
Thank you very much!

Craft uses MySQL's native mysqldump and PostgreSQL's pg_dump binaries to create database backups.

In order for PHP to be able to execute those binaries, it needs to be able to run the proc_open and proc_close PHP commands.

I would not consider it a security issue, but if you were really concerned about it, you can prevent Craft from making backups on update and/or specify your own backup logic bypassing Craft's default implementation.


Add Dynamic Elements In Forms I'm needing to add a dynamically added dropdown input field for my form, as is commonly done with javascript.  How would this be possible?

In other words, there may be more than 1 dropdown desired by the user, and I need a link or button that would create any additional desired dropdown inputs.

Thanks

You need to create a custom Field Type or you can use dynamicfields in order to gain dynamic inputs. Or is it just about hiding/showing specific values in Javascript and not really about Craft at all?


Get selected values from all of an entry’s Multi-select fields I am new in Craft, and will be happy if I can get help with this task. I have a tab that contains only multiselect fields. What I want to do, is to get all selected values for all multiselects field in this tab. I find this answer to get all field from a tab, but I can't get the selected values for the entry. Here is my code:

{% for tab in entry.getFieldLayout().getTabs() %}
  {% if tab.name == 'Spec' %}

{{ tab.name }}

          {% for field in tab.getFields() %}

{{ field.getField().name }}

          {% endfor %}

  {% endif %}
{% endfor %}

You can loop through all of the selected values of a multi-select field like this:

{% for value in entry.myFieldHandle %}

{{ value }}

{% endfor %}

(See the Multi-select field docs for other examples.)

The easiest way to loop through all of your multi-select fields’ values would be to manually merge all of their values into a new array:

{% set values = entry.fieldHandleOne
    |merge([entry.fieldHandleTwo])
    |merge([entry.fieldHandleThree]) %}

{% for value in values %}
    {{ value }}
{% endfor %}

If you really don’t want to hardcode the field handles in your template, then you can go the getFieldLayout() route. That field.getField() function will give you the actual FieldModel that represents the field. You can use its handle property to access the field’s selected values on your entry:

{% set values = [] %}

{% for tab in entry.getFieldLayout().getTabs() %}
  {% if tab.name == 'Spec' %}
    {% for field in tab.getFields() %}
      {% set handle = field.getField().handle %}
      {% set fieldValues = entry.getFieldValue(handle) %}
      {% set values = values|merge([fieldValues]) %}
    {% endfor %}
  {% endif %}
{% endfor %}

{% for value in values %}
  {% for selected in value %}

{{ selected}}

  {% endfor %}
{% endfor %}


Image Transform Problems, Timeouts, Stuck Transforms We are seeing the following symptoms:

We routinely encounter stuck Generating pending image transforms tasks and have to manually mark the tasks as failed using SQL in the table craft_tasks.
Broken image links on pages that use image transforms. This can sometimes be fixed with multiple page refreshes.
The phperrors.log message PHP Fatal error:  Maximum execution time of 120 seconds exceeded in /.../craft/app/vendor/imagine/imagine/lib/Imagine/Imagick/Image.php on line 228, even though are php.ini sets the max execution time to 300. I am pretty sure this is from the hard-coded limit set in AssetTransformsService.php

Our site has a large variety of images; the site is for a advertising agency. We can reproduce the problem pretty easily with animated GIFs, although size of the GIF does not alone seem to be the factor, because some 2mb GIFs never transform, while some 4mb GIFs transform very quickly.

I think there are a few issues going on:

The 120 second limit is affecting some images that take a long time to transform, resulting in a exceeded exec time log message.
Some images are never completing the transform process, seemingly regardless of the transform time, resulting in an exceeded exec time log message.
Some images mysteriously get stuck in the image transform process, resulting in no log messages.

Questions

What is the recommended way for increasing the hard-coded 120 second limit?
How can we track down the cause(s) of the stuck transforms?

AssetTransformsService.php Background

The Craft core file craft/app/services/AssetTransformsService.php has a hard-coded PHP max_execution_time of 120 seconds.

line 421: ini_set('max_execution_time', 120);

Some Craft Info

We are using Craft CMS version 2.6

Some Sever Info

We have imagick enabled as our image driver.

imagick module version  3.4.1
Imagick compiled with ImageMagick version   ImageMagick 6.7.2-7 2016-06-16 Q16 http://www.imagemagick.org
Imagick using ImageMagick library version   ImageMagick 6.7.2-7 2016-06-16 Q16 http://www.imagemagick.org
ImageMagick release date    2016-06-16

Craft release 2.6.2911 has made a significant improvement, and with it, our troublesome animated GIFs are transforming correctly.


Why does the UserSessionService create a *state* cookie? I'm trying to set a cookie using saveCookie(), and I'm puzzled by the UserSessionService's behaviour.

Instead of creating a plain old cookie, Craft actually creates a so-called state cookie, where the cookie name is prefixed with a hash key and the cookie value is also hashed.

Here's the code I'm running to set the cookie:

craft()->userSession->saveCookie('myAwesomeCookieName', $someAwesomeCookieData, 3600)

...and here's what the cookie looks like:

d9c79699028b2f1b123abbcd3e872e5dmyAwesomeCookieName : aa9de09d72cdbda2caac4551870e073d0f7307b3s

Reading over the source code, docs and other SE's on the subject, it's not apparent to me why Craft creates a state cookie instead of a regular (non-hashed) cookie.

Also, as far as I know, the only built-in method available to templates for retrieving a cookie is craft.request.getCookie – which is actually unable to read state cookies, so it all seems a bit odd.

I've currently implemented template variables for retrieving and reading the state cookie in my template (by wrapping the UserSessionService's getStateCookie and getStateCookieValue methods, respectively) but I'd love to know why the hashing happens in the first place, and if I can prevent it without an additional plugin (I'm aware of the LJ Cookies and the Cookie plugin).

craft()->userSesssion->saveCookie() is basically a fancy wrapper for craft()->request->getCookies()->add() that (as you've discovered) does some key and value based hashing to ensure that cookie data hasn't been tampered with between requests.  Which is especially useful if, for example, cookies are used to maintain user session.

If that's not the behavior you're looking for, you can use PHP's setCookie method (like LJ Cookies and the Cookie plugin do) or you can interact with craft()->request->getCookies()->add() directly outside the context of the UserSesssion service.


List authors on front end by total number of entries I need to output a list of channel authors. There are about 40 authors but I want the 8 authors with the most entries. Not sure how to achieve this.

What I have so far:

    {# get all the itbuzz entries #}
    {% set allEntries = craft.entries.section('itbuzz').all() %}
    {# get all the authors #}
    {% set authors = craft.users.group('itBuzzAuthor').limit(8).all() %}

      {% for author in authors %}

          {{ author.firstName }}
{{ author.lastName }}

      {% endfor %}

All this does is output the first 8 authors, it's not finding the 8 with the most entries.

You could do something like this:

{# Fetch entries + authors and group by author id #}
{% set entriesByAuthors = craft
    .entries()
    .section('itbuzz')
    .limit(null)
    .with('author')
    .all() | group(e => e.author.id) %}

{# Build an array with authorId and entry count for each that we can sort them #}
{% set leaderBoard = [] %}
{% for author, entries in entriesByAuthors  %}
    {% set leaderBoard = leaderBoard | merge([{'author' : author, 'count' : entries | length}]) %}
{% endfor %}

{# Build an array of user ids only sorted by entry count and extract the top 8 #}
{% set authorIds = [] %}
{% for result in leaderBoard | multisort(e => e.count, direction=SORT_DESC) | slice(0,8) %}
    {% set authorIds = authorIds | merge([result.author]) %}
{% endfor %}

{# Fetch users based on our sorted and sliced array of ids #}
{% for author in craft.users().id(authorIds).all() %}
    {{ author.firstName }} - {{ author.lastName }}<br>
{% endfor %}


Blog template not displaying posts The blog post should display the posts created but when I got to the slug /blog it says 404 not found as well as the press news should be displayed here /press-news but same thing happens.

If i access the posts directly : site.com/blog/blog-post-name it is displayed correctly.

an you help me giving me some probable causes so that i can check how to fix it? thanks

If you've setup a channel, it does not include a "blog index" by default, for this you need to make it yourself by placing an index.twig file within the blog folder (If that is a directory in your templates folder).

Check the answer in this question for an example on how to do the twig code.
What's the right way to create a simple blog in Craft?


Looping through element queries directly has been deprecated on the template

_events.twig

{% include "./components/_listing" with {
  entries: craft.entries.section('events').orderBy('eventStartDate ASC').limit(3),
  columns: 3,
  heading: 'On this month',
  art: 'art3',
  headings: true
} %}

_listing.twig

{% if pagination is defined and pagination == true %}
        {% paginate entries as pageInfo, pageEntries %}
    {% else %}
        {% set pageEntries = entries %}
    {% endif %}

             {% for entry in pageEntries %}
    ~~~~

"Looping through element queries directly has been deprecated. Use the all() function to fetch the query results before looping over them."

The line number is {% for entry in pageEntries %}

I referred Explanation of Deprecation Warnings and Output deprecation error

But seems I'm away from those two answers.

Can someone suggest me to find a solution for this?

Update:

{% set featuredEvents = craft.entries.section('events').featuredEntry(1).limit(10).orderBy('offerStartDate') %}

on the template

{% for featuredEvent in featuredEvents %}

When we limit to 10, why `{% for featuredEvent in featuredEvents %} line highlight for

Looping through element queries directly has been deprecated. Use the all() function to fetch the query results before looping over them.

For your first issue, if you are not paginating then your {% else %} should be:

{% set pageEntries = entries.all() %}

So that the query gets executed. In full:

{% if pagination is defined and pagination == true %}
        {% paginate entries as pageInfo, pageEntries %}
    {% else %}
        {% set pageEntries = entries.all() %}
    {% endif %}

Regarding the update to your question, it's the same thing.

Until you add .all() to your featuredEvents query (or any query), it's like the query hasn't run yet. Adding .all() executes the query.

Craft is smart enough to still run it without .all() but it will warn you hence the deprecation warning.

You should read more about element queries and how to execute them.


How to request entries data for React? Hello I have a website built in Craft 3. I have some components built in React but typically the site is served using Twig templates.

How can I make an axios call to craft to request the page's entry blocks, sections, etc? Is this possible?

Yes you can. I use Craft 3 as an headless CMS for React or for any other javascript framework.

You have various options to do this, the most know ones are described here: https://docs.craftcms.com/v3/dev/headless.html#app

I would recommend you to use the CraftQL plugin. My example below is using ReactJS, Axios and CraftQL within CraftCMS. This plugin (CraftQL)  allows you to access your Sections, Entries, Categories, etc... by doing queries to a GraphQL api endpoint in Craft CMS.

See more about the plugin here:
https://github.com/markhuot/craftql

This is an example for ReactJS and with Axios on componentDidMount:

  componentDidMount() {
    // data query
    // your GraphQL query should go here!!
    const queryData = {
      query: `{
        helloWorld
      }`
    };

    // GraphQL API headers
    // The values for craftql_token_type and craftql_token_value are in
    // the settings of the plugin in Craft CP (Control Panel).
    // You can update the access to the GraphQL api endpoint there
    const queryHeaders = {
      headers: {
        'Authorization': `craftql_token_type craftql_token_value`
      }
    };

    // Axios POST request to GraphQL API url
    axios
      .post(api_url, queryData, queryHeaders)
      .then((response) => {
        if (response.data.data.errors) {
          // do something
        } else {
          // do something
          this.setState({
            data: response.data
          });
        }
      })
      .catch(error => {
        this.setState({
          error: true
        });
      });
  }

Hope this helps!

:)


Can someone explain to me the difference between 'not' and without? Here is an example of code I'm trying to use to eliminating have to iterate comparing the current entry.title to the related to entry.title then omitting it.

{% set entries = craft.entries.relatedTo(context).limit(MAX_FILLERS).id('not' ~ entry.id) %}

{% set entries = craft.entries.relatedTo(context).limit(MAX_FILLERS)|without(entry.id) %}

Current code I'm trying to get around with a single relatedTo call.

{% set entriesUnfiltered = craft.entries.relatedTo(context).limit(MAX_FILLERS).search('-title:'+entry.title) %}

{% set entries = [] %}

{# Removing self entries #}
{% for e in entriesUnfiltered%}
    {% if e.title not in entry %}
        {% set entries = entries|merge([e]) %}
    {% endif %}
{% endfor %}

Your first example (.id('not' ~ entry.id)) will exclude that entry ID from the results on in the actual database query.

Your second example will grab all of the entries that satisfy the criteria, then from the PHP/Twig side, then use the |without filter to loop through the array results and remove the ones that match the criteria.

Pretty sure your 2nd one won't work as you're expecting though, since you're telling it to remove an entry.id, which is an integer, but the results are an array of Entry elements. It might work just using entry instead, but I'm guessing the |without filter isn't smart enough to work on entire objects.

Long story short, use the 1st example.


Show entry version history on front end We have some content that needs to display a log of changes (legal docs, terms etc)

Could I use version history for this?

I found this for Craft 2 but doesn't work on 3...

How can I display entry edit history on the front end?

Here's an example of accessing an entry's version history that Nathaniel Hammond recently shared on Twitter:

{#
Options for getVersionsByEntryId
* @param int $entryId The entry ID to search for.
* @param int|null $siteId The site ID to search for.
* @param int|null $1 limit The limit on the number of versions to retrieve.
* @param bool $includeCurrent Whether to include the current "top" version of the entry.
* @param bool $withContent Whether the field content should be included on the versions.
* @return EntryVersion[]
#}
{% set entryId = 7 %}
{% set siteld = null %}
{% set limit = null %}
{% set includeCurrent = true %}
{% set withContent = false %}
{% set versions = craft.app.entryRevisions.getVersionsByEntryId(entryId, siteId, limit, includeCurrent, withContent) ?? null %}

{% if versions|length %}

    {% for version in versions if version.getCreator() %}

{{ version.getCreator().username }}

    {% endfor %}

{% endif %}

In this example he's accessing the version's creator and displaying that, but you could easily swap that out for whatever you need to do, such as grabbing the version creation date etc.


Craft 3 installation issue on account creation I try to install Craft 3 but I encounter an issue at the very beginning.
I uploaded the CMS via FTP and completed manually the .env file. When I try to run the installation, I get stuck at the account creation (the second step…) I want to create my account but the next button is doing nothing.
I get an error 400 "Bad Request // Unable to verify your data submission." When I send the form to create the admin account (POST to http://mywebsite.com/web/index.php?p=admin/actions/install/validate-account).

The server meet the requirements of Craft CMS (runned the server check and was ok). The DB connection is fine.

I tried to delete and reupload all the CMS but nothing changed.

Therefore, I'm unable to install Craft :| I saw some topics of the same issue but they're all unanswered.

Thanks a lot !

Here are the corresponding logs :

            2018-04-13 06:05:42 [2a02:a03f:3c1f:a00:6826:543f:275d:d8d5][-][-][error][yii\web\HttpException:400] yii\web\BadRequestHttpException: Unable to verify your data submission. in /home/MyWebsite/www/vendor/yiisoft/yii2/web/Controller.php:166
            Stack trace:
            #0 /home/MyWebsite/www/vendor/craftcms/cms/src/web/Controller.php(53): yii\web\Controller->beforeAction(Object(yii\base\InlineAction))
            #1 /home/MyWebsite/www/vendor/yiisoft/yii2/base/Controller.php(155): craft\web\Controller->beforeAction(Object(yii\base\InlineAction))
            #2 /home/MyWebsite/www/vendor/craftcms/cms/src/web/Controller.php(74): yii\base\Controller->runAction('validate-accoun...', Array)
            #3 /home/MyWebsite/www/vendor/yiisoft/yii2/base/Module.php(528): craft\web\Controller->runAction('validate-accoun...', Array)
            #4 /home/MyWebsite/www/vendor/craftcms/cms/src/web/Application.php(238): yii\base\Module->runAction('install/validat...', Array)
            #5 /home/MyWebsite/www/vendor/craftcms/cms/src/web/Application.php(446): craft\web\Application->runAction('install/validat...', Array)
            #6 /home/MyWebsite/www/vendor/craftcms/cms/src/web/Application.php(410): craft\web\Application->_processActionRequest(Object(craft\web\Request))
            #7 /home/MyWebsite/www/vendor/craftcms/cms/src/web/Application.php(147): craft\web\Application->_processInstallRequest(Object(craft\web\Request))
            #8 /home/MyWebsite/www/vendor/yiisoft/yii2/base/Application.php(386): craft\web\Application->handleRequest(Object(craft\web\Request))
            #9 /home/MyWebsite/www/web/index.php(21): yii\base\Application->run()
            #10 {main}

Hello and thanks Brad !

I was actually using Firefox. When I tried to install Craft 3 via Chrome (which has never gone to the website before) the issue was solved and I could access to the next page. Should be a cache issue !

Thank you !

Olivier.


Change order content blocks home page Good afternoon, I was wondering to what extent you can change (the order for example) the existing contentblocks on the pages. Thank you in advance!

By default, Matrix blocks will display in the order you have entered them in your entry form.
If you need to change the display order, you can drag/drop your blocks straight from your entry form using the small handle on the right of the blocks and the order will be reflected on your page.


Post to an action URL fails, Get works I have a simple plugin that's expected POST data from a form:
<form method="post" action="" accept-charset="UTF-8">
    <input type="hidden" name="action" value="{{ actionUrl('broadbean/jobs/new') }}">

When I submit the form, that fails:

Page Not Found
Unable to resolve the request "http:/craft.dev/index.php/admin/actions/broadbean/jobs/new".

If I cut and paste that URL into a new window, I get the plugin response, so what gives here? The plugin is set up to allow anonymous access (but I'm submitting the form from within an admin view anyway).
EDIT:
According to http://buildwithcraft.com/docs/plugins/controllers#posting-to-controller-actions I should be able to put the action URL in a hidden field, which I've done. If I dispense with that and instead put the actionUrl() directly in the form's action parameter, everything works.
Is this a bug? This is on Craft 2.2.2601.
EDIT:
Controller code:
class Broadbean_JobsController extends BaseController
{
    protected $allowAnonymous = true;

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

        $result = craft()->broadbean_jobs->createJob();

        var_dump(array(
            'message' => ($result['success']) ? Craft::t('Job created.') : Craft::t('Unable to create job.'),
            'values' => craft()->request->getPost(),
            'errors' => $result['errors']
        ));

    }
}

I believe that when you post data using name='action' from a form that craft automatically uses the actionUrl to route the request properly, so that if your controller is here:

/craft/plugins/broadbean/controllers/Broadbean_JobsController.php

with a method actionNew, then craft will create the action route broadbean/jobs/new automatically:

<input type="hidden" name="action" value="broadbean/jobs/new">

On the other hand if you are linking directly then craft doesn't know to use the action route, so you need to explicitly tell it that this is an action request:

<a href="{{ actionUrl('broadbean/jobs/new', { id: 10 }) }}">

or from javascript:

var url = Craft.getActionUrl('broadbean/jobs/new', { id: 10 });

If you were to call the action externally then you would have to write the full action url without the benefit of using the automatic config routing:

http://mysite.com/actions/broadbean/jobs/new?id=10

or, if the admin had, for example, set up a custom actionUrl in the config file:

http://mysite.com/methods/broadbean/jobs/new?id=10


Mass Creation of Entries Without taking the time to explain the reason behind the requirement, I need to make about 3,000 empty entries.

How can I do this, that is how can I generate X number of entries without manually saving them from the admin area, outside of writing my own plugin? I don't think there's any good way to just write some SQL and barf them into existence right inside the database :(

Edit:

So I'm fairly certain this would have to be done via custom plugin development if it is indeed possible. I've never made a Craft plugin before, so I'm a little gunshy!

I imagine the structure of the plugin would be something like this:

public function onSaveEntry(Event $event)
{
    $title = $entry->title;

    for ( $i = $title; $i<8000; $i++)
    {
        do
        {
            public function saveEntry(EntryModel $entry)
        }
    }
}

Now, this is pseudo-code at best. I'm not sure what to exactly do here. But I hope this illustrates my thinking:

When I save a new entry, I want this thing to fire.
Right now my entries have auto-generated titles: take the last entry and add one: 5000 -> 5001 -> 5002, etc.
As long as we have less than 8000 entries (technically 3000 entries, as our entry titles will be 5000 - 8000) we want to keep saving new entries.
Once we finally save an entry with a title of 7999 or 8000, stop making entries.

Is this possible? What do I need to do?

Thank you soooo much to whoever out there can help me out!

Or you could just use an existing seeding plugin like A&M Seed. :)

Even if it does do exactly what you're looking for, you can use it as a starting point for your plugin.


How do you return an instance of a variable class from within a different variable class? I have a plugin with the structure something like:

variables
 - PluginVariable.php
 - PluginAnotherVariable.php

Inside PluginVariable.php I have something like:

<?php
namespace Craft;

class PluginVariable
{
   public function foo($parameter)
   {
       $result = craft()->plugin_results->get($parameter);
        return new PluginAnotherVariable($result);
   }
}

Now when I do {{ craft.plugin.foo('something') }} I just get Fatal error: Class 'Craft\PluginAnotherVariable' not found.

I've checked that the filenames and classnames are identical and the namespacing etc so the class most certainly exists but I can't get this to work, has anyone had a similar issue with this and what could be causing it? Thanks.

Boom!

So I just needed to put an underscore between the plugin handle and variable name so PluginAnotherVariable.php becomes Plugin_AnotherVariable.php and the classname Plugin_AnotherVariable and things are now working :)


Using the Redactor rich text field, how can I dynamically wrap my images with a fancyBox link (with attributes as parameters)? I'm using fancyBox (from fancyApps, http://fancyapps.com/fancybox/), and I need to wrap my images added within the Redactor rich text field with a link that had an href to the image source + some attributes as parameters :

an href attribute to specify the image source to open
a data-fancybox-group attribute to specify in which gallery the image
should open
a title attribute to specify the image title in the fancyBox)

I tried to add formatting tags to Redactor (cf. https://imperavi.com/redactor/examples/formatting-add/) which let me add links with .fancybox class, but there's still missing parameters that are required to open the fancyBox that I'm not sure that can be retrieved.

"fancybox": {
    "title": "Add fancyBox link",
    "args": ["a", { "data-fancybox-group": "images-gallery", "class": "fancybox" }]
}

I also tried the Retcon plugin (https://github.com/mmikkel/RetconHTML-Craft) which is very cool and lets me automatically wrap each image with a link with data-fancybox-group but I still can't retrieve and apply the img src + title to the link.

{{ entry.body | retconWrap( 'img', 'a.fancybox') | retconAttr('.fancybox', { 'href':'', 'data-fancybox-group':'images-gallery' }) }}

is there a way to achieve this with one of this two methods ? Or to do this in another way ? This should be very easy for the end user which is a non-programmer.

I managed to achieve this a while back within ExpressionEngine. The approach would be the same...

I used this Javascript:

$(document).ready(function() {
    $(".fancybox").fancybox();

    // Apply FancyBox to images within the body of an article
    $(".articleBody img").on("click", function(){
       $.fancybox($(this).attr("src"),{
           // API options
           padding : 0 // example
       });
    });

    $('.fancybox-media')
        .attr('rel', 'media-gallery')
        .fancybox({
            openEffect : 'none',
            closeEffect : 'none',
            prevEffect : 'none',
            nextEffect : 'none',
            padding : 0,

            arrows : false,
            helpers : {
                media : {},
                buttons : {}
        }
    });

});

From memory, this worked on all  tags within .


can't login after move site to local - empty response After migrating a site to local i can't login into the backend-part /admin/login.
There is an error message in the browsers console log

VM1974:1 POST http://great-site.localhost/index.php?p=admin/actions/users/login net::ERR_EMPTY_RESPONSE

I debugged into the backend until the return $this->asJson($return); line 1671 in UserController (vendor/craftcms/cms/src/controllers/UsersController.php).
But somehow it seems to not return anything as the browser console says.
I am on Craft Version 3.3.6
PHP Version 7.3.18
Questions upfront
Could it be that i am running on http instead https now?
Could it be that i am not creating a session correctly?

Finally i got it.
It was an issue with the .htaccess
I had not a default installation .htaccess, but a special one.
What helped in my case wa putting following into the .htaccess
    # Remove www from URL's
    RewriteCond %{HTTP_HOST} ^www\.(.+)
    RewriteRule ^ http%2://%3%{REQUEST_URI} [L,R=301]

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

But also got issues similar to this answer afterwards: https://craftcms.stackexchange.com/a/35846/11140


URL Encode only file name is there any built-in way to encode malicious file name characters when getting an asset URL through assetHandle.getUrl('transformationName')?

My system contains files with names such as /assets/images/foo/_transformationName/105 Flippy Dolphin 31 (F60).jpg and escaping the whole string escapes also slashes.

I can assemble a valid URL from asset.directory and asset.filename, but that cuts off access to image transformations.

I do realize I could create a twig extension or explode the string using regular expressions, do my thing and join it back, but I have a feeling this might use some approach more aimed at fixing the cause, not the consequence. The .getUrl() method might be able to return a web-safe value somehow maybe?

If you're worried about malicious characters in an uploaded file name, Craft already sanitizes them when uploading from the control panel.

Craft doesn't do this during Asset indexing because generally it's assumed that the files you're uploading are trusted files.

It sounds like that might not be true in your case, though. I can think of two options.

Write a Craft plugin that loops through all files in your upload folders and calls the same AssetsHelper and IOHelper sanitizing methods that Craft does.
Find some desktop application that does it before you upload the files. A quick Google search turned up this for OSX, and this for Windows.


How to build a simple gallery Just installed the cms last night. I am looking for a step-by-step instruction on how to create a gallery and display it.

So far I have created the:
- channel called: Gallery
- section called: Gallery
- entry type: Gallery
- the assets field named: gallery
- added 4 images
- created a new entry called: Gallery (only the Title is visible so far) and this is where I got stuck.

Any help would be greatly appreciated

I'm a beginner myself but have used assets plenty of times. It should be something like this:

{% set entry = craft.entries.section('gallery').first() %}
{% set assets = entry.gallery %}
{% if assets | length %}
    {% for asset in assets %}
        <img src="{{ asset.getUrl('imgTransform') }}" width="{{ asset.getWidth('imgTransform') }}" height="{{ asset.getHeight('imgTransform') }}" alt="{{ entry.title }}">
    {% endfor %}
{% endif %}

I use a set entry instead of a for loop because I'm assuming you only have one entry (one gallery). Maybe use a single section instead of a channel than? If you have multiple galleries, a channel is perfect, than you can use a for loop.

The imgTransform can be set in your assets page in the Control Panel. More info: http://buildwithcraft.com/docs/image-transforms


Timezone in Store Hours Plugin I am located in Austria using Pixel & Tonic's Store Hours Plugin. The Timezone in Craft's settings is set to UTC+1 (CET) - Europe/Vienna.

When I type in that it's opened from 3 - 6pm it outputs that it's opened from 2 - 5pm.

I guess that it is outputting the UTC but I can't really figure out why and how to fix it.
Is that possibly a bug in the plugin or is it meant to be adjusted in the template anyway?

Any help will be appreciated.

This is going to be a bug in the Store Hours plugin.  I've created an issue in the repo here so we can keep track of it: https://github.com/pixelandtonic/StoreHours/issues/3


Can I get Assets from a specific Matrix block? When they exist, I'd like to get specification PDFs from a product entry. They're stored in a productInfo Matrix field, in a specifications block that has a downloads Assets collection.
Naturally I attempted the following...
{% set specFiles = entry.productInfo.specifications.downloads %}
{% for specFile in specFiles %}
    {{ specFile.title }}
{% endfor %}

...and Craft thought I was being greedy:

Internal Server Error
Craft\ElementCriteriaModel and its behaviors do not have a method or closure named "specifications".

I noticed in this SE question that examples skipped referencing the block type and went straight for the field name, so I tried that next...
{% set specificationDownloads = entry.productInfo.downloads %}
{% for specFile in specificationDownloads %}
    {{ specFile.title }}
{% endfor %}

This didn't throw any error, but it didn't return any results either.
I know that I can loop through the blocks and then the downloads, it just seems excessive...
{% for block in entry.productInfo %}
    {% if block.type == 'specifications' %}
        {% for specFile in block.downloads %}
            {{ specFile.title }}
        {% endfor %}
    {% endif %}
{% endfor %}

So what is the most straightforward way to get results when I want to limit them to a specific (Assets) field within a certain Matrix block type?

You should be able to do this like so:

{% for block in entry.productIndo.type('specifications') %}
    {% for download in block.downloads %}
        {{ download.url }}
    {% endfor %}
{% endfor %}

Of if the nested loops don't suit you:

{% set specificationBlock = entry.productIndo.type('specifications').first() %}

{% if specificationBlock %}
    {% for download in block.specificationBlock %}
        {{ download.url }}
    {% endfor %}
{% endif %}


Or element criteria model filters Im trying to do an OR filter for craft.entries and not sure of the syntax

so like this

{% set startedThisYear = craft.entries.find({ section: 'exhibitions', startDate: ">= " ~startDate, startDate: "<= " ~endDate, order:'startDate desc'}) %}

if i wanted it to be

startDate: ">= " ~startDate or startDate: "<= " ~endDate

??

I think that you actually want to use 'and' rather than 'or'. 'Or' would return all entries. This is also assuming that you have predefined the 'startDate' and 'endDate' variables.

{% set params = {
    section: 'exhibitions',
    startDate: 'and, >= ' ~ startDate ~ ', <= ' ~ endDate,
    order:'startDate desc'
} %}

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

If you haven't already done so, you may need to format 'startDate' and 'endDate' variables first.

startDate: 'and, >= ' ~ startDate|date('Y-m-d') ~ ', <= ' ~ endDate|date('Y-m-d')

See this answer for another example.


Trouble calling a plugin's controller function from within an event listener function I am working on extending the formbuilder2 plugin to call and pass the $event variable to a custom Controller after FormBuilder2 has initialized the "onBeforeSave" event within the FormBuilder2 Entry_Controller.

Background Info

Trying to extend the Formbuilder2 plugin
My plugin is called FormBuilder2ExtensionPlugin
Trying to call a Controller Function from within my FormBuilder2Extension_NotifyController and pass $event variables.
Within my FormBuilder2Extension_NotifyController, I am calling the actionNotifyAdmin($event) function.

My Plugin Logic:

FormBuilder2 Plugin saves entry and initializes the "onBeforeSave"
event.
FormBuilder2Extension Plugin listens for "onBeforeSave"
event, and triggers a custom controller function to run. Note: Must be
able to pass the $event variables to the new FormBuilder2Extension
controller function as well.
FormBuilder2Extension Controller will then parse $event data, and
run other FormBuilder2 Controller & Service functions using the $data, so I will need to link from FormBuilder2Extension Controller functions to Formuilder2 Controller functions.

My Problem:

Cannot figure out how to run a Controller Function from within the init() event listener and pass the $event variables as well.

My Current Code: (within main plugin file)

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

       craft()->on('formBuilder2_entry.beforeSave', function(Event $event)
       {

         $url = UrlHelper::getActionUrl('formBuilder2Extension/notify/notifyAdmin', array('event' => $event));

         return;
       });
   }

Closing Remarks:

It works if I use a service function.

Example: craft()->formBuilder2Extension_notify->notifySubmitterOfSubmission($event);

But I would rather not rewrite the same Controller & Service functions that formbuilder2 has already written and place it within my service folder.

Any thoughts…? Thanks!

You really, really shouldn't do this.

I'm not familiar with FormBuilder, but if it is well-built, its controllers will comprise thin methods calling services to do the grunt work; services which you can also call.

If there isn't a service method which does what you want (still assuming everything is well-architected), that means the author chose not to make that functionality part of FormBuilder's API, presumably for a good reason.

If FormBuilder isn't well-built, and instead shoves a load of code in its controllers, well, that's still not a reason for you to do something similarly ill-considered.


How do I get elements using getCriteria from a specific date? I'm trying to get elements in a section created on a specific date. How do I do that?

This is what I've been trying with:

$criteria               = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section  = 'sectionHandle';
$criteria->postDate     = '2014-11-04';

Something like this should work:

$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section  = 'sectionHandle';
$criteria->postDate = array('and', '> 2014-11-03 23:59:59', '< 2014-11-05 00:00:00');
$results = $criteria->find();


What files do you have to be aware of when migrating (i.e config files)? What files do you have to be aware of when migrating a craft application from one domain to another? Are the specific files one should be aware of?

Most craft installs will require moving the database and asset folders, since these are typically not checked into version control. If the site is in version control, it should be a simple clone to install in a new domain.


Is there a way to populate a drop-down with the templates files in a folder? When I have a folder setup for template partials, is there a way I could automatically populate a drop-down with the list of templates in that folder?

This would be useful in the case where I have a complex matrix field set, and would like to select a partial to render or include along with the block's content.

If the drop-down were automatically populated, it would eliminate a lot of time setting up the drop-downs in the backend, and would make it much easier to deploy new feature sets across many Craft based sites as they are developed or improved.

This would be a good task for a plugin.

You'd essentially need to build the plugin to do a couple of things:

(1) Use PHP in a service to list the contents of a directory. Once you have that list, you'd then need to...

(2) Deliver that information to the front end via a custom field type. You can then use your new custom field type wherever you'd like.


Can't load assets or upload assets Currently trying to load an asset located in the following branch of my install:

Craft

html

uploads

Unfortunately when I try to head directly to a specific asset I get the following error message from Craft:

You don't have permission to access /uploads/students/universities/giphy.gif on this server.
Server unable to read htaccess file, denying access to be safe

I've set the following on the uploads folder

chmod 774 /var/www/html/

My site is on DigitalOcean.

Any help would be brilliant

Fixed by doing the following commands:

chown -R www-data:www-data /var/www
service apache2 restart


Retrieve Author Email based on Entry Id I have created a front-end form to facilitate editorial review of user submitted content. I have created a controller action to receive the post.

My question, how do I locate the email address of the author tied to this entry? My objective is to be able to email the author with the results of the editorial review. In order to accomplish this I need to know the user (author) email address etc. Here is my code.

$this->requirePostRequest();

$entryId = craft()->request->getRequiredPost('entryId');
$editorialNotesInternal = craft()->request->getPost('fields.editorialNotesInternal');
$editorialScore = craft()->request->getPost('fields.editorialScore');
$editorialNotes = craft()->request->getPost('fields.editorialNotes');
$sectionId = craft()->request->getPost('sectionId');

$entry = new EntryModel();

$entry->id = $entryId;
$entry->sectionId = $sectionId;

if ( $editorialScore >= 3) {
    $entry->enabled = true;
} else {
    $entry->enabled = false;
}

$entry->getContent()->editorialScore = $editorialScore;
$entry->getContent()->editorialNotes  = $editorialNotes;
$entry->getContent()->editorialNotesInternal  = $editorialNotesInternal;

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

I assume you're talking about getting the email address of the currently logged in user?  That's what EntryModel's authorId property will get set to, if one isn't explicitly supplied.

If so, you can do that with:

$email = craft()->userSession->getUser()->email;

If you want to get the email address of the user that is the author of the entry, then you can do:

$email = $entry->getAuthor()->email;


How to get second last url segment I'm setting up a dynamic thank-you page for all forms added to the site. Client can add forms with freeform to any page and I have set the return url to this:

{{ form.renderTag({
    class: "w-full pb-4",
    returnUrl: craft.app.request.absoluteUrl ~ 'thank-you/'
    }) }}

Which works. However on the thank-you page I would like to set the entry to be the slug of the second last url segment

i.e. if the thank you page is https://domain.com/foo/bar/thank-you then I need to be able to get bar however if the url is https://domain.com/foo/thank-you then I need to get foo

How can I do this? if only craft.app.getSecondLastSegment() were a thing.

so ideally something simpler than this:

{% set entrySlug = "" %}

{% if craft.app.request.getSegment('4')|length %}
  {% set entrySlug  = craft.app.request.getSegment('3') %}
{% elseif craft.app.request.getSegment('3')|length %}
  {% set entrySlug  = craft.app.request.getSegment('2') %}
{% elseif craft.app.request.getSegment('2')|length %}
{% else %}
  {% set entrySlug  = craft.app.request.getSegment('1') %}
{% endif %}```

You can use negative numbers as the parameter for segment which then counts from right to left.

So {{ craft.app.request.segment(-1) }} will get the last segment.

And... {{ craft.app.request.segment(-2) }} will get the next to last segment


Twig - render a rich text field Maybe I have not understand how entries work but I would like to create a rich text field in my plugin without having an entry.

All I want is creating a rich text field with twig but how can I do this? I already read this https://craftcms.com/docs/rich-text-fields but it was not really helpful. I would just like to have something like this just for a rich text field instead of a normal textfield

{{ forms.textField({
    label: 'Ingredient Name'|t,
    required: true,
    name: 'ingredient[name]',
    value: ingredient ? ingredient.name : null,
    errors: ingredient ? ingredient.errors('name') : null,
 }) }}

Could someone please help me?

if I make {{ entry.richTextFieldHandle }} I get the error Variable "entry" does not exist and I don't know how to define entry since I don't use an entry. Do I have to include my own redactor.js if I just want to have an html editor?

If you want a rich text field on a front end - this question has been answered in detail here:
How do I enable redactor rich text editor in a front-end form?

In short technically possible but not recommended.

If you want a rich text field for a back end, i.e. plugin, form:

The craft macros for form fields live in craft/app/templates/forms - however I do not believe there is a macro for a rich text field.  There are text and textarea macros you can use.

However, I think it is possible in a plugin - this apparently creates a rich text field widget in your craft dashboard, so you should be able to pinch the relevant code from: https://github.com/gilleard/RichTextWidget/blob/master/richtextwidget/widgets/RichTextWidget_DashboardWidget.php

(Specifically look at public function getSettingsHtml() I think)


CraftCMS: Search entries by title in CMS In the CraftCMS admin page at /admin/entries/, there is a search bar at the top:

This search bar appears to only search the Body field of Entries.

Is it possible to make this search bar match against the Title field too?

Eg. I have an Entry titled "Example Entry" with a body of "Testing 1 2 3". If I search for "Testing", my Entry will show in the search results. If I search for "Example", my Entry will not show. I would like my Entry to show for the search term "Example"

It does search for the title by default.

I'm assuming you're on MySQL for the database. The searchindex table uses the MyISAM storage engine by default and example happens to be of the default MySQL MyISAM stopwords: https://dev.mysql.com/doc/refman/8.0/en/fulltext-stopwords.html (see "Stopwords for MyISAM Search Indexes"), which it will skip.


Strange 'index.php' Issue I have built and deployed dozens of Craft sites, so I know how to remove 'index.php' from urls, but now I have a site that refuses to accept my most determined efforts to remove it.

This is the situation:

I am using the Craft supplied .htaccess file with the same settings
as all of my other sites.
Just to be thorough, I added 'omitScriptNameInUrls' => 'true', to the config file
double checked all of the general settings in the CP and all is as it should be

After trying a few things, I found that if I use {{ siteUrl }}path I get a clean url, but if I use {{ url('path') }} it leaves that nasty index.php in the url. The same is true for {{ entry.url }}. One last bit of puzzlement - if I manually enter a full path, e.g. http://sitename/news it works fine

I suspect I am missing something obvious, but it is definitely driving me nuts!

This recently tripped me up. 'true' (with quotes) is not the same as true (without the quotes).

Lose the quotes in the config file, clear Craft's caches, and it should stick.

Also make sure your siteUrl is the same as what your web server is configured as. If you have a redirect in there, say www.example.com goes to example.com, and your siteUrl is configured to use the former, that seems to trip up Craft's check too.


In a matrix, link to entries with a future date This is somewhat related to this How can I display a "pending" entry in my "_entry" template?

I have an 'events' section where some entries have a future date - the above link solved my issue to get those listed in a sidebar and display single entries while ignoring the date. So far so good.

I have a homepage slider (a matrix field) where each slide can link to an entry - problem is those entries with a future date from the 'events' section are simply not showing up.(block.slideLink is my entries field inside the matrix)

Any ideas how to get around this?

{% for block in entry.homeslider %}
    {% if block.type == 'slides' %}

{{ block.slideTitle }}

{{ block.slideIntro }}

                        {% for link in block.slideLink %}
                        lees verder...
                        {% endfor %}

    {% endif %}
{% endfor %}

Forgot to take the entry status into account + an additional check for the sectionhandle to cover the custom route.
This solved it for me, if you have a better suggestion I'm all ears.

{% for link in block.slideLink.status('live', 'pending') %}
    {% if link.section.handle == 'events' %}
        lees verder...
    {% else %}
        lees verder...
    {% endif %}
{% endfor %}


Joining sections (Channel) to query based on a related item attribute I've been trying this for a while now, so might have read this before. Sorry about that, I'm struggling really hard to get this right. At first I tried (wrongly) with the eager load features.

I have two channels: events and shows. In the events you can select a show with an entry field. The shows items have a category attached. I need to filter the events, based on the category of the show

Like events with shows where show has category 1. They told me on the slack channel to join the tables I needed, but cannot manage to do it.

Not sure about doing this in a single query. Referencing this doc page section, https://docs.craftcms.com/v3/relations.html#templating, you can make use of relatedTo() by passing in IDs.

Assuming you know the ID of the category already and that ID is 1:

{% set showIds = craft.entries.section('shows').relatedTo(1).ids() %}

{% set entries = craft.entries.section('events').relatedTo(showIds).all() %}

The relatedTo() method doesn't care if the IDs are from Entries or Categories, or even Users and Tags. They're all Elements stored in the elements table so they have unique IDs.


List users connected to me I have a relationship field within my member profile. It allows users to connect to each other, i can list those that currentUser is connected to, but i need to list all other members that are connected to currentUser, i.e. a reverse relationship.

I have this, but it just lists those that the currentUser is connected to, not the reverse, where am i going wrong?

{% set myReverseConnections = craft.users.relatedTo(currentUser) %}

Solution:

    {% set myReverseConnections = craft.users.relatedTo({
        targetElement: currentUser,
        field: 'yourCustomRelationshipField'
    }) %}


Can I query based on a date field rather than the postdate? I'm passing along a year as the yearQuery variable.  Later in my template, I am doing this:

{% set eventEntries = craft.entries
    .section('events')
    .eventStartDate('>=' ~ yearQuery)
    .eventStartDate('<' ~ (yearQuery + 1))
    .orderBy('eventStartDate asc')
    .limit(12)
%}

What I want to do is show all entries for a year based on the "eventStartDate" field - and not the date they were posted.

So basically, all Events that were on in 2018, etc.

Is it possible to do this within this query or is there something I am just missing since I have been up way too late?  I have a feeling I may be missing something obvious...

This should work:

{% set year = '2016' %}

{% set eventEntries = craft.entries
    .section('events')
    .where(['>=','field_eventStartDate',year~'-01-01'])
    .andWhere(['<=','field_eventStartDate',year~'-12-31'])
    .orderBy('eventStartDate asc')
    .limit(12)
%}


Is this a basic error, or do I misunderstand how Craft queries the database? I’ve been wrestling with a site from another developer (who will not be named). He seems to have a pretty solid grasp of PHP, and I had assumed that he also understood Craft well.
However, as I started to look at his templates, I came across code like this:
{% if
  (entry.productDimensionsImage.one() or
   entry.productSpecifications.one())
%}

I would have written it using count() instead of one(), or if I really needed the entry:
{% set prodDim = entry.productDimensionsImage.one() %}
{% set prodSpc = entry.productSpecifications.one() %}
{% if (prodDim and prodSpc) %}

My main concern is that the exact same queries are being used repeatedly throughout a single template; he’s going back to the database over and over again to check the same entry. Then, after he’s done so half a dozen times, then he finally sets it in a variable to loop through it.
So, is there something I’ve misunderstood? Is there a good reason to keep querying the database multiple times in a single template file?
TIA

You're not misunderstanding anything, and your concerns are perfectly valid. I feel like many developers using Craft do not realise that .one() and .all() are in fact database calls, and pretty expensive ones at that. Do it your way, watch the number of DB queries go down in the debug toolbar and feel all warm and fuzzy. (Also, you don't need parentheses in conditionals unless you're doing some complex grouping - {% if prodDim and prodSpc %}).


Importing fields into A&M Forms plugin I'm currently using the A&M Forms plugin and was wondering if I can import fields from the native Craft 2 fields?  I have already created 20 or so fields that I will use in both the native sections and the A&M Forms sections.

I believe A&M Forms stores its fields separately, it does not use the Craft fields that you would use elsewhere. You'll probably need to re-create those fields through A&M Forms to be able to access them in your forms.

To be honest, you should probably stop using A&M Forms if you are not in too deep. It was never ported to Craft 3 (and never will be), so your site will be stuck on Craft 2 unless you put in significant effort later to switch form plugins.


Reset db "auto_increment" count? How does craft manage the counts? And how do I set it to a specific number?

I've already tried to do it manually with something along the lines of

ALTER TABLE tablename AUTO_INCREMENT = 1

But that doesn't really do the trick.

I've also noticed that there is no auto_increment setting in the table structures. Can someone please point me in the right direction?

Thanks!

I assume you're referring to the auto incrementing primary key values in the tables.  Craft doesn't manage that at all, but relies on MySQL to do so.

See here for discussion on how to do it, just keep in mind that there's a pretty high chance you'll be breaking foreign key constraints on existing data.  And I'm pretty sure you'll need to truncate the table first before running the command you tried.

  I've also noticed that there is no auto_increment setting in the table structures.

Sure it does. Check the primary key of any table and you'll see the auto increment bit.


Redactor upload image and file does not work I succeeded to add the image and file upload buttons to my rich text redactor field with the fileupload param in the json config file.

{
    buttons: ['html','formatting','bold','italic','unorderedlist','orderedlist','link','image','video','table','file'],
    plugins: ['fullscreen','video','table',''],
    toolbarFixed: true,
    fileUpload: 'fichiers/'
}

But it does not work : when I drap and drop a file or an image it shows the top bar indicating upload in progress but it finish without anything inserted in my field.

Craft's default Redactor implementation comes with image selection and uploading out-of-the-box that ties to its Assets sources.

If you click this button:

You'll get a modal where you can select already uploaded Assets or upload new ones.


Migrating Server - Craft isn't installed yet I've set up a new Forge server and connected the repo to my site. I've also uploaded the database and copied over the db credentials to the dotenv file. However when I visit the site control panel continue to see this

Have created new db, imported and changed credentials. Still same
Have ftp'd into the server and can confirm all files are there

Is there something else I am missing?

Have you tried running ./craft setup to double check if your setup is correct?

If ./craft setup completes successfully ./craft should find the existing installation and complete any required setup.

In my experience, this is usually related to a non-default /config/db.php or problematic .env file.

Note: Always do a backup before trying anything related to setup just to be on the safe side.


Webhooks: Filter Entry by type (or Section) Using the Webhooks Plug-in, I'm looking to specify a "scope" (or filter) for content type (or section) when using the saveEntry event.

Example:  Fire a webhook only when a new entry of specific type (say recipe ) is saved... not any/all new entries.

My config for my webhook is:

Sender Class = craft\elements\Entry

Event Name = afterSave

Filter = Element is new: ON

Filter options provided allow to filter out new entries, but not entry type.

My solution for now is to try and filter the incoming JSON on my endpoint and only trigger when I see the right Entry Type (untested yet), but would be nice to not send JSON on every single new entry to my webhook if I don't have to.

You can register additional filters.
See the documentation - https://github.com/craftcms/webhooks#filtering-events
The example shows you how to add a filter based on the entry's type as you need.


Get _POST from Select element in Form I'm  trying to get the _POST data for my form in a plugin, and for whatever reason am unable to get the selected option from a select tag:

 <form class="parseResults" action="actions/MyPlugin/myFunctionAjax" method="post" name="submitResults">
    <select name="submission">
        <option value="view">View</option>
        <option value="submit">Submit</option>
    </select>
    <textarea rows="9" cols="80" name="content"></textarea>
    <input type="submit" value="Submit" name="submit">
</form>

And then in my plugin, I can get the textarea form content like:

    $formContent = craft()->request->getPost('content');

But when I try to get the selected option from the #submission select, nothing returns

    $submissionType = craft()->request->getPost('submission');

What am I missing or doing wrong in order to get the selected option?

Form elements need to have a name attribute.

<select name="submission" id="submission">
<option value="view">View</option>
<option value="submit">Submit</option>
</select>

<textarea name="content" rows="9" cols="80" id="content"></textarea>

That should do the trick!


Updating just a single content field from a plugin I have a Task that is running through a collection of elements, moving some data from one field to another. The problem I am hitting (more and more with situations like this) is that in order to update just one field of an element, using the recommended BaseElementModel::setContentFromPost() method, I have to also account for all kinds of other values to get it to validate and save.

I know you need to specify the IDs (from questions like these two) for any relation fields that are required, which is not ideal, but not a huge issue in this case.

However, on this project I also have the Venti plugin installed, with its Venti_EventFieldType for dates and RRULEs, and I'm having to manually pass through a big array of any existing start/end date information into setContentFromPost() just so the validation for that field will pass, even though I'm doing absolutely nothing with that field.

Is there not a single way to update a single field's value, without already knowing the way data needs to be formatted for any other fields that might be on that ContentModel? Otherwise I don't see how a general-release plugin could be made that can modify existing elements, without knowing about the setContentFromPost()-specific data format of every possible Field Type in advance.

I don't have much experience using tasks, but I often write plugin methods to move data around. Typically, I just use the EntriesService saveEntry or RelationService saveRelation as needed.

Here is a sample from a recent data move:

    // Assign category and save entries
    foreach($unassignedEntries as $entry) {

        $success = craft()->relations->saveRelations($field, $entry, array($categoryId));

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


Looping through an assets field type within a matrix field that's eager loaded I'm trying to loop through images that are eager-loaded inside matrix block, but I can't get the images inside a matrix field handle to loop and show each individual image.

The loop I have loops the correct amount of times (based on how many images there are in each matrix block), but it just shows the first image of the loop.

Here's the set up:

Section handle: products
Matrix field handle: imageTextSections
Block type handle: sectionBlock
Field handle: sectionBlockImages
Field type: Assets

I'm trying to loop through images that are eager-loaded inside matrix block, but I can't get the images inside a matrix field to loop and show each individual image.

The loop I have loops the correct amount of times (based on how many images there are in each matrix block), but it just shows the first image of the loop.

Here's the set up:

Section handle: products

Matrix field handle: imageTextSections

Block type handle: sectionBlock

Field handle: sectionBlockImages

Field type: Assets

{% set blocks = entry.imageTextSections.find({
    with: [
        'sectionBlock:sectionBlockImages'
    ]
}) %}

{% for block in blocks %}
...

{% for images in block.sectionBlockImages %}
    {% set image = block.sectionBlockImages[0] ?? null %}

{% endfor %}

{% endfor %}

I figured that the following would work, but I get an error stating that the AssetFileModel.0 is not defined.

{% for images in block.sectionBlockImages %}
    {% set image = images[0] ?? null %}

{% endfor %}

Any guidance would be greatly appreciated!

Eager loading an Assets field simply means that instead of block.sectionBlockImages returning an ElementCriteriaModel, it'll return an array. This means that you can't do stuff like block.sectionBlockImages.first(), but have to use brackets notation – i.e. block.sectionBlockImages[0] to access the first Asset.

Looping over the field would look exactly the same, though. So you'll need to change this

{% for images in block.sectionBlockImages %}
    {% set image = block.sectionBlockImages[0] ?? null %}

{% endfor %}

to this

{% for image in block.sectionBlockImages %}

{% endfor %}

...and you should be good.


Twig replace filter - use part of regex match Using replace filter we can match pattern using regular expressions, but can we use part of the matched string in the second argument of filter? For example, I want to match all numbers and replace each matched number with a matched number enclosed in parentheses.

Craft's replace filter will just use PHP's preg_replace method behind the scenes if it detects that a regular expression has been passed in.

It sounds like you're looking for the PHP preg_match method, which isn't available natively.

There was a plugin that added support for this in Craft 2, but I don't think it's been ported to Craft 3. You might be able to use that as a starting point if you'd like to port it, though.


How get entries by sources in a frontend fieldlayout? I have multiple entries fields that I want to use in the front-end. In the field settings I'll set up a sections source for each field. On the frontend I want a dropdown select box with all the entries from section I'll setup for each entries field. If I'll dump the field sources from the field layout I'll get this:

array(1) {
  [0]=>
  string(44) "section:a0977adf3fd-bd50adf-479cadf-90cd-8d5ef46de79c"
}

How to get entries related to the section source above?

{% entries = craft.entries.section(field.sources).all() %} // This is not working

This is the code where I'll need it for some context

{% for tab in entry.fieldLayout.tabs %}
    {{ tab.name }}
    {% for field in tab.getFields() %}
            <label for="{{ field.handle }}">{{ field.name }}</label>
            {% if field.className == 'craft\\fields\\PlainText' %}
                {# field text settings #}
            {% elseif field.className == 'craft\\fields\\Number' %}
                {# field number settings #}
            {% elseif field.className == 'craft\\fields\\Entries' %}
                {% set entries = craft.entries.section(field.sources).all() %}
                {# entries is empty how to fix? #}
                <select name="fields[{{ field.handle }}][]">
                    <option value="">Choose</option>
                    {% for entry in entries %}
                        <option value="{{ entry.id }}">{{ entry.title }}</option>
                    {% endfor %}
                </select>
            {% endif %}
    {% endfor %}
{% endfor %}

UIDs are not yet usable in queries. You would need to extract the UID of the section from the string then fetch the sectionId to use in your query.

Something like this:

{% for tab in entry.fieldLayout.tabs %}
    {{ tab.name }}
    {% for field in tab.getFields() %}
        {{ field.name }}

        {% if field.className == 'craft\\fields\\PlainText' %}
        {# field text settings #}
        {% elseif field.className == 'craft\\fields\\Number' %}
        {# field number settings #}
        {% elseif field.className == 'craft\\fields\\Entries' %}

            {% set sources = [] %}

            {# Start our `entries` query #}
            {% set entries = craft.entries %}

            {# Iterate over sources #}
            {% for source in field.sources %}

                {# If All sources is selected in field definition, skip this #}
                {% if source != '*' %}
                    {# Extract UID from the string #}
                    {% set sectionUid = source | replace({'section:': ''}) %}

                    {# Fetch sectionId from UID and push in `sources` array #}
                    {% set sources = sources | merge([craft.app.sections.getSectionByUid(sectionUid).id]) %}
                {% endif %}
            {% endfor %}

            {# If we have `sources` then add to our query, else, fetch everything #}
            {% set entries = sources ? entries.sectionId(sources) : entries %}
            <select name="fields[{{ field.handle }}][]">
                <option value="">Choose</option>
                {% for entry in entries.all() %}
                    <option value="{{ entry.id }}">{{ entry.title }}</option>
                {% endfor %}
            </select>
        {% endif %}
    {% endfor %}
{% endfor %}

This will cater for multiple sources as well as All being chosen in your field definition


Include an extension in your template name, including ".twig" (e.g. robots.txt.twig) I like to use .twig for my templates for easy syntax switching, but it doesn't seem to work when my template requires an extension as part of its name.

For instance:

robots.txt works fine
robots.txt.twig, doesn't. The matching request is now {siteUrl}/robots.txt.twig, and I don't get the automatic Content-Type matching that happens when it is just robots.txt.

I figure this just isn't currently supported, but I would be nice!

This is because right now, if your template path includes an extension, Craft assumes that you’re explicitly providing the full template path, and won’t try appending the defaultTemplateExtensions to it. (See a full explanation here.)

robots.txt does make a good use case for why we should append those extensions anyway, though. We shall consider it :)

UPDATE

We changed this behavior in Craft 2.2, so now a request to /robots.txt could resolve to a template called /robots.txt.twig. http://buildwithcraft.com/updates#build2579


Multi-user blog "repost entry" functionality In our Craft Pro site we've enabled public registrations and allow anyone to create an account and make entries in a "blog" channel.  These entries are then filtered via URL segments - so /blog/ will show a listing of entries by each user.  A user can create different entry types (video/audio/text/etc) which are handled by different templates.

I'm trying to add the ability for a user to "reblog" or "repost" another user's entry - I'm not sure of the best way to do that though.  The ideas I've had are:

Create a new entry type (reblog), with a field that stores a reference to the original entry ID and allows the user to add a comment
Use a custom plugin to create an entry as above
Clone the original entry data into a new entry and allow the user to edit it
Create a new channel for reblogs which the user doesn't have permission to post to via the CP, and try to hack around that using a plugin and frontend forms

My issue is that, for usability reasons, I'd very much prefer to hide the original entry ID reference field (if this is handled through the CP) but I don't know if that's possible?  We're relying entirely on the CP for creating entries at the moment, so it'd be a bit clunky if we moved the handling of reposts to a separate section of the site.

Also if I simply reference the original entry ID in a field, while it would be cleaner than cloning the original entry's content (assets/etc) and creating a new post for the current user, I'll most likely still have to create a new entry type (reblog) to house the new post, which would then appear in the "Entry Type" dropdown when accessing the create entry page, which would be pretty confusing to the end user, unless I made the original entry ID some kind of custom FieldType with a live-search sort of feature?

I'm beginning to think that perhaps the best way is to handle this through a plugin / frontend form, but that feels super hacky.

Any suggestions on how best to approach this issue?  I'm totally open to any and all ideas!

I think it's going to be a lot easier if you go the custom plugin route with your own front-end forms for everything.  Not hacky at all!


How do you get the user id on the front-end? I'm using Craft Pro to make a website where users have a private area. Users register and when login happens they are redirected to a page in the private area with respective info about that user.

When i use {% requireLogin %} with {{ currentUser.id }} Craft 3 outputs the ID of the user that has active login in the CP (control panel).

But what I need is the ID of the user that made login in the frontend to access private area and not user ID that is logged in CP.

I'm reading the Craft 3 docs but I didn't find the answer I'm looking for.

Any suggestions?

In Craft, there is no difference between the currently logged in user in the CP, and the currently logged in frontend user. Whenever a user logs in (be it through a frontend form, or the CP login page), it results in that user being logged in. Period. There's no 'being logged in in the frontend', as far as Craft is concerned.


How do I use a leading slash with the url() function? The url() function won't work with a leading slash as it's path parameter.

For example, this: {{ url('jobs') }}
Outputs: http://example.com/jobs

But this: {{ url('/jobs') }}
Just outputs: /jobs

This is easy enough to remember for developers, but if you're passing a variable from a user input field like {{ url(entry.myField) }}, users can accidentally break a link if they add a leading slash.

How can I make the url() function more resilient when relying on an unknown variable?

Use the trim filter to automatically remove leading and trailing slashes like so:

{{ url( entry.myField | trim('/') )  }}


How can you retrieve entries with a specific locale in a plugin? I have this:

$this->requireAjaxRequest();

$segments = craft()->request->getActionSegments();

$lang = $segments[2];

$entryId = $segments[3];

$entry = craft()->entries->getEntryById( $entryId );

$response = array(
    'titre' => $entry->typeChambre,
    'etage' => $entry->etage->label,
    'surface' => $entry->surface,
    'loyer' => $entry->loyer,
    'charges' => $entry->charges,
    'description' => $entry->description,
    'photos' => $entry->photosChambre
);

$this->returnJson($response);

Thanks

You'll want to use an ElementCriteriaModel:

$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->id = $entryId;
$criteria->locale = $lang;
$entry = $criteria->first();

if ($entry)
{
    $response = array(
        'titre' => $entry->typeChambre,
        'etage' => $entry->etage->label,
        'surface' => $entry->surface,
        'loyer' => $entry->loyer,
        'charges' => $entry->charges,
        'description' => $entry->description,
        'photos' => $entry->photosChambre
    );

    $this->returnJson($response);
}


How do I flush the query cache? How do I flush Craft's query cache so that I may query a relationship field again in the same web request with a new set of parameters? In this particular scenario, I need to handle it inside of a custom module so I need PHP and not Twig.

Yes, I am fully aware of cloning the original query in order to make a second query with modified parameters so do not mention that in your answer. It is not an option in this scenario and it does not answer my question.

Craft is using the default Yii queryCache component, which is set to the file system cache by default (i.e., what's in storage/runtime/cache.

There's no way to clear specific items in that cache, but you can clear all of it with Craft::$app->getCache()->flush().


How to reverse the rows in a table? I could do with flipping the rows in a table, within a template. Is that possible?

Reverse it!

    {% for row in entry.myTableFieldHandle|reverse %}

{{ row.columnHandle }}

    {% endfor %}


Help understanding an error message from Dukt OAuth plugin I'm using the Dukt Twitter plugin which requires the Dukt OAuth  plugin.

Both are working perfectly on both my local Dev environment and the remote Staging environment, but not on the Live site. Both plugins install with no errors or problems. Configuring the OAuth plugin (for Twitter only) is fine as well - it accepts the keys/credentials generated from the Twitter API Management Console and shows as "configured" on it's status screen.

However, when I then go to the actual Twitter plugin config and hit the "Connect to Twitter" button, I get this error message:

Fatal error: Class 'League\OAuth1\Client\Server\Twitter' not found in /webserver/domains/[CLIENT]/live/craft/plugins/oauth/providers/Twitter.php on line 46

Anyone have any idea what this error message means?

I suspect it's more to do with the server or site config than the actual plugin but I'm not sure where to start looking as I don't understand why it can't find that namespace

It was indeed missing files, as suggested by Alec and Benjamin. All down to some non-specific .gitignore rules that meant it was ignoring all "src" folders - which is one of the folders created by the composer install

Thanks for your help guys!


Output entries sorted by category title and paginate I'm stuck on an issue where I have to paginate a list of entries that would be sorted by category title.
So basically, I need to:

fetch entries in the 'project' section
sort those entries by the 'projectYear' category title (2016->2002)
paginate it (limit 5 for example)
sort entries by title (a->z)

The output expected would look like this

Page 1
    2016
        Project A
        Project B
        Project C
    2015
        Project D
        Project E
Page 2
    2015
        Project F
        Project G
    2012
        Project H
    2010
        Project I
        Project J

At the moment, I have this "working"

{% set categories = craft.categories({
    group: 'projectYear',
    title: 'not Unknown',
    order: 'title desc'
}) %}

{% set allProjects = craft.entries({
    section: 'projects',
    relatedTo: categories,
    order: 'title asc'
}) %}

{% for year, projectsInYear in allProjects | group('projectYear.first().title') %}
    {{ year }}
    {% for project in projectsInYear %}
        {{ project.title }}
    {% endfor %}
{% endfor %}

By "working" I mean that it outputs all project entries sorted by title & grouped by projectYear... but those projectYear groups are not sorted by title and it also lacks a pagination system.

FYI: If I limit to 5 in craft.entries, it outputs the 5 first entries sorted by title and groups them by year after that. Instead, I want it entries to be first grouped by year and then get the 5 of those first entries.

Could anybody help me figure out how I can get the output I want or lead me in the right direction?

Thanks!

PS: we used postDate originally and it worked great, but we had to move from using postDate so it's not a possibility anymore.

Not exactly what you're looking for, but it gets you closer.  This should display the order you want, but it doesn't have any pagination (and honestly I'm not sure if that's possible using Craft's {% paginate %} tag along with your other requirements.

IMO, you're probably going to be better off doing this in PHP either using a Template Hook or a custom plugin.

Regardless, here's the Twig code:

{% set allProjects = craft.entries({
    section: 'projects',
    order: 'title asc'
}) %}

{% set categories = craft.categories({
    relatedTo: allProjects,
    title: 'not Unknown',
    order: 'title desc'
}) %}

    {% for category in categories %}

{{ category.title }}

        {% set relatedEntries = craft.entries.relatedTo(category).order('title asc') %}

            {% for entry in relatedEntries %}

{{ entry.title }}

            {% endfor %}

    {% endfor %}


failed: could not find driver Craft CMS 3 - I have used the CLI ./craft setup script to set the database connection on my local machine. I setup a MySQL connection, but when it attempts to validate my credentials, I get "failed: could not find driver". However, when I make a direct MySQL CLI connection using the same credentials, it works just fine. Why can Craft CMS not connect to my local database?

For anyone from the future, this worked for me utilizing Ubuntu 16.0.4 with PHP7.2:

Try this command:

sudo phpenmod pdo_mysql

If it says it cant find the package, install this:

sudo apt-get install php7.2-mysql

Check your active php.ini file for this line(my active .ini was located n /etc/php/7.2/apache2/php.ini):

;extension=pdo_mysql

If it has a semicolon before it, remove it, and then save. For good measure, run this again:

sudo phpenmod pdo_mysql

Restart apache. Good day.


Get related entry data within a plugin (ElementCriteriaModel) without extra queries I have the following code:

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

// Loop
foreach ($criteria as $entry)
{
    echo $entry->id.'
';
    echo $entry->title.'
';
    echo $entry->sport.'
';
}

The sport field is an Entry field, pointing to an entry in a different channel. My question is, how can I get the data from the related entry (i.e. the title) without an extra query per row? Can I eager load it? Or get the sport entries in a separate query and then combine the data?

I need to get the title of the related sport entry. The following works but gives an extra query for every row:

$entry->sport->first()['title'];

Anyone? Thanks in advance

I fixed this now by using the method buildElementsQuery, like so:

    $query = craft()->elements->buildElementsQuery($criteria, $contentTable, $fieldColumns);

After that, I was able to add custom joins to the query:

$query
    ->addSelect('sport.title sportTitle')
    ->leftJoin('relations sportRelation', 'sportRelation.sourceId = elements.id AND sportRelation.fieldId = 71')
    ->leftJoin('content sport', 'sport.elementId = sportRelation.targetId')

This gave me access to the data I need, without running extra queries. Thanks go out to Bob Olde Hampsink for showing me this.

I'd love to hear though if there is a simpler way that won't require custom SQL, but for now this will do the trick.


Do tuples exist in twig? If so, how can I create one? Is there a tuple data structure in Twig? If there is, how do you create one?

None that I'm aware of.  Since Twig ultimately gets compiled down to PHP and PHP doesn't have first-class citizen support for tuples, you're limited there.  You can quasi-fake them with arrays and the list function, but I don't think there is a Twig equivalent for list.


Change translation format in Craft CMS I'm trying to get my Craft translations to work with the translation management tool Phraseapp.

The standard format for translation-files in Craft CMS looks like this:

# de.php

return [
    'good_morning' => 'Guten morgen',
    'KEY' => 'GERMAN_TRANSLATION_VALUE'
];

But this format is not supported by Phraseapp.

Is there a way to return json or yaml instead?

We used to use PhraseApp to manage Craft translations, but as of Craft 3, we don't anymore (everything is now on Github).

When we were using them, we wrote a quick PHP script that would take the PHP based translation file format Craft uses, parse them and convert them to a format that PhraseApp could use.  Then there was another quick script that would reverse the process when we pulled them down.


Show entry on certain date, regardless of year A project I'm working on needs to show a daily reading depending on the date you access the page. I plan to create entries for each day of the year, and each year it will show the post for that day.

For example, I'll create an entry with a post date of May 1, 2015. That entry should show on May 1, 2016/2017/2018, etc.

I've tried only putting in MM-DD in the postDate parameter, but no luck; that throws a PHP error. Any ideas?

I fear this is not possible with a simple postDate parameter and you have to find a workaround.
The Twig apporach would be to loop all events and filter the right ones with a simple conditional.

{% set events = craft.entries.section('events').limit(null).order('postDate asc') %}
{% for event in events %}
    {% if event.postDate|date('m-d') == now|date('m-d') %}
        ...
    {% endif %}
{% endfor %}

If you'd like to paginate the results, collect / merge entry IDs within the for loop first and
then prepare another ElementCriteriaModel with these IDs in its id param, to get the entries.


Focal Point - Changes don't take effect when Saved a second, or third time When I set the Focal Point for the first time, it works. If I change the Focal Point and save again, the changes do not take effect.

Now, if I set the Focal Point and "save as a new asset", I can use that new file and its Focal Point. But, if I change that Focal Point, I have to "save as a new asset", which creates multiple copies of the same image.

I'm also using ImageOptimize plugin. Any ideas why my Focal Point changes don't take effect?

If you're using Chrome, make sure you open up the URL to the image itself (you can do this by clicking on the variant in the OptimizedImages field) and do a Shift-reload. Chrome will locally cache images so you won't see the changes unless you force it to reload the image from the source.


How to translate the whole page? Ok so I know this is something really basic but unfortunately i could not find it in the documentation and I don't have a lot of experience with localisation at all. i have set up two locales in my craft admin panel and I have also updated general.php, etc to set up content localisation. But unfortunately the content that i set as translatable is still displayed in english at both the en and zh site post-fixes. Can somebody simply explain how can I use a link to change the language of all my content on a page to another language inside of a template?

Do you have separate index.php files for your locales? There is a nicely explained documentation for this on the official Get Help pages: "How do I show localized content on the front end?"


YouTube video embeds in rich text field not saving When adding a YouTube video to a rich text field the video embed appears as expected. The entry then fails to save with no error (if I make other changes at the same time they don't save either).

Strangely, this only happens on the live server (my local MAMP setup saves the entry as expected) so I'm thinking it might be a server config thing?

I have unchecked the 'Clean up HTML' and 'Purify HTML' options for the field. It's in a Matrix field if that makes any difference.

Here's my Redactor config (added everything to allowedTags to try to figure it out):

{
  "buttons": ["html","formatting","bold","italic","unorderedlist","orderedlist","link","image","video"],
  "plugins":["fullscreen","video"],
  "toolbarFixed": true,
  "pastePlainText": true,
  "allowedTags": ["a", "abbr", "address", "area", "article", "aside", "audio", "b", "bdi", "bdo", "blockquote", "br", "button", "canvas", "caption", "cite", "code", "col", "colgroup", "dd", "del", "dfn", "div", "dl", "dt", "em", "fieldset", "figcaption", "figure", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "header", "hgroup", "hr", "i", "iframe", "img", "input", "ins", "kbd", "keygen", "label", "legend", "li", "map", "mark", "menu", "nav", "ol", "optgroup", "option", "p", "picture", "pre", "q", "rp", "rt", "ruby", "s", "samp", "section", "select", "small", "source", "span", "strong", "sub", "summary", "sup", "table", "tbody", "td", "textarea", "tfoot", "th", "thead", "time", "title", "tr", "track", "u", "ul", "var", "video", "wbr"],
  "replaceDivs": false,
  "formatting": ["p"],
  "formattingAdd": {
    "heading": {
      "title": "Heading",
      "args": ["h2", "class", "h2", "toggle"]
    },
    "subheading": {
      "title": "Subheading",
      "args": ["h3", "class", "h3", "toggle"]
    }
  }
}

My guess is you're running into one of two issues.

You're bumping into your php.ini file's max_intput_vars and/or post_max_size limitations.
Your server has something like Suhosin or mod_security installed and the content you're trying to save in the Rich Text field is triggering one of their security rules.