Allow users to change email address on front-end form I've got a front-end user profile form working on a client site I'm developing, but the one thing that I'm having trouble with is allowing users to change the email address associated with their account via this form.

When I use my email field to attempt an email address change, I get a verification email generated by Craft sent to the new email address, but the email change is not reflected in either the CP or on the front-end when I refresh the form.

I've pasted an abbreviated version of my form below with some irrelevant fields omitted.

What am I missing?

 <form method="post" accept-charset="UTF-8" enctype="multipart/form-data">

    {{ getCsrfInput() }}
    <input type="hidden" name="action" value="users/saveUser">
    <input type="hidden" name="redirect" value="account/my-account?m=updated">
    <input type="hidden" name="userId" value="{{ currentUser.id }}">

    {% macro errorList(errors) %}
        {% if errors %}
            {% for error in errors %}

{{ error }}

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

    {% from _self import errorList %}

    <fieldset>

        Username
        <input id="username" type="text" name="username" value="{{ currentUser.username}}">
        {% if account is defined %}
            {{ errorList(account.getErrors('username')) }}
        {% endif %}

        First name
        <input id="firstName" type="text" name="firstName" value="{{ currentUser.firstName}}">

        Last name
        <input id="lastName" type="text" name="lastName" value="{{ currentUser.lastName }}">

    </fieldset>

    <fieldset>

Fill in both fields below to change the email address associated with your account

        Email
        <input id="email" type="text" name="email" value="{{ currentUser.email }}">
        {% if account is defined %}
            {{ errorList(account.getErrors('email')) }}
        {% endif %}

        Current Password
        <input type="text" id="currentPassword" name="password" />
        {% if account is defined %}
            {{ errorList(account.getErrors('currentPassword')) }}
        {% endif %}
    </fieldset>

    <input class="btn btn-primary btn-large" type="submit" value="Save changes" />

</form>

When I use my email field to attempt an email address change, I get a verification email generated by Craft sent to the new email address, but the email change is not reflected in either the CP or on the front-end when I refresh the form.

The user's email address won't actually update until you click the link in the verification email the user receives.


Change start of the week in Date Picker A simple question with hopefully a simple answer.

How can I make the date picker in the admin area start the week (i.e. each new line) with Mondays rather than Sundays?

I'm sure it will just be a configuration issue. I just can't see where to change it.

Thanks

Currently this isn’t configurable, but I suppose it should be. I’ll add it to the list, and update this answer when it’s possible.

Update:

As of Craft 2.3, each user can choose their own preferred week start day from their account settings.


Craft 3 Image quality is terrible after asset upload from admin panel After I upload an asset (png), the image loses quality. I changed the defaultImageQuality from its default value of 82 to 100 but didn't make a difference. I can't add these assets via FTP as I need users to be able to add them from the admin panel. Any advises?

Converting my comment(s) into an answer...

Make sure you are using the ImageMagick library to handle image manipulation (instead of the default GD library). It provides much better results.

Craft will "clean" every image that gets uploaded. This prevents anyone from accidentally (or intentionally) uploading malicious scripts to your site hidden within an image file.


Macros, Variables and Includes Trying to get my head around this and make my code a little DRYer.

I have a _helpers macro file. Like so:

{% macro date_formatted(givenDate) %}
    {{ givenDate|date("l, jS F Y") }}
{% endmacro %}

{% macro product_title(product) %}
    {{ product|replace(' HA', 'HA')|raw }}
{% endmacro %}

This file is used in various places throughout the website and is included in various base templates using {% import '_macros/_helpers' as helpers %}

I then have another macro for creating products (teasers and various code that would be repeated). This contains:

  {% macro teaser(product, imgSize, className) %}
    {% set cart = craft.commerce.getCart() %}
    {% set category = product.category.first() %}
    {% import '_macros/_helpers' as helpers %}

        {% set thumbAsset = product.productImage.first() %}
        {% if thumbAsset %}

        {% endif %}

{{ helpers.product_title(product.title) }}

{{ product.defaultPrice|currency(cart.currency) }}

            View Product

            {% if className == "product-teaser--featured" %}
                {{ category.title }} Range
            {% endif %}

{% endmacro %}

{% macro alsoPurchased(product, imgSize) %}
    {% set cart = craft.commerce.getCart() %}
    {% import '_macros/_helpers' as helpers %}

        {% set thumbAsset = product.productImage.first() %}
        {% if thumbAsset %}

        {% endif %}

            {{ helpers.product_title(product.title) }}

            {{ product.defaultPrice|currency(cart.currency) }}

{% endmacro %}

The problem/question I have come up against is that it seems I have to include {% import '_macros/_helpers' as helpers %} in each Macro and also the same goes for setting the variable for cart. {% set cart = craft.commerce.getCart() %}

Is there a better way of doing this? Or a DRYer way of doing this? So I don't have to repeat my includes and setting of variables for each Macro block?

You aren't able to pass an import into a macro. So helpers needs to be imported into each macro file that uses it.

You can however pass the cart to your macros. As a side note, it's definitely best to set the cart variable in a global template - this means you're only ever setting it once. All templates that extend this global template then inherit cart. The way macro's work though means they need to have these variables explicitly passed to them. They don't inherit variables in the same way includes do or when you extend templates.

You can then pass cart to your macro like so:

{# Variable set in an extended template or current template #}
{% set cart = craft.commerce.cart %}

{# Variable is passed to the macro #}
{{ teaser(product, imgSize, className, cart) }}

Macro file then edited to take variables:

{% macro teaser(product, imgSize, className, cart) %}
    {# We still need to import our helpers into this macro file #}
    {% import '_macros/_helpers' as helpers %}

    {% set category = product.category.first() %}

        {% set thumbAsset = product.productImage.first() %}
        {% if thumbAsset %}

        {% endif %}

{{ helpers.product_title(product.title) }}

{{ product.defaultPrice|currency(cart.currency) }}

            View Product

            {% if className == "product-teaser--featured" %}
                {{ category.title }} Range
            {% endif %}

{% endmacro %}


How to edit the Date Created value that appears on the Entry page I've just noticed that there's a Date Created value that appears for each entry in the control panel. Here's a screenshot:

.

How can I edit this Date Created value?

I've just looked at the craft_entries table and edited the dateCreated value for the entry in question, but when I refreshed the entry in the control panel, the Date Created value remained as it was previously.

If you want to edit that value in the database, then you'll need to find the corresponding row in the craft_elements table and update the dateCreated column there.


Sprout Forms Confirmation Page Field Not Defined I'm trying to create a confirmation page for a Sprout form, where I want to check if a certain field is present, and if so, check for a value, so I can return a message based on that value.

I'm using lastEntry, and am able to pull the valid fields in without a problem, but it's having issues checking whether the field is defined. I'm currently using the following code:

{% set lastEntry = craft.sproutForms.lastEntry() %}
{% set qualified = true %}
{% if lastEntry.fieldName is defined and lastEntry.fieldName == 'no' %}
    {% set qualified = false %}
{% endif %}

When I use the code above, and the field has not been used in the particular form, I see:
Craft\SproutForms_EntryModel and its behaviors do not have a method or closure named "fieldName".

It appears Craft is seeing the field as defined, but not. Anyone have any ideas on what I could do to figure this out?

Thanks!

When you set the lastEntry variable on your page. You are either setting lastEntry to be the SproutForms_FormEntryModel or null. In both cases you are defining the variable.

{# Sets lastEntry to SproutForms_FormEntryModel or null #}
{% set lastEntry = craft.sproutForms.lastEntry() %}

If you then want to test the lastEntry variable, you'll need to use something different that is defined.

I believe the following will work:

{% set lastEntry = craft.sproutForms.lastEntry() %}
{% set qualified = true %}
{% if lastEntry and lastEntry.fieldName == 'no' %}
    {% set qualified = false %}
{% endif %}

Testing for if lastEntry will work just like using if lastEntry is not null. The secondary part of your conditional should only be evaluated if if lastEntry returns true, in which case your SproutForms_FormEntryModel would exist and the fieldName field would be defined, with or without a value.


Is it possible to use the MySQL LIKE directive in an ElementCriteriaModel? In a plugin, I'd like to pull all Assets with filenames starting with a certain string (the $prefix variable, in the below examples).

It's possible to do this with a custom DbCommand:

$results = craft()->db->createCommand()
    ->select('assetfiles.*')
    ->from('assetfiles assetfiles')
    ->where(array(
        'like',
        'assetfiles.filename',
        $prefix.'%',
    ))
    ->queryAll();
$assets = AssetFileModel::populateModels($results);

However, I'd like to do this using an ElementCriteriaModel. The below doesn't work:

$assets = craft()->elements->getCriteria(ElementType::Asset, array(
    'filename' => 'LIKE "'.$prefix.'%"',
    'limit' => null,
))->find();

In the above example, is the syntax off, or is not possible to use LIKE in an ElementCriteriaModel parameter?

The * wildcard character should do the trick.

c.f. https://craftcms.com/docs/templating/elementcriteriamodel#parameter-value-syntax

$assets = craft()->elements->getCriteria(ElementType::Asset, array(
    'filename' => $prefix.'*',
    'limit' => null,
))->find();


Still not able to manage tags in Craft 3? I have page where I display some items and there are filters by tag. So I make a list of all tags that are created. Then when the user click on some of the tag, he see only the product with that tag. Now I found out, that some of the tags are not used or written wrong. I want to delete them from the system. I found this question, that say it is not possible to done it in Craft 2. I am using Craft 3 is it possible to done it in the Craft 3?

Short answer is "no, this still isn't possible".

Longer answer is:

The Tag Manager plugin from Craft 2 will not be ported.
Pixel & Tonic have mentioned the possibility of rolling that functionality into Craft's core.

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

So what can you do about it? Vote up this feature request!


How can I display the Discount Value onSale of Products I am trying to display the Discount Value (%) of Products with the onSale Tag. What works for now is to display only the Products which are onSale. But I can't figure out which value stores the Discount Value.

{% set products = craft.commerce.products.find() %} {% for product in products %}

    {% if product.defaultVariant.onSale == true %}

Sale!

{{ amount.saleAmount }}/h6>

off

    {% endif %}

I haven't done this myself, but I see two ways to get the percentage:

Take the product.defaultVariant.saleAmount and use maths in twig to work out the percentage - that should definitely work.  Twig math is a good general solution if you can't get the numbers you need directly from Commerce. See:

http://twig.sensiolabs.org/doc/templates.html#math

However, I think you can use

 {% set sales = craft.commerce.getSales() %}

...to get all your SalesModels.

(see /craft/plugins/commerce/models/Commerce_SaleModel.php) as this model is not really documented yet it seems.

You'd loop through those and get the particular sale you're after (e.g. by id).  Then, it appears there is code in there to  getDiscountAmountAsPercent to get what you're after....however while DiscountModel has an attribute of percentDiscount on it, SaleModel does not appear to so I don't think you can get at it directly in your templates currently.

Unfortunately I am a bit pushed for time in terms of actually trying it to see.  But Twig maths will do it for sure if you get stuck with a more direct approach!


Changing base currency I set up a new shop and the base currency is US dollars. However I want to change this to Euro's. How can I do this?

In Commerce --> Settings --> Payment Currencies I can add new currencies but I can't set it as the new default.

Am I looking in the wrong spot?

Click on USD under Commerce->Settings->Payment Currencies and change the dropdown from USD to EUR.  That will become Commerce's new base/primary currency.

If you also want to support USD, you can add it as a second currency now and setup a conversion rate.


Check for an image in Rich Text Field I have a DIV wrapping a Rich Text field.  I would like to add a class name to the DIV only if an image is present in the text field.  Is there a way to check for an image?

You could use the in operator to search for a substring in your markup.

{% set imageExists = '<img' in entry.body.getRawContent() %}
{% set classAttr = imageExists ? 'with-image' : '' %}

<div class="{{ classAttr }}">
    {{ entry.body }}
</div>

Another, probably bit more reliable way to test for <img> elements is to use the Retcon plugin, which uses DOMdocument to parse the markup.

A combination of retconOnly and length filters should get you there.

{% set imageExists = entry.body|retconOnly('img')|length %}


How to Deploy CraftCMS to Dreamhost w/Github I was recently able to get Craft CMS installed on my local server and I am using MAMP to host locally as I develop the site.

I have never set up a site on my own, so I was hoping someone could give me some instructions on how I eventually post my site.

I already have a domain registered through DreamHost and I am prepared to set up a managed server or VPS, but how will this work in the end?

Ideally, I would have things set up so that I could push everything to github and the site would update automatically. I've used GitHub pages before, so this is the process I'm most familiar with.

Thanks

I'd recommend against DreamHost, FWIW -> How Agencies & Freelancers Should Do Web Hosting

In any event, to do what you want to do, you'll need something that triggers on that when a push to GitHub or what have you happens. If you use Forge as a provisioner, that comes baked in.

If not, you can use a service like buddy.works or the like to do it for you. This is discussed a bit in the Setting up a New Craft CMS 3 Project article under the DEPLOYING CRAFT CMS section.

We also discuss it on the Website Deployment without Tears podcast on devMode.fm

...but the general idea is that something has to receive a notification from GitHub when you push to a particular branch, to kick off the deployment process for you. Here's what my deployment script looks like on Forge: My deploy script for Forge


Entry saved trigger not working Using the Sprout Email plugin. The only notification triggers that are working are related to users. Any notifications with triggers related to entries (created, updated, deleted) do not send an email, not even a test email.

I'm using Craft Client 2.4.2688.

The Sprout Email Example Notification templates are designed to illustrate an example of the the Events that take place when a user is saved. They illustrate how to set custom variables for the User Events in both the Control Panel and in the template itself.  While in most cases, you won't need to customize things in both places, the example is meant to be illustrative of what is possible so you can decide what the best option is for your situation.

The issue here arises when the Notification in the Control Panel is updated to be triggered on a Entry-related event, instead of a User-related Event, and the same notification template is used.

When the Entry-related Event is fired, the User-specific template tries to access user-specific variables and a Twig processing error causes the template to err out.

The key thing to understand here is that, when Sprout Email fires an Event, it only has two types of variables available to the template you are using:

Information about the Notification Email itself, like the Subject Line. This info is available via the entry object (i.e. {{ entry.subjectLine }})
Information about the Event the trigger is associated with.  This information may change depending on the Event you are using.  This info is always available via the object variable (i.e. {{ object.value }}), but the available values will differ based on the event.

To fix this issue, you need create templates for your Notification Email that:

Are built in a generic way so that they make no assumptions about what variables will be passed to the template.  If dynamic variables are needed, they can be handled directly in the fields within the Control Panel.
Are designed to expect the right variables for the Event that they are being used for.

If you run into trouble, try simplifying the templates you're using to hard-coded text.  Confirm that the Event is working as expected and that the Notification email is being fired as expected.  Once you confirm that, then try to add in variables in one by one and testing to confirm you're adding the variables correctly.

Sprout Email creates a log file at craft/storage/runtime/logs/sproutemail.log. You should see any template errors that may be happening there to help troubleshoot and diagnose what is happening.


How to get a result from search even if the search query contains a part of title? Suppose there are three Entries:

Entry One
Section One
Channel One

I need to get Section One in result when I search Sect. Is this possible ? I am using

{% set entries = craft.entries.search(query) %}

to get the results. But keyword sect doesn't return any result.

Like stated in the docs you have to place * around your search term

{% set results = craft.entries({
    search: {
        query: '*sect*',
        subLeft: true,
        subRight: true
    }
}) %}

Note: it would be easier to help you if you show us your query variable


CKEditor fieldtype overlaying redactor I've created a Fieldtype to use CK Editor so can take advantage of the advanced table formatting options over Redactor. However I want to keep Redactor for other content management. I came across this post so thought would give it a go: Craft WYSIWYG editor and CKEditor

All seemed to be working well but now whenever I focus on a redactor field the CKEditor buttons pop up. Any thoughts as to why this might be happening? Screenshot:

Fieldtype code posted up at https://gist.github.com/cole007/1ffa5036f8b79516ca34406d7b6833bf

Any thoughts as to what might be causing this?

Cheers

Cole

At first glance, it looks like a little conflict around absolute positioning

I've had good success in 'massaging' the Craft CP using: Craft CPCSS

See here for a little more, too: Remove outdent & indent from Redactor2 "lists" button

Hope it helps, Cole


Include results in "Object of class Craft\ElementCriteriaModel could not be converted to string" I have a template with just this code:

{% include 'amenities/_types/amenities' %}

This results in a template error:

Object of class Craft\ElementCriteriaModel could not be converted to string

Never encountered this one before. What is causing this?

Well I now see this error was caused by the included template and not the fact that I was trying to include a template.

I thought that the error message would show the error on the included template that was the actual source of the problem, but it was just referencing the include as the error.


If URL Contains x Then Do Y in Twig / Craft Template? I've got a website that has a resource center, news center and blog where each of those sections has a high quantity of assets that can be filtered by topic / type / date, etc. Additionally, due to the quantity of assets, we're using pagination to spread the assets across multiple pages.

All of the filtering and pagination creates a variety of worthless but currently crawlable URLs that we'd like to hide from the search engines.

I'm attempting to deploy the meta name="robots" content="noindex, follow" tag to all of the paginated / filtered URLs while keeping the overview pages indexed. It seems that the most logical way to do that is based on a consistent URL string that appears in both pagination and filtering instances.

How can I add a rule within my template that will insert the meta tag based on whether or not a string exists in the current URL appearing in a user's browser?

Any help would be much appreciated. Thanks!

If the string you're looking for is part of the URI segment, then something like:

{% if (craft.request.getSegment(3) == 'mySpecialKey') %}
    <meta name="robots" content="noindex, follow">
{% endif %}

(Adjusting the 3 for whichever part of the segment it's actually in.

Or if it's part of the querystring, then use craft.request.getParam('mySpecialKey').


Locale-specific country select menu Wonder if you can help? Got a booking form on a multi-locale site and I need to include the user's country in the form. I'm using Craft's LocaleData class to output locale-specific locales (e.g. Angleterre for England)...

<select name="country" required>
{% for country in craft.i18n.getLocaleData().getAllTerritories() %}
    <option>{{ country }}</option>
{% endfor %}</select>

Works great except it outputs stuff I don't need like "World", "Oceana", "Ascension Island" etc... Is there any way to control the output, like maybe show countries only and not regions?

If you look at the data file for a locale in Yii you can see that the territories property includes regions and continents as you've found. These all have keys with numeric values, whereas countries have two character keys. Using this knowledge, you can loop over the keys and values of the territories array as you are doing, but only output those with two character keys. You'll also probably want to omit the Unknown Region value which has a key of zz.

Untested, but this should work:

<select name="country" required>
    {% for key, value in craft.i18n.getLocaleData().getAllTerritories() %}
        {% if (key matches '/[a-z][a-z]/') and (key != 'zz') %}
            <option>{{ value }}</option>
        {% endif %}
    {% endfor %}
</select>

EDIT

OK, so my original idea doesn't work as craft.i18n.getLocaleData().getAllTerritories() doesn't preserve the territory array keys from the Yii i18n data files.

I'm not sure you can do what you want to do natively in Craft, but it looks like John D. Wells' Territories fieldtype plugin may provide what you need. You don't need to use the fieldtype as there is an undocumented Twig variable provided that gives you an array of localised territory names, excluding the regions. Try this:

<select name="country" required>
    {% for country in craft.territories.getTerritories() %}
        <option>{{ country }}</option>
    {% endfor %}
</select>


Transform: Image {file} cannot be found with Why do i get an error

throw new Exception(Craft::t('Image “{file}” cannot be found.', array('file' => $file->filename)));

for

{% set myImage = entry.pr_foto.first %}
{% set params = { width: 300, height: 200 } %}

while

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

shows the image?

The filesystem path for photos is uploads/photos/. The upload works fine in the admin. It's only the transform.

Full trace error:

As i was working on a localised website I had to use the full path,
in my case on MAMP PRO that was:
/Users/davedriesmans/Documents/Sites/website.dev/public/uploads/photos/

guess i'll have to change then when going into production

use environmentVariables like Mats Mikkel Rummelhoff suggests


Set Users' passwords When you create a new user in the craft backend CMS, it used to be possible to set (and change for existing users) the password.  It appears recently (last 6 months+) that this feature has been removed, is there a simple way to re-instate this feature or is the only way to set the password the password re-set url feature?

For security reasons, this was changed in Craft 2.3...

  Admins are no longer allowed to change other users’ passwords.

But savvy admins can still pull it off... Simply click the gear icon in the right sidebar, and select "Copy password reset URL". Then, instead of sending that URL to the user, just use it yourself.


How can I only allow authors to edit their own entires via front-end? I have a front-end form that registered users can log into and edit entries.

I am checking for the correct user group, then also checking for the permission:

{% if currentUser.isInGroup('myGroup') %}

    {# Get the entry #}
    {% set request = craft.app.request.segment(3) %}
    {% set entry = craft.entries.section('mySection').slug(request).one() %}

    {% if entry|length > 0 %}
        {% if currentUser.can('editEntries:7') %}
          {# user can edit the current entry #}
        {% endif %}
    {% endif %}

{% endif %}

All is fine, but if I change the url to another valid url (where the logged in user is not the author) I am still able to see the entry.

Is there a way to prevent that? Is it as easy as just checking/comparing authors? Or is there a more eloquent way? I do have other permissions disabled...

Thank you for any suggestions!

You can check if the current entry's author is the currentUser.

{% if entry.author.id == currentUser.id %}
    {# User can edit entry #}
{% endif %}


Craft Commerce: After add to cart, redirect to specific line item I'm building a craftcommerce based site, where each item added to the cart must be individually customised through a wizard interface.

When the item first gets added to the cart, I'd like to immediately redirect to a page where we can customise the item further

Something like the redirect shown below:

<input type="hidden" name="action" value="commerce/cart/updateCart">
<input type="hidden" name="redirect" value="commerce/item?item={id}">
<input type="hidden" name="qty" value="1">
<input type="hidden" name="purchasableId" value="{{ purchasable.purchasableId }}">
<input type="submit" value="{{ "Buy"|t }}" class="btn btn-default"/>

This is possible with user form submission for instance, where the newly created user id is accessible via the method described above.

Any ideas on how I would go about doing this?

I created a simple plugin to redirect using the onAddToCart method

  craft()->on('commerce_cart.onAddToCart', function($event){

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

      craft()->request->redirect("/commerce/item/?item=" . $lineItem->id);

  });


.htaccess file not rewriting url Hi I'm having major problems trying to get my .htaccess file to rewriteRule or redirect one url to another. I've used .htaccess before on other cms installs and always work but for the life of me I cannot get it to work on my craft install.

<IfModule mod_rewrite.c>

    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

    # Send would-be 404 requests to Craft
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d

    RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]

    RewriteRule (.+) index.php?p=$1 [QSA,L]

    Redirect /outdoor-furniture/all-garden-benches https://www.mywebsite.co.uk/outdoor-furniture/garden-benches

</IfModule>

This should redirect /outdoor-furniture/all-garden-benches to /outdoor-furniture/garden-benches (getting rid of the 'all-' bit).

This actually redirects to this:

https://www.mywebsite.co.uk/outdoor-furniture/garden-benches?p=outdoor-furniture/all-garden-benches

which is obviously wrong and still throws up a 404 error. I've tried everything now and what was supposed to be a 5 minute job is sending me round the bend so if anyone could shed some light on this then that would be great thanks!

EDIT The only thing that will help is if I take off ?p=$1 from this line:

 RewriteRule (.+) index.php?p=$1 [QSA,L]

Once I do that the redirect works fine, however I'm reluctant to do that as it might break the site somewhere.

You can try this

<IfModule mod_rewrite.c>

    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

    # Send would-be 404 requests to Craft
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d

    RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]

    RewriteRule ^/outdoor-furniture/all-garden-benches /outdoor-furniture/garden-benches [NC,L,R=301]

    RewriteRule (.+) index.php?p=$1 [QSA,L]

</IfModule>

If that doesn't work you can always try using a plugin for your redirects

https://plugins.craftcms.com/redirect
https://plugins.craftcms.com/retour


How to pull a single podcast source, using the Matrix field and loop? {% if block.type == "podcastBlock" %}
    {% for category in block.podcastChannel %}
        {{category.title}}

        <audio class="mp3" controls>

        {% for entry in block.podcastChannel %}
            <source src="{{ entry.audioFile.one.url }}" type="audio/mp3">
        {% endfor %}
    {% endfor %}
{% endif %}`

Try using the limit:1

{% for entry in block.podcastChannel.limit(1) %}


Frontend Form - Checkboxes cannot "all" be unchecked I have a frontend entry form with some checkboxes that is not behaving correctly.

If you uncheck all options and save, nothing changes (this is bad). However if you uncheck one item and check another item it saves correctly.

Additionally in the Craft CP if you uncheck all items it saves correctly so it clearly works there.

relevant template code:

{% for volunteer in craft.entries.section('careers').search('positionType:volunteerPosition') %}
  <label class="d-block">
        <input type="checkbox" class="form-check-input" name="fields[volunteerPositions][]" class="form-check-input" value="{{volunteer.id}}" {% if volunteer.id in selectedEntries %}checked{% endif %}>&nbsp;&nbsp;{{volunteer.title}}  (created by {{volunteer.author }})
      </label>
{% endfor %}

Please advise.

Your code is correct but you need to add another line near the top:

 <input type="hidden" name="fields[volunteerPositions]" value="">

From the documentation:

  If you are including a Checkboxes field on a front-end entry from, make sure to include a hidden input before the checkboxes, so that an empty value is submitted if no checkboxes are checked.


How do I programmatically set a Users company field? I'm currently able to add a user with the following code (from the Docs):

$user = new UserModel();
$user->username  = 'tommy';
$user->firstName = 'Tom';
$user->lastName  = 'Foolery';
$user->email     = 'tom@thefoolery.com';

$success = craft()->users->saveUser($user);

if (!$success)
{
    Craft::log('Couldn’t save the user "'.$user->username.'"', LogLevel::Error);
}

How can I also set the Profile Company name??

I've tried the following with no luck:

$user->company = 'ACME';

$user->setContent([ 'fields' => ['company' => 'ACME'] ]);

Close! You should be using setContentFromPost() for this.  See here and here for more info.

You code would look like:

$user = new UserModel();
$user->username  = 'tommy';
$user->firstName = 'Tom';
$user->lastName  = 'Foolery';
$user->email     = 'tom@thefoolery.com';
$user->setContentFromPost(array('company' => 'ACME'));

$success = craft()->users->saveUser($user);

if (!$success)
{
    Craft::log('Couldn’t save the user "'.$user->username.'"', LogLevel::Error);
}


How can Craft-generated Content HTML be accessed via an external PHP app? We have a CakePHP 2.5 app for which we'll very soon be building a learning centre/knowledge base. Craft is one of the tools we're considering for that due to its apparent suitability for content editors to create longform, mixed content consisting of text, images and videos without ending up with junk HTML.

For a couple of reasons, it might be preferable for us to have the learning centre content served as part of the app rather than via Craft at a subdomain, so we'd like to know how we would pull in just the generated HTML Content for the actual article content from Craft for embedding within the app's layout.

The learning centre will have four categories, each with an unknown number of articles.

We'd need to be able to reference each article, and maybe each category, from within the app as users can be set parts of the learning centre as tasks.

Your app can load up Craft using its bootstrap.php file:

$craft = require 'path/to/craft/app/bootstrap.php';

That file returns a Craft\WebApp instance. From it, you can access all of Craft’s services, including the ElementsService which provides APIs for fetching elements and their content.

Read through our Working with Elements guide to get an idea of how those APIs work.

As a quick example, here’s how you’d get the entries in a section with an ID of 1 with a category selected, with an ID of 5:

$criteria = $craft->elements->getCriteria(Craft\ElementType::Entry);
$criteria->sectionId = 1;
$criteria->relatedTo = array('targetElement' => 5);

$entries = $criteria->find();

To get the HTML for an entry, you could either assemble that in PHP based on the entry’s content fields, but it would probably be easier to just write a template for it, and have TemplatesService::render() render it for you:

$html = $craft->templates->render('path/to/templates', array(
    'entries' => $entries
));


Control Panel advanced search? Is it possible to use the search in the CP to search let's say by id? Or even one of the fields?

Thanks in advance,
Sidney

You can search any of your fields using the syntax "fieldHandle: search term".

See http://buildwithcraft.com/docs/searching for more info.


Variable "entry" does not exist in template at Structure Section So, the subject.
I am currently working with customer of craftcms v2.
I am setting up Structure Section where I want to add Entry Type for index listing of items and add some items in list.

So, here is my setup:

Section: https://imgur.com/a/afXBU4M
Section EntryType: https://imgur.com/a/ugkEkGh
Field Settings tab: https://imgur.com/a/efAe0Kp
Field Layout tab: https://imgur.com/a/4FuZcAZ
Entry Example: https://imgur.com/a/KIxOdbO

I have 3 Entries added.
I made this setup exactly the same as was for same page type (Structure Section too). But page I did throws error as in subject title.

I've googled and found that the key for 'entry' object in template using is to check this option in Section settings:

'Entries in this section have their own URLs'

I found that in this article: https://straightupcraft.com/articles/the-craft-entry-variable

So, what may be the problem? This option is checked. Also exactly the same page (called Features) works well! It's kind of magic I think.

Simple code in template raises the error: https://pastebin.com/fjqeb1LT
I am using template in 'app/craft/templates/reviews/index.twig' folder.

That entry variable will only be predefined for the template when you go to one of your entry’s URLs.

Your section’s Entry URL Format for top-level entries is {slug}, and your entry’s slug is qweasdzxc, so that would make your entry’s URL <site-url>/qweasdzxc (http://localhost/qweasdzxc).

If you change your section’s top-level Entry URL Format to reviews/{slug} instead of just {slug}, then the entry’s URL will become <site-url>/reviews/qweasdzxc.

When you go to <site-url>/reviews, you’re just accessing the reviews/index.twig template directly, so the entry variable was never defined, which is causing the error you’re getting.


Checkbox array for days of the week I'm attempting to create something within my template using global values and checkboxes. What I need this to do is "if it's one of the days of the week marked as open, as selected by a checkbox, and the time is between X and Y, then display that we are open, otherwise, say we are closed".

I have Monday through Sunday listed as checkboxes, and their values are set with Monday as 1, Tuesday as 2, etc, and I'm trying to compare it to 'now'|date('N'), which lists the day of the week as a number.

{% for dayOfWeek in theCenter.openWeekDay %}

    {% if 'now'|date('N') == dayOfWeek and 'now'|date('Hi', 'America/Denver') > theCenter.openTime|date('Hi') and 'now'|date('Hi', 'America/Denver') < theCenter.closeTime|date('Hi') %}

We are OPEN

    {% else %}

We are CLOSED

    {% endif %}

{% endfor %}

I've selected Tuesday through Sunday as open by selecting their checkboxes in the globals form. The code above returns 5 'We are Closed' and 1 'We are Open' results. I just need it to check if today is one of the open days, and if it's between open and closing time, and display one result.

I've tried this:

{% if 'now'|date('N') in dayOfWeek and 'now'|date('Hi', 'America/Denver') > theCenter.openTime|date('Hi') and 'now'|date('Hi', 'America/Denver') < theCenter.closeTime|date('Hi') %}

but it returns 6 'We are Closed'. I've been trying to figure this out for several hours, but the documentation doesn't seem to be made for what I want to do, and I'm probably looking in the wrong place.

Any suggestions on how I could get this to work?

EDIT

Here's the entire script:

{% if 'now'|date('z', 'America/Denver') > theCenter.startWinterSeason|date('z') or 'now'|date('z', 'America/Denver') < theCenter.endWinterSeason|date('z') %}
    {% for dayOfWeek in theCenter.openDaysWinter %}
        {% if dayOfWeek.selected and 'now'|date('N') == dayOfWeek and 'now'|date('Hi', 'America/Denver') > theCenter.openTimeWinter|date('Hi') and 'now'|date('Hi', 'America/Denver') < theCenter.closeTimeWinter|date('Hi') %}

The center is OPEN

        {% else %}

The center is CLOSED

        {% endif %}
    {% endfor %}

&nbsp;{{ theCenter.hoursTitleWinter }}

Tuesday &mdash; Saturday
{{ theCenter.openTimeWinter|date('g:i A') }} to {{ theCenter.closeTimeWinter|date('g:i A') }}

{{ theCenter.timeNotes|raw }}

{% elseif 'now'|date('z', 'America/Denver') > theCenter.startSummerSeason|date('z') and 'now'|date('z', 'America/Denver') < theCenter.endSummerSeason|date('z') %}
    {% for dayOfWeek in theCenter.openDaysSummer %}
        {% if dayOfWeek.selected and 'now'|date('N') == dayOfWeek and 'now'|date('Hi', 'America/Denver') > theCenter.openTimeSummer|date('Hi') and 'now'|date('Hi', 'America/Denver') < theCenter.closeTimeSummer|date('Hi') %}

The center is OPEN

        {% else %}

The center is CLOSED

        {% endif %}
    {% endfor %}

&nbsp;{{ theCenter.hoursTitleSummer }}

Tuesday &mdash; Saturday
{{ theCenter.openTimeSummer|date('g:i A') }} to {{ theCenter.closeTimeSummer|date('g:i A') }}

{{ theCenter.timeNotes|raw }}

{% else %}

EPIC FAIL

{% endif %}

Which outputs this:

I need it to only show the center is closed once.

This should do what you're looking for:

{% set closed = true %}

{% for dayOfWeek in theCenter.openWeekDay %}

    {% if 'now'|date('N') == dayOfWeek and 'now'|date('Hi', 'America/Denver') > theCenter.openTime|date('Hi') and 'now'|date('Hi', 'America/Denver') < theCenter.closeTime|date('Hi') %}
        {% set closed = false %}
    {% endif %}

{% endfor %}

{% if closed %}

The center is CLOSED

{% else %}

The center is OPEN

{% endif %}


Change title url of elementtype in the list I have a plugin. In this plugin I did elementtype which extends the user one, but with only one source "clients". I have and New Client button which points to my plugin Plugin_ClientController which looks like this:

class Plugin_ClientController extends UsersController
{

    public function actionIndex( array $variables = array() ) {

       $this->renderTemplate('plugin/client/_index');

    }

    public function renderTemplate($path, array $variables = array()) {

        $path = str_replace('users/', 'plugin/client/', $path);
        parent::renderTemplate($path, $variables);

    }

}

I don't know if this is the right way to do this, but it seems to work,
so like this I can have my one view for Client edit, which is almost the same as users one.

My elementtype is look like this:

class Plugin_ClientElementType extends UserElementType
{

    public function getSources($context = null)
    {
        $sources = array(
            '*' => array(
                'label'    => Craft::t('Clients'),
                'criteria'  => array('groupId' => 1),
                'hasThumbs' => true
            )
        );
        return $sources;
    }

}

So all fine up to here. The problem is in that list:

where I list all my clients the url on the title in my case now User1 is pointing to admin/users/[ID]
I would like to change it to plugin/client/[ID] if that possible I know that it has to be in the model like this:

class Pluign_ClientModel extends UserModel
{

    protected $elementType = 'Plugin_Client';

    public function getCpEditUrl()
    {
        return UrlHelper::getCpUrl('plugin/client/' . $this->id);
    }

}

But it seems that it's not coming from there. If someone can help me with this would be great. Thank you in advance.

I found the solution of this was under my nose,

I added this

public function populateElementModel($row){

  $model = Plugin_ClientModel::populateModel($row);
  return $model;

}

In Plugin_ClientElementType and then getCpEditUrl() it works.


How to setup Bootstrap 4 Carousel with Craft CMS 3? I'm hoping to get some help or guidance on a issue that I'm having. I am using Bootstrap 4 as my CSS framework and wanted to integrate a working Carousel with my web project.  I managed to get the jumbotron working with a Matrix field. See below:

I was hoping that I could create a Carousel Matrix block in a similar fashion as the Jumbotron that was created previously. Any suggestions on a proper setup?

A matrix field for an image carousel needs only a single asset field, one that will accept more than one image. In my experience there is rarely a requirement for anything more. 99% of carousels I have implemented look like this:

If you wanted to add text to accompany each slide you could add a text field directly to the image asset and then display that with each carousel slide:


Has anybody built a plugin or API integration with Xero or Cin7? Love hear thoughts on the complexity of this or if anyone has something off the shelf to offer. Thanks

I don't believe so. The complete list of known plugins can be found here:

  https://straightupcraft.com/craft-plugins


Use Twig's batch filter with conditional I am trying to make a grid of blocks using Twig. I have different types of blocks so I am using a conditional to test the block type and render different components per block type.

The problem I am having is I want to batch my blocks (columns) in twos so that I can have two blocks per row, so I can do {% for row in entry.curatedContentBlocks|batch(2) if row.type == 'halfWidthBlock' %}, add a row and then nest {% for block in row %} and add my block styles. This should work but when I try to test the block type with row.type, I get an error saying Key "type" for array with keys "0, 1" does not exist.. I'm thinking this is something to do with the batch filter returning an array.

I think the following code is the closest I've gotten, but I am still getting an error saying Key "1" for array with keys "2, 3" does not exist.. Here's the code:

{% for i, row in entry.curatedContentBlocks|batch(2) if row[i].type == 'halfWidthBlock' %}

      {% for block in row %}

{{ block.titleText }}

              {% if block.ctaUrl|length and block.ctaText|length %}

                  {{ block.ctaText }}

              {% endif %}

      {% endfor %}

{% endfor %}

I don't think you can test a conditional against a batch set like this. I think it's testing each batched set against the conditional instead of each item inside the batched sets which is what you're going for.

I would just create a new set of filtered matrix blocks and then batch the result.

{% set onlyHalfWidthBlocks = [] %}

{% for block in entry.curatedContentBlocks if block.type == 'halfWidthBlock' %}
  {% set onlyHalfWidthBlocks = onlyHalfWidthBlocks|merge([block]) %}
{% endfor %}

{% for row in onlyHalfWidthBlocks|batch(2) %}

      {% for block in row %}
        {# ... block code here ... #}
      {% endfor %}

{% endfor %}


Search Between 2 Dates Venti Calendar Plugin I am using the Venti Events Calendar Plugin. I was wondering how I could go about searching for events between 2 dates.

I can display events between 2 dates below, using the .between parameter. But I have not figured out how to incorporate this into a search.

{% set events = craft.venti.events.between('2016-04-01 00:00:00','2016-05-19 00:00:00') %}

I managed to figure this out on my own.  There's a good chance this solution will work for searching for entries between custom date fields using Craft's standard entry system (not the Venti Plugin) as well.

 {% set start = craft.request.param('startMonth') %}
 {% set end = craft.request.param('endMonth') %}
 {% set entries = craft.venti.events.startDate('and', '>= ' ~ start|date('Y-m-d'), '<= ' ~ end|date('Y-m-d')) %}

 {% for entry in entries %}
      <p>{{ entry.title }}</p>
 {% endfor %}


Creating users as inactive I'm writing a plugin to create users. The problem I'm having is when I create them Craft is automatically setting the user as "active". I want them to be "inactive" so that I can then send a verification email. I've look through the code and there appears to be no way to Create a user using craft()->users->saveUser($user) without having them always be active.

In the admin panel I do have the "Verify email addresses?" option checked.

Please help!

Matt and I managed to work this out together. Seems like setting the pending and unverifiedEmail attributes on the userModel before saving the user does the trick.

$user = new UserModel();
$user->pending = true;
$user->unverifiedEmail = "username@domain.com";
craft()->users->saveUser($user);

Edit: Might also want to look into another syntax that I noticed in this question.

$user = new UserModel();
$user->status = UserStatus::Pending;
$user->email = "username@domain.com";
craft()->users->saveUser($user);


Possible to share assets, templates and plugins across two domains but not all content? I've seen many similar questions (Multiple databases, single codebase) but now a little confused on the best approach. This is our first Craft CMS site so still learning the possibilities.

We have domainone.com and domaintwo.com which will be almost identical in design and functionality but the copy throughout will be slightly different as each website is for the same brand but different locations (same country).

In a perfect scenario, both websites will share the same assets, CSS/JS, templates and plugins as they require the same functionality, however, they'll have their own login areas to manage their own content.

Approx. half of the content will be the same i.e. new and used vehicles, but they'll have different pages such as 'about us', 'meet the team' and so on.

Would the best option be to just copy over the plugins, templates etc to a fresh installation and separate the two completely or is there a way to achieve this 'perfect scenario'?

As long as your sites are hosted on the same server, you can easily share templates and plugins between them by defining the appropriate path constants in the index.php files for your sites:

define('CRAFT_PLUGINS_PATH', '/absolute/path/to/your/plugins/folder');
define('CRAFT_TEMPLATES_PATH', '/absolute/path/to/your/templates/folder');

As for your resources (i.e. CSS and JavaScript files), symbolic linking is an option. However, I would recommend following Tom Bauer's suggestion in his answer – pick one domain and serve all assets from that domain's public folder, or even better: host the resources on a CDN.


currentUser: Impossible to invoke a method ("isInGroup") on a null variable I couldn't find this anywhere else, I'm looking up if the currentUser.isInGroup('verified') and if not, display another link. Works fine when logged in but throws a Template and Runtime error when using the {{logoutUrl}} or viewing any page when not logged in.

I expected this would work the same as currentUser by itself, which throws no errors. But obviously there's something I'm missing. Should I be using something like craft.session in combination with the isInGroup? Or some other method of detection?

Update

{% if currentUser.isInGroup('verified') is defined %}

Seems to get rid of the errors. So a couple of questions:

Is this expected behaviour?

I'm yet to wrap my head around the |length is defined etc methods of checking, and when to use them. I'll have to go over this post a few more times!

Yes, that's expected behavior.  currentUser will not exist if there is not a currently logged in user.

{% if currentUser.isInGroup('verified') is defined %}

That's one workaround for it.

Another would be:

{%if currentUser is defined and currentUser.isInGroup('verified') %}

which to me reads a little better even though it's more verbose.


How would I list all entries regardless of section or structure? I'm trying to build and XML site map that sorts all entries by their modification dates with the newly modified first.

{% for entry in craft.entries.find() %} ignores the structures,

{% for entry in craft.entries.section().find() %} returns the same as above,

{% for entry in craft.entries.section('mainPages').find() %} returns the structure as expected.

Looking for a way to include everything in a single, sortable query.

Actually your code should work just fine. But by default only 100 entries are fetched, maybe you need to increase the limit:

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

But if you just want to create a Sitemap, try Ben Croker's Sitemap-Plugin (I really like it)


Querying Global fields using CraftQL and Gatsby JS I am using Craft in headless mode with the CraftQL plugin. My front end is built using Gatsby JS.

I am able to query entries and output the data to my templates, however Global fields are not available. Here is my code:

// gatsby-config.js
plugins: [
  {
        resolve: `gatsby-source-craftcms`,
        options: {
            endpoint: `http://cms.local/api`,
            token: `REDACTED`,
            query: `{
                globals: globals {
                    contact {
                        address
                    }
                },
                home: entries(section:[home]) {
                    id
                    title
                    ... on Home {
                        subHeading
                        intro
                        ctaButton {
                            ... on CtaButtonButton {
                                __typename
                                text
                                linkUrl
                            }
                        }
                    }
                },
// etc

And then in my template:

export const query = graphql`
  query {
    home {
        title
        subHeading
        intro
        ctaButton {
            text
            linkUrl
        }
    }
    globals {
        contact {
            address
        }
    }
  }
`

In my console I get:

error  Cannot query field "globals" on type "Query"

If I remove the globals from the query I can successfully build and output data.home.title.

I've tried using the CraftQL browser in the CMS and I can successfully query globals:

I'm confident I'm missing something but can find nothing in the docs for Gatsby-Source-Craft or CraftQL.

Anyone have any idea what I'm doing wrong here??

In looking at this, the first thing I notice is that your query has a field called globals, but your error has the singular global.

If you open Gatsby’s GraphiQL instance (http://localhost/8000/___graphql in develop mode), can you see the Craft CMS data in the docs? That might help zero in on the query to use in Gatsby.

Hope that helps!


Does the default local content show when you toggle another locale/s off? With multiple locales setup when you toggle a specific locale off in the control panel for that entry, does the entry not show or will the output show the default locale content?

If you toggle off a locale for an entry, that entry will not show in that locale. So, if you have a section news, toggle off the entry my-entry in your current locale, and use craft.entries.section('news') to get all entries, my-entry will not be in that list.


How can I use the password confirmation modal on other forms? While logged into the Control Panel, you can edit your account information. When you try to change your email address or password, Craft asks you to enter your current password (for security reasons).

Is it possible to borrow this password confirmation security feature?

I've built a form which is very powerful and contains sensitive data. I want the user to be triple-sure that they want to submit the form... Forcing users to re-enter their password seems like a good way to minimize accidents.

I copied and modified the built-in craft AccountSettingsForm.js and placed it in my own plugin to test and it seems to work great. You will need to adapt it for your own use of course. It is currently triggered on elements that have a class 'btn confirm', and just prints 'Password Confirmed!' on success to the alert window.

Create a button in your plugins CP template file:

<input type="submit" class="btn confirm small submit" value="{{ 'Confirm'|t }}" >

And include the new js file PasswordConfirmation.js, which is:

(function($) {

PasswordConfirmation = Garnish.Base.extend(
{
    isCurrent: null,

    $lockBtns: null,
    $currentPasswordInput: null,
    $spinner: null,

    modal: null,

    init: function(isCurrent)
    {
        this.isCurrent = isCurrent;
        this.$lockBtns = $('.btn.confirm');
        this.addListener(this.$lockBtns, 'click', 'showCurrentPasswordForm');
    },

    showCurrentPasswordForm: function()
    {
        if (!this.modal)
        {
            var $form = $('<form id="verifypasswordmodal" class="modal fitted"/>').appendTo(Garnish.$bod),
                $body = $('

'+Craft.t(this.isCurrent ? 'Please enter your current password.' : 'Please enter your password.')+'

').appendTo($form),
                $passwordWrapper = $('
').appendTo($body),
                $buttons = $('
').appendTo($body),
                $cancelBtn = $('
'+Craft.t('Cancel')+'
').appendTo($buttons),
                $submitBtn = $('<input type="submit" class="btn submit" value="'+Craft.t('Continue')+'" />').appendTo($buttons);

            this.$currentPasswordInput = $('<input type="password" class="text password fullwidth"/>').appendTo($passwordWrapper);
            this.$spinner = $('
').appendTo($buttons);
            this.modal = new Garnish.Modal($form);

            new Craft.PasswordInput(this.$currentPasswordInput, {
                onToggleInput: $.proxy(function($newPasswordInput) {
                    this.$currentPasswordInput = $newPasswordInput;
                }, this)
            });

            this.addListener($cancelBtn, 'click', function() {
                this.modal.hide();
            });

            this.addListener($form, 'submit', 'submitCurrentPassword');
        }
        else
        {
            this.modal.show();
        }

        // Auto-focus the password input
        if (!Garnish.isMobileBrowser(true))
        {
            setTimeout($.proxy(function() {
                this.$currentPasswordInput.focus();
            }, this), 100);
        }
    },

    submitCurrentPassword: function(ev)
    {
        ev.preventDefault();

        var password = this.$currentPasswordInput.val();

        if (password)
        {
            this.$spinner.removeClass('hidden');

            var data = {
                password: password
            };

            Craft.postActionRequest('users/verifyPassword', data, $.proxy(function(response, textStatus)
            {
                this.$spinner.addClass('hidden');

                if (textStatus == 'success')
                {
                    if (response.success)
                    {
                        alert('Password Confirmed!');

                        this.modal.hide();

                    }
                    else
                    {
                        Garnish.shake(this.modal.$container);
                    }
                }

            }, this));
        }
    }

});

new PasswordConfirmation;

})(jQuery)

The next step would be to make it more generic so that it returns true, or executes a callback method, so that the result function can be customized per-use, and perhaps improve the instantiation so that you can pass it your own jquery selectors.


Group and Sort Alphabetically I have a list of categories that I am listing out, grouping by alphabet.  The issue is the list goes A H B C D E...and so on.  Why would it go in that order?

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

{% set categoriesGroup = categories|group('title|slice(0,
1)|replace("/[^a-zA-Z]/", "0-9") | upper') %}

{% for letter, categoriesInGroup in categoriesGroup %}
{{ letter }}
{% for category in categoriesInGroup %}

{{ category.title }}

{% endfor %}

{% endfor %}

Seems I needed to put in the order filter

{% set categories = craft.categories.group('programs').order('title') %}

{% set categoriesGroup = categories|group('title|slice(0,
1)|replace("/[^a-zA-Z]/", "0-9") | upper') %}

{% for letter, categoriesInGroup in categoriesGroup %}
{{ letter }}
{% for category in categoriesInGroup %}

{{ category.title }}

{% endfor %}

{% endfor %}


Return the current section type? (plugin) Is there an easy way to check what the current page section type is, within a plugin?

I wonder if I'm overlooking a little function that simply returns: "single", "channel", "entry", etc...?

UPDATE:

Thank you Aevlan, this was the approach I took originally. I've been struggling to determine wether the user is currently on the root of a channel/structure, or if they are on an entry page.

This is how I can determine "single", "channel" or "structure".

$element = craft()->urlManager->getMatchedElement();
$element_exists = $element && $element->getElementType() == ElementType::Entry;

$currentPageType = $element->section->type;

The reason I need to know this, is so I can perform some checks before I add certain navigation throughout the site. To help with my specific issue, I will use "hasDescendants()" or check the segment counts.

Thanks again. Mark

The SectionModel has a type property, which return what you're after, "single", "channel" and "entry". In a template it can be accessed like this:

{{ entry.section.type }}

If this is in a plugin and you have the section, you access it like this:

$section->type

But I'm confused by the "current page" of your question. Maybe you can describe in a bit more detail what you're trying to achieve, and what your code looks like atm?


Craft/Yii not garbage collecting session? I want to store a session value and have that cleared after a set timeout.

I’ve got PHP's session.gc_maxlifetime set at 60 seconds for development and am using Craft’s HttpSessionService to set a session value craft()->httpSession->set('foo').

I’m then checking that after 60 seconds and would expect it to be cleared by PHP’s session garbage collector but it’s still there: craft()->httpSession->get('foo').

I'm aware of how PHP's garbage collection works in that it's not run on every request (1/100 chance by default, defined by other PHP session settings).

What's the best way to force garbage collection on each session? Is there anything under the hood that we can leverage or do we need to write something custom?

I’m then checking that after 60 seconds and would expect it to be cleared by PHP’s session garbage collector but it’s still there:
I'm aware of how PHP's garbage collection works in that it's not run on every request (1/100 chance by default, defined by other PHP session settings).

I think you answered your own question?  From: https://secure.php.net/manual/en/session.configuration.php#ini.session.gc-maxlifetime

session.gc_maxlifetime specifies the number of seconds after which data will be seen as 'garbage' and potentially cleaned up

That means after 60 seconds the value in session has a 1/100 chance of being picked up by the garbage collector.  Of course, you can affect that percentage via other settings, but there are some valid reasons why you would not want garbage collection to run on every request.
I'm not aware of any way to force the PHP garbage collector to run and clean certain values.  I'd probably look at using cache based methods instead since you can set expiration times on cached items.


Javascript issue when setting an expiry date for entry If I set an expiry date for an entry I get an error on one of the last lines:

$timePicker.timepicker('setTime', Name of edit section as shown to the user*3600 + 00*60 + 00);

I've traced this back to craft/app/templates/_includes/forms/time.hml:39:

$timePicker.timepicker('setTime', {{ value|date('G') }}*3600 + {{ value|date('i') }}*60 + {{ value|date('s') }});

But I don't understand why value|date('G') returns Name of edit section as shown to the user instead of an integer.

Might also mention that this site uses Norwegian locale.

The issue here was an error in a translations file:

array(
    'some key' => 'some value',
    'key missing value',   <== no value assigned to this key
    'other key' => 'other value value'
);


When to use .first() and why? Can someone explain why and when we need to use .first()?

An example to use would be this code.

{% set featuredProductsHome = craft.entries.id(2).first() %}
{% for product in featuredProductsHome.featuredProducts %}
    {% import '_macros/_product' as m_product %}
    {{ m_product.teaser(product, 500, "product-teaser--featured") }}
{% endfor %}

The above works, but when I had {% set featuredProductsHome = craft.entries.id(2) %} without calling .first() it returned nothing.

By default, when you query elements you get back an array of Elements. Craft assumes you are using find() to query your elements if you don't explicitly say otherwise. You can loop through those elements and display attributes of those elements like you are doing:

{% for entry in craft.entries.find() %}
    {{ entry.title }}
{% endfor %}

More generally, here an abstract example of what you are getting back from your query:

{# A query for several Entry elements #}
craft.entries.find()

{# Results are an array of Entry Models #}
array(
  EntryModel,
  EntryModel,
  EntryModel
)

And in the case, you are only querying a single entry, you still get it back in the format of an array when using the default find() behavior.

{# A query for a single Entry element using find() #}
craft.entries.id(11).find()

{# Results are an array of a single Entry Model #}
array(
  EntryModel
)

However, if you update your query to use first(), you get back the Model directly:

{# A query for a single Entry element using first() #}
craft.entries.id(11).first()

{# Results are the Entry Model itself (not within an array) #}
EntryModel

There is one more scenario to consider when using first(). If you happen to be Eager Loading Elements, the results that you get back for your Element fields are not ElementCriteriaModels, but just normal arrays. So, in the case of accessing the data returned from Eager Loaded Elements you will not be able to use first() as the first() method is only available when you interact with ElementCriteriaModels.

In these cases, or in cases where you are sharing a partial template between two pages, one which uses eager loading and one that doesn't, you will need to access your first entry in an array using array syntax.

{% set entry = entry.entryRelationsFieldHandle[0] ?? null %}

In the above example, since we are accessing the first element in the array directly [0], if it doesn't exist, we will get an error (The first first() method is a bit smarter and will not throw an error). So, in the above example we have to explicitly plan for the situation of having no results using the null-coalescing operator ?? and falling back to null.

A longer form discussion of this scenario can be found in the article Examples of Eager Loading Elements in Twig and PHP.


Cache Not Invalidating Im using a pretty standard method for calling for entries, but with one small caveat in that I'm setting the limit inside a variable which is passed through to an include

so my index.twig file is like so

{% include 'homepage/_latest' with {'postCount' : 9} %}

and my homepage/_latest file has the following

{% cache %}
{% set latest = craft.entries.section('blog').limit(postCount ? postCount : 12) %}

<div class="entries entries--latest">

    {% for entry in latest %}

    {% include 'blocks/_entry-item-latest' %}

    {% endfor %}

</div>

{% endcache %}

Is that variable the issue for me/ I save a post and it doesnt know up on the homepage. I had it setup to invalidate every 15 minutes, but we put out 3-4 posts a day so theres no real need to invalidate that content every 15 minutes

If I understand you correctly, you’d basically need it to store separate caches depending on the limit.

The way to do that would be to set a custom key on the {% cache %} tag with the using key param:

{% if postCount is not defined or not postCount %}
    {% set postCount = 12 %}
{% endif %}

{% cache using key "homepage/_latest:"~postCount %}
    {% set latest = craft.entries.section('blog').limit(postCount) %}
    ...
{% endcache %}


Storing multilingual content that is used across sections I'm new to Craft, but starting off with building a multilingual site. I wonder what is best practice for storing multilingual content that is used accross sections (i.e. site navigation headings, footer link text). I know about the static translation files, but I want to enable local editors to translate those themselves in the CP.

I am fairly new to Craft myself but I think the best approach for that type of content would be to set up Globals I think you can then make them translatable and common translations can be added to in a translations file. Have a look at the HappyLager site to see how that works. I have found it really useful.


Store categories in array by level in controller I'm making a plugin and I need to get an array from a certain category group where the levels of the array are the same as the level of the categories in the group.

So I used the following code to get all categories in a group.

$criteria = craft()->elements->getCriteria(ElementType::Category);
$criteria->group = 'groupHandle';
$array = $criteria->find();`

This works fine but I want to create something like this:

$array[
    level1:[
        level2[
            level3,
            level3,
        ],
        level2[],
        level2[]
    ],
    level1:[
        level2[],
        level2[],
        level2[]
    ]
]

I hope you get the idea...
I could make a foreach in a foreach in a foreach but that's not very classy.
Thanks in advance!

You might just have to do it yourself :)

$criteria = craft()->elements->getCriteria(ElementType::Category);
$criteria->group = 'groupHandle';
$categories = $criteria->find();
$sortedCategories = [];

foreach ($categories as $category) {
  if (!isset($sortedCategories[$category->level]) {
    $sortedCategories[$category->level] = [];
  }
  $sortedCategories[$category->level][] = $category;
}
var_dump($sortedCategories);

NOTE: I haven't tested this code, but in theory it should do the trick :)


How do you set a flash message in the template in Craft 3? How does one set a flash message in the templates? I can't find any documentation about this, only for plugins or getting the message.

My use-case is, I am checking if a user is allowed to access a certain page and if they cannot I want to set a flash message, then redirect them to another page. I prefer this than to keep them on the same page and is if else logic to show the message or the rest of the page.

Thanks

You can set flash messages using yii\web\Session::setFlash().

The session component is available to templates via craft.app.session.

{% do craft.app.session.setFlash('error', 'You’re not allowed to go there.') %}

For convenience, Craft’s SessionBehavior class adds shortcut setError() and setNotice() methods to the session component as well.

{% do craft.app.session.setError('You’re not allowed to go there.') %}

You can place that right before your {% redirect %} tag.


Create date/time from string via form I'm using the wonderful A&M form plugin to create a form on my site, and I have 3 dropdowns for the user's birthday: month, day, and year.  Currently, I have it set up so that when the form submits, those values get put into a matrix field when logged in the form submissions entry in the CMS.  I would prefer to have it put into a date/time field though, but I'm unsure how to do it.

This is the code in my form:

Birthday
<input type="hidden" name="fields[birthday][new1][type]" value="date">

    <select name="fields[birthday][new1][fields][month]">
        <option selected="selected" value="">M</option>
        {% for i in 1..12 %}
            <option value="{{ i }}">{{ i }}</option>
        {% endfor %}
    </select>
    <select name="fields[birthday][new1][fields][day]">
    <option selected="selected" value="">D</option>
        {% for i in 1..31 %}
            <option value="{{ i }}">{{ i }}</option>
        {% endfor %}
    </select>
    <select name="fields[birthday][new1][fields][year]">
        <option selected="selected" value="">Year</option>
        {% set startYear = now.year - 15 %}
        {% set endYear = now.year - 110 %}
        {% for i in startYear..endYear %}
            <option value="{{ i }}">{{ i }}</option>
        {% endfor %}
    </select>

In this case, "birthday" is my matrix field handle and "date" is the block type handle.  "month", "day", & "year" are obviously the field handles within the matrix field.

There's nothing in the docs. I understand a date/time field doesn't produce an object like a matrix field, but I can't think of a solution of how to convert it.

Ok, I figured it out. First, to solve the birthday input problem, I used javascript to gather the values of each individual date dropdown and assemble them into a hidden text input that would be what passes in the datetime value to Craft.  No problem.

However, the datetime formatting tripped me up because there are two posts here that had the formatting differently.

The formatting needs to exactly match the example shown here on StraightUpCraft under the date row.  So a date value like 2014-06-24 does not work; it needs to be 06/24/2014. Likewise, the time value of 23:30:00 does not work either; it needs to be 11:30 PM.

My final code looks like this after the javascript fills in the date value. Since it's a birthday, the 6pm time is just hardcoded in.

<input type="text" size="10" name="fields[birthday][date]" value="02/24/1985">
<input type="text" size="10" name="fields[birthday][time]" value="6:00 PM">

Extra note for those using localized sites: you need to submit the date and time exactly how Craft formats them for each localization. For example, "6/24/2016" would be the acceptable date format for the U.S., but it will need to be "24.6.2016" when submitted on the German version of that page. You can output the formats dynamically in Craft using the translations filter:

<input type="text" size="10" name="fields[fieldHandle][date]" value="{{ now|date('Date Input Format'|t) }}">
<input type="text" size="10" name="fields[fieldHandle][time]" value="{{ now|date('Time Input Format'|t) }}">

And then in your translations files put something like:

"Date Input Format" => "d.m.Y",
"Time Input Format" => "G:i",

etc


Entries & Twitter Posts I'm trying to build what's basically a blog page, but spread throughout the posts we want some of our tweets as well. Obviously we have the entries from Craft, and I've found this plugin which I can use to pull in our tweets.

My question is how can I merge our entries and tweets and order them by date?

I was thinking of creating an array with the entries, then pulling in the tweets and merging them into the array and then ordering them by date.

Is this possible?

I finally got this working, here is how, I'm sure there is a better way or ways I can improve, but for now it works.

First, we need to create an empty array like so...

{% set posts = [] %}

Then we need to loop through the entries, and for each entry create an array containing the entry.postDate and the entry data. We then need to push that entry array into the main posts array

{% for entry in craft.entries.section('blog').limit(10) %}

    {#-- We store the date reference for our custom sort function, and the entry data --#}
    {% set entry = [{
        'date': entry.postDate,
        'data': entry
    }] %}

    {#-- Now we push that entry array into the posts array --#}
    {% set posts = posts|merge(entry) %}

{% endfor %}

So now we've got an array containing just our craft entries. Next we need to install the Dukt Twitter plugin and the Dukt oAuth Plugin. Set them both up via the documentation and then we move on to the next step.

We now need to pull in our tweets, which with these two plugins is surprisingly easy. It looks pretty much the same as the above chunk of code, except we're executing a GET request to Twitter instead of pulling in the entries from Craft. Also, because the tweets created_at variable is formatted in a non-standard way, we need to reformat it into the same format as the craft entry date.

{% for tweetRef in craft.twitter.get('statuses/user_timeline', {
    count: 10,
}) %}

    {% set tweet = [{
        'date': tweetRef.created_at|date('Y-m-d'),
        'data': tweetRef
    }] %}
    {% set posts = posts|merge(tweet) %}

{% endfor %}

So now, our posts array contains both our entries and tweets, but not in date order. With a bit of research I discovered this post which explains Twig can't sort multi-dimensional arrays. Luckily @victor_in in that post provided a solution. He has developed a plugin with improves twigs sort functionality. So download his plugin, then as he mentioned, modify the plugin to add the custom sort function.

This is the custom sort function that I used.

private function sortByDate($a, $b)
{
    return strtotime($a['date']) < strtotime($b['date']);
}

I should also note that Craft was giving me an error with array('TwigBetterSortTwigExtension', 'sortByDate') saying the class 'TwigBetterSortTwigExtension' not being found. I fixed this by replacing it with array(__CLASS__, 'sortByDate').

So now, we can loop through our posts array using the custom sort filter to order them by the date.

{% for entry in posts|sort('dateSort') %}
    {{ entry.date }}
{% endfor %}


How do I add an H2 tag to a page? How do I add an H2 tag to a page? The site already runs many months now. All pages are okay but some are lacking an h2 tag. Is there a simple way to add an h2 tag to these pages?

All of the templates that generate the HTML files for the front-end of your site will live in the templates folder on the server Craft is installed on.

You can edit the HTML there to add <h2> tags anywhere you wish.

The most important thing to note about Craft CMS is it is a platform used to build bespoke solutions for clients. It is light on traditional "out-of-the-box" features and instead provides developers with a modern toolset and content teams with a great author experience. In practice, this means that every Craft site is made specifically for the client which is great and why clients and developers love us.

Here are a bunch of learning resources that should help get you up to speed quickly.

Craft Official Docs & Support:

Craft CMS docs - The official Craft CMS documentation
Support Services - Both free and paid first-party support options.
Craft Discord group - The Craft development team is in Discord every day along with thousands of other Craft developers and users from all over the world.
Craft Stack Exchange - The best place to ask "how do I" type questions. Our development team monitors Craft Stack Exchange on a regular basis.

Learn Craft:

CraftQuest - CraftQuest is our official education and training partner. They have a number of excellent free and paid resources for Craft CMS & Craft Commerce. Ryan Irelan, Mijingo's founder, also offers customized training online or on-site.
Tuts+ Tutorials - Not official but [very good and low cost].
nystudio107 Blog — Andrew Welch is one of the best Craft developers around and the creator of the popular SEOmatic plugin. His regularly posts some excellent developer-oriented posts on Craft and web development.


Apache or Nginx for a Craft site Any recommendations as to whether it is better to use Apache or Nginx for a Craft website?

If the answer is "it depends", could you please delineate some of the advantages and disadvantages of each option?

There is no "this over that" for Craft specifically. Your own statement "it depends" plays a big role. I would read this pretty extensive post on DigitalOcean "Apache vs Nginx: Practical Considerations" as a good start on what software to use.

https://www.digitalocean.com/community/tutorials/apache-vs-nginx-practical-considerations

For me personally this has always been the key difference in choosing between the two:

  In terms of real world use-cases, one of the most common comparisons between Apache and Nginx is the way in which each server handles requests for static and dynamic content.

Usually you don't need all the extra features Apache comes bundled with. You have your Craft website, that's it. Nginx (for me) has all the functions it requires and can handle a lot of requests on lower hardware. For me personally that's key.


Incorrect user-level lock name - Local Vagrant Environment - Craft 3 When creating a new field, I received a Database Exception error -

  SQLSTATE[42000]: Syntax error or access violation: 3057 Incorrect user-level lock name '/var/www/storage/runtime/compiled_classes/ElementQueryBehavior.php'.

Loading an older database backup did not resolve the error, and neither did checking out an older branch. I am unable to access the panel or the site itself.

Installed Plugins

SEOmatic
Element API
SuperTable

Any assistance would be greatly appreciated

Edit: After dropping/creating the database multiple times, I am now getting this error instead

Edit 2: Here is a link to the full stack trace, which was posted to imgur due to the length

https://imgur.com/a/ADSvGCj

I just  ran into the exact same error on my Vagrant/Homestead environment when creating a field just with the lock name '/home/vagrant/code/craft/storage/runtime/compiled_classes/ContentBehavior.php'.

After getting this error the page cannot be accessed at all.

I'm using SuperTable, too.

The error itself seems to come from MySQL 5.7 where there is a character limit for the user-level lock names of 64 characters. Here the GET_LOCK statement fails. I just don't know how to fix it right now.


Examples of magazine/newspaper publication websites using Craft? I was just wondering if anyone has any examples of any mag/newspaper websites that use Craft? I'm interested to see the blend of technology or how the layouts turned out. Thanks!

Check out the Straighupcraft gallery. Maybe you'll find something there.


Conditional logic to add class for specific section entries I'm trying to create a conditional logic so that the class 'white-nav-bg' is added to the  element on the 'blog' section entries only.

Below is the code I'm currently using to try and achieve this with a logic tag but it is adding the 'white-nav-bg' class to all pages on the site rather than just the blog section entry pages.

<nav class="navbar navbar-default navbar-fixed-top
  {% for entry in craft.entries.section('blog').limit(1) %}
    {% if entry.type.handle == 'post' %}white-nav-bg{% endif %}
  {% endfor %}">

This code is in the '_layout.html' file, hence needing to figure out how to do conditional logic tags rather than adding the code differently in the blog template files.

After much time looking through Craft documentation I can't seem to find an example of how to do this. Any help would be gratefully received.

UPDATE:

Following helpful answers I have come to the following code, which works and allows me to define multiple sections to have the 'white-nav-bg' class.

{% set segment1 = craft.request.segment(1) %}
<nav class="navbar navbar-default navbar-fixed-top
  {% if segment1 == 'blog' %}
    white-nav-bg
  {% elseif segment1 == 'our-work' %}
    white-nav-bg
  {% endif %}">

There are many possibilities for this.

One of them is to listen to the section handle if you want it to be triggered only on the blog template:

{% if entry.section.handle == 'blog' %}your-class{% endif %}


Getting 'signed out' after exactly 1 minute of inactivity I've launched a site recently which is being hosted on Vidahost's Cloud servers. After exactly 1 minute of inactivity, anyone using the control panel is signed out. Except that if you refresh the page when you're "signed out", you're actually still signed in (but you lose any changes you were making).

So far I've tried changing the config setting overridePhpSessionLocation to auto, false and true, and nothing has changed. I've also tried changing the PHP version from 5.4 to 5.5 to no effect.

How can I stop this from happening?

This was related to the place that the sessions were being stored with my hosting company (Vidahost). Using the Utils section in Craft2, we managed to track it down to being stored with memcache. This meant that true and auto wouldn't work, and we had to set the override to false. False is meant to be the default anyway, but it seems to be working now that it's hardcoded.

The key lines to look for when debugging this are:

session.save_handler    memcache
session.save_path       tcp://10.168.1.55:11211?persistent=0&amp;weight=1&amp;timeout=5&amp;retry_interval=15`


Image thumbnail generation (on S3/Cloudfront integration) returns blank when first generated For a client site with S3/Cloudfront integration, we are seeing that images will not be able to load for the first time if they have not been generated before. I'm guessing this is because it takes time for the generated thumbnail to be saved to S3 then propagated to Cloudfront, so images will always return nothing the very first time. Is this correct, or are we missing something, or are there workarounds?

Got the solution through Craft support, as well as this similar question: Image Transforms - Image not processed until second page refresh

In summary, use the generateTransformsBeforePageLoad settings in Craft CMS.

e.g.
project>config>general.php

<?php
/**
 * General Configuration
 *
 * All of your system's general configuration settings go in here. You can see a
 * list of the available settings in vendor/craftcms/cms/src/config/GeneralConfig.php.
 *
 * @see craft\config\GeneralConfig
 */

return [
    // Global settings
    '*' => [
        // Default Week Start Day (0 = Sunday, 1 = Monday...)
        'defaultWeekStartDay'  => 0,

    // Enable CSRF Protection (recommended)
    'enableCsrfProtection' => true,

    // Whether generated URLs should omit "index.php"
    'omitScriptNameInUrls' => true,

    // Image variant be created on Asset save (aka BeforePageLoad)
    'generateTransformsBeforePageLoad' => true,

    // The secure key Craft will use for hashing and encrypting data
    'securityKey'                      => getenv('SECURITY_KEY'),
],

To set that in specific environment, e.g. in Live only, copy and paste

'generateTransformsBeforePageLoad' => true, into the desired environment

e.g.

// Live environment settings
    'live' => [
        'devMode' => false,
        'generateTransformsBeforePageLoad' => true,
        'enableTemplateCaching' => true,
        'allowAutoUpdates' => false,
    ],


Twig Cycle - how to show different html based on cycle Here is my code so far:

{% for event in post.get_field('timeline_event') %}
{% set items = [odd, even]%}
{{ cycle (items, loop.index0) }}

{% if cycle == odd %}

{% endif %}

{% if cycle == even %}

{% endif %}

This is working for the most part, the issue is the code I have is being duplicated twice.

Here is an image:

I know how to do this in jekyll liquid using capture, hit a roadblock using twig for php

Based on the docs:

{% for event in events %}
    {{ cycle(['odd', 'even'], loop.index0) }}
{% endfor %}

or (achieves the same thing):

{% for event in events %}
    {% set oddOrEven = cycle(['odd', 'even'], loop.index0) %}
    {{ oddOrEven }}
{% endfor %}

So, for different HTML:

{% for event in events %}
    {% set oddOrEven = cycle(['odd', 'even'], loop.index0) %}
    {% if oddOrEven == 'odd' %}

Odd

    {% else %}

Even

    {% endif %}
{% endfor %}


Craft 3 Custom Field Type with a File Uploader I have a custom field type I am porting from Craft 2 to Craft 3.

This field type used prepValueFromPost to grab a reference to a just uploaded file and then saves said file to an appropriate place for temporary storage (the file is sent on to a ticketing system which keeps its own copy so really it's only needed here for a few seconds).  The actual field value is jsut set to the full file path/name as a record.

I'm really struggling to port this across to Craft 3 as this area has seemingly been re-factored a lot...

I think I need to use serializeValue in place of prepValueFromPost, but I can't grab the actual filename from input in there and the value received is null (I expected it to be the filename..but it's not).  I used to use getContentPostLocation(); for this.

My specific questions are - is serializeValue() the right place to do this?  I want it to occur, once (per field - this is in a matrix), when the element (a Commerce Order) is saved.

And - how do I get the name of the uploaded file (i.e. what has replaced getContentPostLocation).

Here is the code that worked in Craft 2.

    public function prepValueFromPost($value, $element)
{

    $finalFilePath = null;

    //Weird function that works out the dynamic name of this field
    $filename = $this->getContentPostLocation();
    $file = UploadedFile::getInstanceByName($filename);

    //Save the file where we want it, delete the temporary file
    $outputDir = craft()->path->getTempPath() . "BusinessLogicPlugin_upload_" . time();
    IOHelper::ensureFolderExists($outputDir);
    //Was needed on dev, can't really hurt...leave it here.
    chmod($outputDir, 0775);

    $finalFilePath = $outputDir ."/" . $file->name;

    if(!($file->saveAs($finalFilePath, false))){
        BusinessLogicPlugin::log("Unable to save actual file [$finalFilePath], file will not be attached");
        $finalFilePath = "";
    }

    //Save the pathname of the file, if we were able to save it, otherwise empty string.
    return $finalFilePath;
}

Just as a little example how to store files in a custom field

/**
 * @inheritdoc
 */
public function normalizeValue($value, ElementInterface $element = null)
{

    $namespace = $element? $element->getFieldParamNamespace() . '.' : '';
    $file = UploadedFile::getInstanceByName($namespace . $this->handle);
    if($file !== null){
        // replace this
        $somePath = __DIR__ . DIRECTORY_SEPARATOR . $file->name;
        $file->saveAs($somePath);
    }
    return $file;
}

/**
 * @inheritdoc
 */
public function getInputHtml($value, ElementInterface $element = null): string
{
    Craft::$app->getView()->registerJs('Craft.cp.$primaryForm.attr(\'enctype\', \'multipart/form-data\');');
    return '<input type="file" name="' . $this->handle . '">';
}

Edit:

If you want to store the file path in your Database you would check if $value is an instance of File and if so return the path. Otherwise just declare your field has contentColumn = false


How do I add a local file to an asset field with a dynamically generated sub-folder? I've got a plugin that creates PDFs using Michael Rog’s Printmaker plugin. I'm able to successfully save these to a local folder and, using insertFileByLocalPath(), add them to an asset source. Then, by finding the id of the newly created asset, I can save the PDF to an entry.

My problem is that the asset field in the entry is setup to use dynamically-created subfolders, which I want to use to keep the assets for each entry separate from each other.

However, because the dynamically-created subfolder doesn’t exist until an asset is added to the entry, I am adding the PDF to the parent folder using insertFileByLocalPath().

I thought that when I added the asset to the entry and saved it, Craft would dynamically create the subfolder and move the asset into it, but it doesn’t do this. Instead, it just leaves the assets in the parent folder.

Here’s a simplified version of the code I’m using at the moment:

// Create PDF with $vars and $settings
$pdf = craft()->printmaker_pdf->pdfFromTemplate($template, $vars, $settings);

// Save PDF and get URL
$pdfUrl = $pdf->url();

// Get assets parent folder
$folder = craft()->assets->findFolder(array(
    'name' => 'parent-folder'
));

...

$response = craft()->assets->insertFileByLocalPath(
    $localFilePath,
    $filename,
    $folder->id,
    AssetConflictResolution::KeepBoth
);

// Get id of pdf (newly created Asset)
$pdfId = craft()->assets->findFile(array(
    'filename' => $settings['filename'].'.pdf'
))->id;

// Add PDF to entry
$entry->setContentFromPost(array(
    'myAssetField' => array($pdfId)
));

if (craft()->entries->saveEntry($entry)) {
    // Yay! PDF successfully saved to myAssetField
}

And here’s what the asset folder layout looks like:

parent-folder/new.pdf

Whereas what I want to achieve is this:

parent-folder/entry-slug/new.pdf

Where entry-slug is a dynamically created subfolder for each entry.

Any ideas how I can achieve this, or if it is even possible?

I've now worked out how to do this.

As I have a copy of the entry that I want to save the file to, I can work out what the name of the dynamic folder will be called.

// Generate target folder name
$targetFolderName = $entry->slug; // or whatever you want

Next, I see if the folder has already been created:

// See if target folder exists
// I'm searching on the name of the folder, plus the id of the parent folder
// (see question above for how to find this)
$targetFolder = craft()->assets->findFolder(array(
    'name' => $targetFolderName,
    'parent' => $parentFolder->id
));

if (!$targetFolder) {
    // target folder doesn't exist so we must create it
    $targetFolder = craft()->assets->createFolder($parentFolder->id, $targetFolderName);

    if ($targetFolder->status == 'success') {
        $targetFolderId = $targetFolder->getDataItem('folderId');
    } else {
        throw new Exception(Craft::t("Failed to create new folder."));
    }

} else {
    $targetFolderId = $targetFolder->id;
}

// Now I can move the PDF from its temporary location into out new assets folder
$response = craft()->assets->insertFileByLocalPath(
    $localFilePath,
    $filename,
    $targetFolderId,
    AssetConflictResolution::KeepBoth
);

From here I followed the same code as in the question to add the asset to the asset field in $entry.


Safe number of related entries – before performance hindered? Is there a safe limit to the number of entries related to another entry via the entry field (including nesting 2 deep) before putting too much strain on  performance? I'm approaching a products range using the entry field, e.g.

Parent
-child
-child
-child parent
-- child
-- child

The real answer, as with most performance related questions is, "it depends".

That's based on environmental factors like how much resources does your site and database have, what else the templates are doing, how are the servers configured, etc.

Craft 2 limits the amount of elements returned in a query to 100 by default, so that would probably be a good place to start.


How can I display the number of related entries? I have a template which displays a table of all the bookings on the website. The booking channel entries consist of two fields: a related user, and a related event, 1:1. There's a drop-down list of all the events at the top of the template which lists all of the events on the site. When a user clicks on an event title, the table updates to only show bookings related to that event (done by applying a class to all rows, and hiding every row which doesn't have the same class as the chosen event slug). The filter code looks like this:

<form class="event-filter">
    <label for="filter">Filter event: </label>
    <select id="filter" name="filter">
        {% for event in craft.entries.section('event') %}
        <option value="i{{event.id}}">{{event.title}}</option>
        {% endfor %}
    </select>
</form>

The bookings table displays all the events using something like this:

{% set bookings = craft.entries.section('booking').order('postDate desc') %}

Is there a way for my filter form to list my events, and display the number of bookings for each event? So it would say, for example:

First event (3 bookings)
Second event (8 bookings)

I'm sure it must be possible using relations, but I can't work out the syntax.

Try something like this:

<form class="event-filter">
    <label for="filter">Filter event: </label>
    <select id="filter" name="filter">
        {% for event in craft.entries.section('event') %}
            {% set numEventBookings = craft.entries.section('booking').relatedTo(event).total() %}
            <option value="i{{event.id}}">{{event.title}} ({{numEventBookings}} bookings)</option>
        {% endfor %}
    </select>
</form>

But it'll generate one database query pr event, so it might be a bit inefficient, depending on your setup.


ContactForm – How to make fields required I'm using the P&T ContactForm Plugin. How can I make more field required?

https://github.com/pixelandtonic/ContactForm

In the version from Github only the message and email field are required.

Is there a way to do this with the ContactForm Plugin?

For form validation I typically use Parsley.js - it's dead easy to use.


Entry form in home page I have an entry form in home page which the home page already using the entry object.

And I am placing the entry form in home page when i call

  {%- if entry is defined %} value="{{ entry.title }}"{% endif -%}

and this will grab the home page title, and this is not the result i want.
I need when the form submit and error return with value.

By the way, any source to learn about entry form? I don't see much tutorial about entry form. Thanks.

It sounds like you've got your home page setup as a Single. Which is a great way to go, and that's what is automatically setting the entry variable.

Here's a great walkthrough on creating an "edit entry" form...

  http://buildwithcraft.com/docs/templating/entry-form

Keep in mind, that example uses entry to represent the entry being edited. That won't work for you, however, since entry is being automatically set as your home page Single.

So when you're attempting to modify another entry, I'd recommend setting it to a different variable name. Obviously you can't have your home page and other entry both be represented by a variable named entry.

{% set entryToEdit = craft.entries.slug('my-entry-to-edit').first %}

Then entryToEdit would replace any instances of entry in the documented example.


Craft 3 redirecting me 404 after fill up registration form I have created copy whole HTML from here (https://docs.craftcms.com/v3/dev/examples/user-registration-form.html). and trying to register but it's showing me an error or we can say it redirects me to 404 error.

URL: lawbros.uldev.co/users/registration.html

I had made a small mistake to add action in the form tag. its 'users/saveUser' needs to be updated to 'users/save-user'.


How can I access environment variables from a javascript file in Craft 3? I see a lot of information about using environment variables on php files or twig templates, but I want to use them on javascript. I need to pass the environment, located on the .env file, to the Sentry init, located on assets/js/app.js.

How could I safely access this? Do I need to install dotenv or similar or is there a 'Craft way' of doing this?

I would appreciate any help on how to do this, or maybe a suggestion for a different approach.

The .env file is on the server and javascript is running in the client so you need to pass it through to javascript in your twig template inside a script tag.

{% set env = getenv('ENVIRONMENT') %}
<script>
    var myVariable = '{{ env|e('js') }}'
</script>

You probably don't need to escape it like in my example above, but good practice anyway. If you are then using the variable in that script you are good to go. From elsewhere on the page you can get the variable using:

document.addEventListener('DOMContentLoaded', () => {
    const myVar = window.myVariable;
});

Great article about this and more https://cruftlesscraft.com/passing-data-from-twig-to-javascript