Routing within a single page app integration I'm using Craft as the backend for an app and VueJS along with Element API to deliver the content.

Everything so far is working sweet, except when I try to pull up the detail page for an entry because in Craft, the route doesn't exist.

To be clear, my main listing page and links work but if I try to visit http://localhost/slug/id directly, I get a 404.

I know within the context of something like Laravel, I could do

Route::any('{all}', function () {
    return view('index');
})
->where(['all' => '.*']);

Is there something similar I could do with Craft?

I should add I have user registration and aspects that vue can't handle because Craft doesn't have a full crud api.

To pull this off, first you’ll have to make sure all of your Element API endpoints begin with something consistent, like api/ or data/, etc.

Then create a route in craft/config/routes.php that will match everything besides those Element API endpoints:

<?php

return array(
    '(?!api\/).*' => 'index'
);

'index' is the template path the requests should be routed to, so tweak that if needed.

If you have any other routes defined in there, make sure they go before this one.

  I should add I have user registration and aspects that vue can't handle because Craft doesn't have a full crud api.

You can use the same controller actions the Control Panel uses. There are a few examples, including user registration at the bottom of the templating docs.

If you want to keep these handled by custom pages, you’ll need to add routes for them in routes.php, or else they will stop working due to that new catchall route. Craft only attempts its default behavior of matching the URI to a public template as a last resort; if a route matches the URI, that route will take precedence.


Localized Environment Variables Based On siteUrl? I am setting up a multi-language site so far so good - everything is pretty obvious what to do.

I am curious if there is a way/best practice to have the environmentVariables array configured so that it knows which key to use based on the current siteUrl key?

I realize the syntax is incorrect/wrong but this is just an example:

'.dev' => array(
    'siteUrl' => array(
        'en' => 'http://local.mysite.dev/',
        'fr' => 'http://local.mysite.dev/fr/',
    ),
    'environmentVariables' => array(
        'en' => array(
            'basePath' => '/path-to-mysite/public/',
            'baseUrl' => 'http://local.mysite.dev/',
         ),
        'fr' => array(
            'basePath' => '/path-to-mysite/public/fr/',
            'baseUrl' => 'http://local.mysite.dev/fr/',
        )
    )
)

Or, is that something I just append to any path(s) in my template given the current section/segment etc?

I also set up those two environment variables (totally custom variables, with the one specialty that they are passed to the CP)
for my multilibgual sites.

But I have both basePath and baseUrl combined for all my locales!

'.dev' => array(
    'siteUrl' => array(
        'en' => 'http://local.mysite.dev/',
        'fr' => 'http://local.mysite.dev/fr/',
    ),
    'environmentVariables' => array(
        'basePath' => '/path-to-mysite/public/',
        'baseUrl' => 'http://local.mysite.dev/',
    )
)

I use these variables for two things:

Make assets from local asset sources available to all my locales. I set them absolutely, because relative paths don't
do it in this case, as the path to the assets' folder and the URL is a different one from http://example.com/fr/ as it is from http://example.com/.
Build absolute URLs to static files from my templates, e.g.
<link rel="stylesheet" href="{{ craft.config.environmentVariables.baseUrl }}stylesheets/site.css" />
Both, the url() function and the siteUrl variable don't work in this case, they always return the site's URL including the locale part.

So it's basically just a way to build absolute URLs to Craft assets and files for me.

I'm actually not totally sure how much of this could be solved with root relative paths, but in my case I've also
at least one environment where the path from web root to the craft site is differently to my other environments.

(For testing sites on mobile devices where I can't set virtual domains, I have an environment to access the site via the
local machine's IP address. As there's multiple sites on that machine, they are all in subfolders under web root.)


Trying to style Printmaker Plugin PDF by linking css in head of PDF template Similar to this issue Render styled output using Printmaker plugin

I am having the same issue and can't seem to figure out how to style the PDF.

Here is my code to generate the PDF:

    {% set html %}
        {% include '_includes/_pdf/social.twig' %}
    {% endset %}

    {% set pdfUrl = craft.printmaker.pdfFromHtml(html).url %}

    Print Page

This opens the PDF in a separate tab.

and then I am loading pdf.css into the head of _includes/_pdf/social.twig but the PDF is not styled.

<!DOCTYPE html>

        <meta charset="utf-8">
        <title>PDF Template</title>
        <link href="pdf.css" rel="stylesheet" type="text/css">

        // PDF HTML

and here is my directory structure

_includes
    _pdf
        pdf.css
        social.twig

Is it possible to style the PDF this way or do I need to use

You can link to the CSS in this way, but if it's not working for you then try changing the path to

<link href="./pdf.css" rel="stylesheet" type="text/css">

assuming that your CSS is in the site root.


Invalid path alias: @ error I have a site running Craft 3.6.11.1. I've been working on it for a while, have multi environment config set up and everything working great. I have recently installed and uninstalled quite a few plugins. I'm not sure exactly when something went wrong but now in terminal when I do ./craft I get:
Exception 'yii\base\InvalidArgumentException' with message 'Invalid path alias: @'

in /srv/users/serverpilot/apps/dev-odette-craft/vendor/yiisoft/yii2/BaseYii.php:154

Stack trace:
#0 /srv/users/serverpilot/apps/dev-odette-craft/vendor/yiisoft/yii2/base/Module.php(257): yii\BaseYii::getAlias('@')
#1 /srv/users/serverpilot/apps/dev-odette-craft/vendor/yiisoft/yii2/console/controllers/HelpController.php(245): yii\base\Module->getControllerPath()
#2 /srv/users/serverpilot/apps/dev-odette-craft/vendor/yiisoft/yii2/console/controllers/HelpController.php(240): yii\console\controllers\HelpController->getModuleCommands(Object(modules\sitemodule\SiteModule))
#3 /srv/users/serverpilot/apps/dev-odette-craft/vendor/yiisoft/yii2/console/controllers/HelpController.php(172): yii\console\controllers\HelpController->getModuleCommands(Object(craft\console\Application))
#4 /srv/users/serverpilot/apps/dev-odette-craft/vendor/yiisoft/yii2/console/controllers/HelpController.php(192): yii\console\controllers\HelpController->getCommands()
#5 /srv/users/serverpilot/apps/dev-odette-craft/vendor/yiisoft/yii2/console/controllers/HelpController.php(292): yii\console\controllers\HelpController->getCommandDescriptions()
#6 /srv/users/serverpilot/apps/dev-odette-craft/vendor/yiisoft/yii2/console/controllers/HelpController.php(67): yii\console\controllers\HelpController->getDefaultHelp()
#7 [internal function]: yii\console\controllers\HelpController->actionIndex(NULL)
#8 /srv/users/serverpilot/apps/dev-odette-craft/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)
#9 /srv/users/serverpilot/apps/dev-odette-craft/vendor/yiisoft/yii2/base/Controller.php(181): yii\base\InlineAction->runWithParams(Array)
#10 /srv/users/serverpilot/apps/dev-odette-craft/vendor/yiisoft/yii2/console/Controller.php(184): yii\base\Controller->runAction('', Array)
#11 /srv/users/serverpilot/apps/dev-odette-craft/vendor/yiisoft/yii2/base/Module.php(534): yii\console\Controller->runAction('', Array)
#12 /srv/users/serverpilot/apps/dev-odette-craft/vendor/yiisoft/yii2/console/Application.php(181): yii\base\Module->runAction('', Array)
#13 /srv/users/serverpilot/apps/dev-odette-craft/vendor/craftcms/cms/src/console/Application.php(89): yii\console\Application->runAction('', Array)
#14 /srv/users/serverpilot/apps/dev-odette-craft/vendor/yiisoft/yii2/console/Application.php(148): craft\console\Application->runAction('', Array)
#15 /srv/users/serverpilot/apps/dev-odette-craft/vendor/yiisoft/yii2/base/Application.php(392): yii\console\Application->handleRequest(Object(craft\console\Request))
#16 /srv/users/serverpilot/apps/dev-odette-craft/craft(22): yii\base\Application->run()
#17 {main}

Any ideas on how to fix this would be much appreciated.

This was an error in a module I have built for this site. Going through the docs and some tutorials again fixed it.


Multi-domain routing not working I've followed this answer for running a Craft install based on two domain names. I thought it was working but either I was wrong, or something's changed, because it's not now.

I have a.com (where the Craft install is) and b.com. In b.com's index.php I have this:

$craftPath = '../craft';

$_GET['p'] = 'subpath/' . (isset($_GET['p']) ? $_GET['p'] : '');

So that if I go to b.com/directory it loads a page as if it was a.com/subpath/directory.

Except it's not - it's as if it's trying to load a.com/directory.

If I put this in b.com's index.php (after the above):

var_dump($_GET['p']);
exit();

Then I see "subpath/directory", as expected. But if in my base layout template I put this:

{{ craft.request.getQueryString() }}

Then it shows "p=directory". So it seems like "subpath/" is going missing somewhere? I'm stumped.

UPDATE:

If I request b.com/index.php?p=directory then I get the page I expect (ie, /subpath/directory).

I've found an answer, but I don't know if it's going to cause me any problems or not. Looking at the debug output in the JS Console I noticed that although
$_GET['p'] was set correctly to subpath/directory,
$_SERVER['REQUEST_URI'] was only set to /directory and
$_SERVER['QUERY_STRING'] was only set to p=directory. Maybe Craft or Yii uses the REQUEST_URI rather than $_GET['p'] at some crucial stage?

So I've replaced the $_GET['p']... line in my b.com/index.php with this:

$_SERVER['REQUEST_URI'] = 'subpath/' . (isset($_GET['p']) ? $_GET['p'] : '');

That seems to fix things. Any reason this might be bad and wrong?

UPDATE: Looking back at my code now, it seems that both lines were required, to cover all occasions. So I now have this in b.com/index.php:

$_SERVER['REQUEST_URI'] = 'subpath/' . (isset($_GET['p']) ? $_GET['p'] : '');

$_GET['p'] = 'subpath/' . (isset($_GET['p']) ? $_GET['p'] : '');


Twitter plugin - Time since tweet I am using the Dukt Twitter plugin and want to display the time since the tweet was created.

The Twitter API returns a string in the format:

Fri Sep 02 14:42:42 +0000 2016

I can use the date filter on this string to alter the format, but cannot pass this through the diff method that twig exposes. I think I need to create a dateTime object, would this require a plugin to be created for this task or can I achieve this in twig?

A reference post on this forum discusses the diff method: Get Age from Date of Birth - however I think I need to have a date object, not a string, to use it. Ideally I'd like to just achieve this in twig as I have never written a plugin before! Thanks

You can use the date method for creating a date object.
e.g.:
{% set tweetDate = date("Fri Sep 02 14:42:42 +0000 2016") %}


What's the best way to link to an entry in a template? I have the following code and I'm looking for the best way to link to another entry page.

request a quote

I tried something like this with no luck:

request a quote

Here's the entry: http://grab.by/Ax6s

Thanks in advance for the help.

First, you'll want to retrieve that entry specifically...

{% set entry = craft.entries.slug('get-a-quote').first %}

Once you've got the entry that you want to target, you can easily link to it like this:

request a quote


My tasks don't seem to be running as a background process I have my plugin working now so that I can email users who's accounts will expire in 7 days time. The users are being selected correctly and the emails are being sent as expected. However, the tasks don't seem to be running in the background. I was expecting that when I hit the controller the task will be triggered and the page would immediately return saying "emails sent". Instead it seems it waits until the emails are sent before returning "emails sent". I'm worried that if the number of emails is large the page will timeout before it completes. It was my understanding that tasks run as a background process but may I have miss understood. Can anyone explain them to me in more detail?

For reference here is the controller and the service of my plugin:

class AcmeNotifications_NotificationsController extends BaseController
{

// let anyone run the controller actions
protected $allowAnonymous = array('actionSendEmail');

public function actionSendEmail()
{
    craft()->acmeNotifications_notifications->sendReminderEmail();

    //Make sure we kick the task off

    if (!craft()->tasks->isTaskRunning())
    {
        $task = craft()->tasks->getNextPendingTask();

        if ($task)
        {
            craft()->tasks->runPendingTasks();
        }
    }

    craft()->end();
}
}

and:

class AcmeNotifications_NotificationsService extends BaseApplicationComponent
{
public function sendReminderEmail()
{
    //Get all users whos account will expire in 7 days
    $user_criteria = craft()->elements->getCriteria(ElementType::User);

    $user_criteria->userExpiryDate = date('Y-m-d',strtotime("+7 days"));

    $users = $user_criteria->find();

    if($users){
        //Create array of user email addresses
        $user_emails = array();
        foreach ($users as $user) {
            $user_emails[] = array("to" => $user->email);
        }

        //Create an EmailModel
        $email = new EmailModel;

        //Set the global attributes
        $email->fromName = 'Joe Blogs';
        $email->fromEmail = 'joe.blogs@example.com';
        $email->subject     = 'Your account will expire in 7 days';
        $email->htmlBody    = 'The message';

        //Create the RecipientsModel and add the user emails
        $recipients = new Mailer_RecipientsModel();
        $recipients->recipients = $user_emails;

        if( $recipients->validate()){
            //Create mailer task
            craft()->mailer_main->newMailer($recipients, $email);
        }

        echo "emails sent";
    }
    else{
        echo "no emails to send";
    }
}

}

You are right about the Tasks running in the background. If the Task is just sending a few mails, it might be done before your site is loaded, thus creating this impression.

Check:

Change the Batch Size of the Mailer plugin to 1 and the waiting time to 120 seconds.
Change the $user_criteria to fetch 2 users.
Run your controller

It should now take about 2 minutes for the Task to finish, if your site loads faster it was just an impression.

Code:

You should however separate your code a bit more, because right now you are mixing Controllers and Services.

Your Service shouldn't output anything, it should just return a value, (e.g. boolen), and your Controller should then output the message:

Service {
    //Create Task etc...

    if ($itWorked == true) {
       return true;
    }
    else {
       return false;
    }
}

/* ------------------------ */

Controller {
    if ( FunctionService() ) {
       echo 'It worked';
    }
    else {
       echo 'Something went wrong';
    }
}

Also the "Make sure we kick the task off"-part, should go into your Service.

P.S. I see you are using my plugin :), if you need any help, create an issue over on github.


What is the different between url() and getUrl() What is the different between url() and getUrl()
Ex:
   {% set solutionIcon = solution.solutionIcon.one() ?? null %}

      {% if solutionIcon %}

      {% endif %}

   {% set solutionIcon = solution.solutionIcon.one() ?? null %}

      {% if solutionIcon %}

      {% endif %}

They do the same thing. url() is an alias of getUrl(). This is the link from the Craft 2 docs: https://docs.craftcms.com/v2/templating/entrymodel.html#url.
It works the same way in Craft 3, but I can never find anything in the Craft 3 docs.


How can I populate a drop-down on the front-end using Sprout Forms? I have a contact form where I can choose the current state (U.S states).
I have the field created in Sprout forms as "state" and is populated with all 50 states.

I would like to use "custom" html and loop through the values of that field. I just can't figure out how to get to it.

I know I can output the whole field/element using:

{{ craft.sproutForms.displayField('contact.state') }}

But that outputs a whole html element. I only want the options so I can loop over them like this:

....
<select>
    <option value="">Select</option>
    {% set states = form.getField('contact.state') %}
        {% for option in states %}
            <option value="{{ option.value }}">{{ option.label }}</option>
        {% endfor %}
....
</select>

As of Sprout Forms 2.0, this has become a lot easier.  Hopefully I can win that last answer away from myself!

A few options

First, Sprout Forms 2.0 adds multiple new override options so you may be able to address this problem in a different way now to that will get away from needing to handle this in Custom HTML.  Things to consider:

Template Overrides - If you were using custom HTML because the default templates we're not the right HTML format for your needs, you can now easily override those default templates on a per-form basis.
Rendering Options - If specific attributes of the field such as the ID or Class did not meet your needs, you could potentially dynamically override them while still using a tag like displayForm() or displayField()
Front-end Field API - You could create a custom plugin that adds front-end field support for a custom State Dropdown field.

Custom HTML

If you still feel custom HTML is the best fit for you, there is now a SproutForms_FormModel::getField() method and craft.sproutForms.getEntry tag to help manage retained values and error states.  Here is a generic example.  A more complete examples of all Standard front-end field types can be found in the docs Custom HTML Forms and Example Fields

{# Get our Form data #}
{% set form = craft.sproutForms.form('formHandle') %}

{# Get our Form Entry data to manage error states and re-populating field values #}
{% set submittedEntry = craft.sproutForms.getEntry(form) %}

{# Get our Field Model #}
{% set dropdownField = form.getField('dropdown') %}

{# We use the Twig attribute tag to dynamically access our
     field value on the submitted Form Entry #}
{% set submittedDropdownValue = attribute(submittedEntry, dropdownField.handle) %}

{% if dropdownField is defined %}

  {{ dropdownField.name }}

  <select name="fields[{{ dropdownField.handle }}]">
    <option value="">Select...</option>
    {% for option in dropdownField.settings.options %}

      {% set defaultValue = option.default ? option.value : null %}
      {% set selectedDropdownValue = submittedDropdownValue != '' ? submittedDropdownValue : defaultValue %}

      <option value="{{ option.value }}" {% if selectedDropdownValue == option.value %}selected="selected"{% endif %}>{{ option.label }}</option>

    {% endfor %}
  </select>

  {% if submittedEntry is defined %}

    {# Assumes you have an errorList macro #}
    {{ errorList(submittedEntry.getErrors(dropdownField.handle)) }}

  {% endif %}

{% endif %}


Craft 3.1 no longer updates all entries on section save - workaround? Craft 3.1 seems to have removed the functionality where if a section is saved, all entries in that section are re-saved.

This has broken a bunch of functionality that relies on this on a site I've built.

Is there a workaround? Even if it's building another plugin to somehow listen for a save section event (is there such an event) manually triggering the same thing?

Even if it's building another plugin to somehow listen for a save section event (is there such an event) manually triggering the same thing?

There's an EVENT_AFTER_SAVE_SECTION event you can listen to where you can put a ResaveElements job in the queue for the specific entries in the section that was just saved.


Installation error - Craft.uppercaseFirst is not a function I get two errors upon installing the latest build 2.3.2641. The first is a slide function for the "Create Your Account" window and the second is a more severe error of TypeError:Craft.uppercaseFirst is not a function which prevents installation and causes the busy gif to work continuosly as if something was about to occur.

php version 5.4.39
MySQL Version   10.0.17-MariaDB

It sounds like some files were not uploaded correctly to your server, or are corrupt/missing from your Craft download.

Download a fresh copy of Craft from http://buildwithcraft.com and swap out your existing craft/app folder with the new, freshly downloaded craft/app folder.


Getting errors while developing plugins So I've wasted a day because I couldn't figure out how to get an error back from an action I'm using in a plugin...

$newUserSuccess = craft()->users->saveUser($newUser);

$newUserSuccess was empty, and it turns out the reason was because the new user was trying to register with an existing user's email address, which fails. I could not figure out how to get any useful information back. I had tried this:

if (!$newUserSuccess)
{
    AutoUserEntryPlugin::log('Couldn't save the new user: '.print_r($newUser->getErrors(), true), LogLevel::Info);
    throw new Exception(Craft::t('Couldnt save the user.'));
}

but in the log all that was output was "Couldn’t save the new user: Array"

How should I be doing this?

You're getting "Couldn’t save the new user: Array" because $newUser->getErrors() returns an array of validation errors (in case there are more than one).

If you want to print them all to a log file, you can do something like this:

AutoUserEntryPlugin::log('Couldn't save the new user: '.implode(', ', $newUser->getErrors()), LogLevel::Info);


Craft on Vagrant: Please advise on initial install (Craft can’t connect to the database with the credentials in craft/config/db.php.) I am trying to install a craft playground using vagrant and puppet.
After firing the default installation for a LAMP stack and creating related DB and User, granting privileges, ... I want to start the craft installation, all I get is:

  Craft can’t connect to the database with the credentials in craft/config/db.php.

The commands I am using to create the DB:

CREATE DATABASE craftdb CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE USER craftadmin@localhost IDENTIFIED BY 'ThisPassword';
GRANT ALL PRIVILEGES ON craftdb.* TO craftadmin@localhost;
FLUSH PRIVILEGES;
EXIT

The dp.php looks like this:

// The database server name or IP address. Usually this is 'localhost' or '127.0.0.1'.
'server' => 'localhost',

// The database username to connect with.
'user' => 'craftadmin',

// The database password to connect with.
'password' => 'ThisPassword',

// The name of the database to select.
'database' => 'craftdb',

// The prefix to use when naming tables. This can be no more than 5 characters.
'tablePrefix' => '',

PHP Packages installed:

"php5",
"php5-common",
"php5-cli",
"php5-mysql",
"php5-sqlite",
"php-pear",
"php5-dev",
"php5-gd",
"php5-curl",
"php5-mcrypt",
"libapache2-mod-php5"

Any suggestions are much appreciated

Solution found:

I copied again all files to the root folder, changed the very same settings and got it to work - for whatever reason it seems that with the first attempt some files where missing.

@Brad: Thanks for taking the time - the shared infos are of help anyway.


How can I loop through a field and print each value individually? I have a field isotope.  It's a dropdown field with a single word text input.   Only one value (out of 6) can be assigned to an entry.  It is not a tag.  It is not a category.

I want to create a button for each value within the isotope field.

{% for button in entry.isotope %}

    <button class="button" data-filter="{{button.title}}">{{button.title}}</button>

{% endear %}

This is wrong and generates the error Variable "entry" does not exist.  I know this is basic, but I am obviously missing something.

Variable "entry" does not exist

This error is being caused by the first line of your code:

... in entry.isotope %}

You are either using this template code on an element that isn't an entry or haven't defined a variable called entry anywhere.

So we can help you more, what type of element is this field being used on?


Carbon 1 is deprecated - migrate to Carbon 2 Is anyone getting this when running a composer update command?

Local install: Craft CMS 3.1.31

update --no-interaction --ansi
    Loading composer repositories with package information
    Updating dependencies (including require-dev)
    Nothing to install or update
    Generating optimized autoload files
    Carbon 1 is deprecated, see how to migrate to Carbon 2.
    https://carbon.nesbot.com/docs/#api-carbon-2
        You can run './vendor/bin/upgrade-carbon' to get help in updating carbon and other frameworks and libraries that depend on it.
    All packages for ./composer.json have been updated.

To find the culprit, you could run a composer show --tree to see which plugin is using the dependency.

So far, I found two plugins using it :

rias/craft-contact-form-extensions (1.1.6)
solspace/craft3-calendar (2.0.20)

If you're using Solspace calendar, you should consider to upgrade to v3.
If you're using Rias Contact form extension, you can try to add the updated dependency to your composer.json file by running a composer require nesbot/carbon. It will fix the warning until the plugin is updated.


asset.first().getUrl('transform') not working for s3 asset - Craft CMS 2.6.2980 I can load the s3 image fine using the s3 base path and the craft cms filename that is saved in the craft cms database:

renders

However if I want to access the same image without the s3 base path (e.g. in order to use an image transform), I get a null.

renders

Any help would be appreciated!

Turns out you need to have the URL prefix set under the Asset Settings in order to call .getUrl()

Once I added this, my transforms began working.


Test for specific or multiple product variants I'm trying to test if a product has multiple variants AND/OR test for specific product variants.

{% if product.variants|length > 1 %}

That does not seem to work, even if it is a non-variant product. I understand that even for products without variants there is a 'default' variant, but shouldn't this return false if its a product type without variants given it should have only 1?

product.variants|length will in fact give you the exact number of variants the product has. If it is giving you an unexpected response, you’re probably just not looking at the right product in the first place. Try outputting the following to create a URL to the product’s edit page in the Control Panel:

{{ product.title }}

Then click on that link from your browser to see the actual product you’re dealing with.


From a Twig template, how to retrieve the content of a HTTP header in the current request? I would like to detect if a header in the current request is present and obtain its value, directly within a Twig template.
I know that craft.app.request gives access to a few variables like isAjax that directly check the headers content, but I haven't found a method to directly retrieve a specific header.

Can this be achieved in some way? (preferably not by writing a plugin)

By checking the code, I could find a method named getHeaders() that will return all the headers of the current request.

So if you want to retrieve the content of the foo header, just use:

{% set headers = craft.app.request.getHeaders() %}
{% set fooHeader = headers['foo'] %}


Sort matrix blocks in admin by a field within the matrix? I have a Single that includes a matrix as a field. The matrix has an internal date field. Is there a way to sort the matrix blocks by the date field on the admin side to help manage the blocks?

There is nothing that will automatically sort blocks for you in the Control Panel. Without writing a plugin with some very fancy JavaScript, the only way to arrange blocks is manually.

You can manually arrange your blocks by clicking & dragging the crosshairs in the upper-right corner of each block:


Make fields required when using Guest Entries This might be a bit of a Noob question but here I go:

Using Guest Entries on a site and cannot figure out how to make certain fields required. Those fields are marked as required in the CP but, when using Guest Entries, entries are submitted even when required fields are not filled in.

I can easily implement a front-end validation but I would like the validation to happen on the back-end before saving the entry as well.

Should this happen automatically, am I missing something ?
Do I have to create a validation "manually" and if so, how ?

EDIT:

After updating the plugin, this is how I displayed validation errors:

{% if entry.errors is defined %}
    {% for errorField, error in entry.errors %}
        {% for errorMessage in error %}

{{ errorField }} - {{ errorMessage }}

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

If the fields are marked as required in your field layout, then they should fail validation even on the front-end, so it sounds like a bug to me.  Can you send a database backup as well as the template code you're using for the form over to support@buildwithcraft.com?

Update

The issue was that if your entries were set to be disabled by default, then Craft won't run any validation on them.  Just made a change so that if you use the latest Guest Entries, you'll have an additional plugin setting to enable/disable validation on a per section basis, regardless of the default status of the entry.


Allow user to set timezone from within Craft when entering a time in a date/time field We are creating a small site to manage meetings that take place in many timezones. Administrators of the site will create meetings on behalf of teams everywhere. They may be in pacific timezone and receive a request to create a meeting from a team in England.

When creating the entry, the date/time they see if for pacific timezone, and to create the event with the correct time for GMT+1, they must do the math in their head as to what time in PST corresponds to the correct time in GMT+1.

Is it possible to have or add a field to specify which timezone the provided time is in, vs relying on the timezone set in settings?

I solved that by adding a dropdown field to user profiles where I allowed users to select timezone and then in custom module set the selected timezone like this:
class SiteModule extends Module
{
   public function __construct($id, $parent = null, array $config = [])
   {
       // Set correct Timezone
       $currentUser = Craft::$app->getUser();
       if ($currentUser) {
           $user = $currentUser->getIdentity();
           $timezone = null;
           if ($user->userTimeZone->value) $timezone = $user->userTimeZone->value;
           if ($timezone) {
               Craft::$app->setTimeZone($timezone);
           }
       }

       ...

If user is not logged in or does not have a timezone set Craft will use the system timezone for those users.
Timezone dropdown values are in the form 'America/Chicago'.


Saving an entry with multiple parentheses throw a 403 Saving an entry with multiple parentheses (in a redactor field) throw a 403. I know it's from ModSecurity - but never experienced that behaviors with another CMS (WP, Kirby, etc.) or with Craft2. This issue appears on 2 (different) projects in development.

Is anyone got something similar?

Field details:

Clean up HTML : checked
Purify HTML : checked
HTML Purifier Config : Default
Column Type : 64KB

PS. If I remove the () from the text or replace them with brackets [], the entry saved correctly. We experienced that issue on multiple computers from different offices and didn't reproduce it on local environment (MAMP or XAMP) - so it's not machine/location oriented.

PPS. Deactivate ModSecurity is not a solution

If you check the ModSecurity logs, you can find exactly which of its rules Redactor/that POST request is tripping.

You can either modify that rule to allow it to pass or just disabled that specific rule.


Best practice on importing Craft db backups? Our team's typical workflow is pull from repo, delete craft tables, import latest db backup, work locally.

We don't want everyone working on the dev server db for early development, because we'll be breaking the site too much for everyone else.

Which brings me to my question, should I be deleting tables before importing? If I don't delete the tables Craft has to do some cleanup magic on the backend (I don't know what it does). I do know that Craft creates tables for matrix types. Would not deleting tables potentially leave orphaned db tables? Obviously there could other side effects as well.

Opinions? Clarification?

The short answer is, yes, definitely drop your existing tables before importing a new .sql file. If you don't, you run a high risk of Craft developing weird issues of data mismatching. This is especially true if the two versions of the database were not created with the same exact version number of Craft.

NOTE: You may want to back up your existing database before dropping all of the tables.

The longer answer is, database syncing is an interesting and complicated problem, with many possible solutions. Check out this thread discussing the "holy grail" of database syncing across multiple environments...

What's the best practice for handling data migration and organization across development environments?

Ultimately, your data migration patterns are up to you. There are varying approaches, some involving Shell scripts and Git hooks. It's an evolving challenge for the Craft community (and other CMS's as well), so keep your eyes peeled for the next brilliant "eureka" moment!


Creating and using custom content tables If I want to create fields that get set to a custom content table rather than craft_content how would I do that?

Okie doke. After bashing my head against the wall THIS is how you create your very own super deluxe content table. Allow me to explain...

In your element class you will need to specify the following:

  public function hasContent()
  {
    return true; // You definitely will need this
  }

  public function hasTitles()
  {
    return true; // This is optional
  }

  public function isLocalized()
  {

    return false; // This is optional

  }

  public function getContentTableForElementsQuery(ElementCriteriaModel $criteria){

    return "custom_content_table_name"; // You definitely will need this

  }

  public function getFieldsForElementsQuery(ElementCriteriaModel $criteria)
  {

      // NOTE: I do not have any custom fields set to this table. If you have custom fields you should return them here so that they are included in the criteria query. If you also do not have custom fields just do what I'm doing here and return an empty array.

       $fields = array();

       return $fields;

  }

In your element's model class you'll need to do the following:

  public function getContentTable(){

    return "custom_content_table_name"; // you will need this

  }

  public function getFieldContext()
  {

    return 'custom_content_table_name'; // I have NO idea what this is and the Craft documentation is not clear about it.

  }

Finally, your record for the content table will have to make the following columns:

elementId
title
locale

That's basically it. If you run into any errors make sure you're not including extra non-existent fields in the criteria queries when querying content. Check the Craft logs to see exactly what's happening if you encounter any problems.


Commerce: How do I use an adjustor for line items? I have built a plugin that, TL;DR subtracts credits. Everything is working great - until I actually need to change the price.

I just flat-out don't understand it.

This is how I am looping through to check a user's credits using the commerce_discounts.onBeforeMatchLineItem event. You can see where I was using the discount $event->performAction = false method to stop the discount from being applied. But, I need the ability to split the line items so-to-speak.

Example: qty of 5 of the same product; 3 are free, 2 are full price.

// $entry is the entry that keeps track how many credits are left.
if ((int)$entry->events > 0) {
    $i = (int)$entry->events;

    while ($i > 0) {
        error_log('doing stuff...');
        $entry->setContentFromPost([
            'events' => ((int)$entry->events > 0) ? ((int)$entry->events - (int)$i) : 0
            ]);

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

        $i--;

        if ($i == 0) {
            error_log('OUT OF CREDITS');
            // $event->performAction = false;
        }
    error_log((craft()->config->get('devMode')) ? 'CREDITS LEFT: ' . (int)$i : '');
    }
} else {
    error_log((craft()->config->get('devMode')) ? 'Uh-oh user is out of event credits..' : '');
   $event->performAction = false;
}

I have an adjustor set up...it's basically from this thread.

What I don't understand is where to actually put the adjustor.

Adjustor.php

$myAdjuster->amount = -5.0;  // How do I make the amount be 100%?
$myAdjuster->orderId = $order->id;
    // Is this is where i need to loop through the line items and do the credit deductions?

$myAdjuster->optionsJson = ['lineItemsAffected' => null];

Do I do all of the looping and such within the adjustor? Instead of a dollar amount, I would like 100% off until my credits are zero. Then the user pays full price.

My apologies for such a large question. Any guidance is greatly appreciated!

I'm finding the question hard to follow, but if I am understanding you, then yes I would do it all in the adjuster - rather than using a discount here... I don't see what using a Commerce discount here offers, as you can't really express your credits system in any way meaningful that relates to a Commerce discount I think.

So this indeed looks like a job for an adjuster, which can act at either the lineItem or order level as per the linked example.

In terms of where you put that adjuster, there are basically three steps.  The first two are in your main plugin file:

public function init()
{
  Craft::import('plugins.yourPluginHandle.adjusters.YourAdjusterClassName');
}

and then later in that file...

 public function commerce_registerOrderAdjusters(){
   return [
     new BusinessLogic_TaxRemover
   ];
 }

Then, you have the actual code in your adjuster to do whatever you want to do, which (repeating that example), looks like this:

    <?php

    namespace Craft;
    use Craft\Commerce_LineItemModel;
    use Craft\Commerce_OrderAdjustmentModel;
    use Craft\Commerce_OrderModel;

    class BusinessLogic_TaxRemover implements Commerce_AdjusterInterface {

    public function adjust(Commerce_OrderModel &$order, array $lineItems = []){

    $myAdjuster = new Commerce_OrderAdjustmentModel();

    $order->baseDiscount = $order->baseDiscount - 5;

    $myAdjuster->type = "Test";
    $myAdjuster->name = "Test Adjuster";
    $myAdjuster->description = "Takes $5 off the order";
    $myAdjuster->amount = -5.0;
    $myAdjuster->orderId = $order->id;
    //if your Adjuster affects lineItems rather than the total, you record the ids here
    $myAdjuster->optionsJson = ['lineItemsAffected'=>null];
    $myAdjuster->included = false;

    return [$myAdjuster];

   }

}

...the main thing to note in there is you need to record the ids of any lineitems you're adjusting by changing this - ($myAdjuster->optionsJson = ['lineItemsAffected'=>null];


Storage advise for product catalog I am going to build a boat catalog.

Boat products x 40
Types of product x 3
Suppliers of products

I was wondering what the best storage setup?

For boat and suppliers these could be entries and categories, eg:

Boats = entries x 40
Suppliers = Categories x 9
Type = Categories x 3

But does it make more sense to use suppliers as entries fields and relate them to products as 'parents'?

Are there specific template benefits later on that can help steer the decision?

Craft gives you a lot of options here. I think you're close. The way I'd set it up:

Boats (section)
Suppliers (section)
Boat Type (category)

Then in your boats section, set up a Supplier relational field, and have it relate back to your suppliers section and also a Boat Type relational field, which relates back to that category group.

In this way, on the front end, you can easily filter by boat type or supplier.

Example: on your supplier pages, you can easily get a list of all the boats made by that supplier, just by querying that section like:

{# assume we're on a supplier page #}

{% set boatsBySupplier = craft.entries.section('boats').relatedTo(entry) %}

{% for theBoat in boatsBySupplier %}

{{theBoat}}

Model: {{theBoat.modelNumber}}

    ...
{% endfor %}

In terms of templating, there won't be a huge difference if you choose a category over an entry, for example, for your suppliers.

I tend to think of brands (suppliers) as content, thus content belongs in an Entry, not in a taxonomy (category). (Down the road you might want to have more than one supplier type, for example.)

But if your data on suppliers is relatively thin, a category would work just as well. Even then, unlike other CMS, Craft allows you to use custom fields on Categories to add more data. So there's no wrong answer there.  In that case, Craft will populate the category variable (and not entry) so just change that and you should be all good.

Not sure what you mean here:

  But does it make more sense to use suppliers as entries [fields] and relate them to products as 'parents'?

If you're asking about setting up a structure, and having the top level parent be the supplier and the boat model be a child, I'd steer clear of that.  A lot of things can go wrong with that model.

In general, I like to keep data structures as "flat" as possible and create depth with Craft's relationships. But if you're asking about using entries fields to relate your suppliers back to your boats, that's exactly what my example above does.


Retour Redirects with Craft and nginx I have come across an issue whilst using the Retour plugin for Craft similar to the question raised here but this is a redirect with a URL using the .htm extension and not .php.

Any ideas why this would not work?

Thanks

Retour only works if the 404 actually is handled by Craft; my guess is that your Nginx config somehow is not passing along the 404 to Craft.


Cycle tag - last cycle returns same cycle I have this code:

{% for entry in craft.entries.section('gigs') %}

{{ entry.title }}

{% endfor %}

This returns the same cycles for the last two entries like so:

Title 1

Title 2

Title 3

Title 4

Title 5

Title 6

No matter how many entries, the last two entries have always the same class. Why is that?

Edit: Okay, I figured the problem. It's not a bug:

I filter the entries by date:

{% set present = now|date_modify("-1 day") %}
{% for entry in craft.entries.section('gigs') %}
   {% if entry.datum < present %}

{{ entry.title }

    {% endif %}
 {% endfor %}

so the cycle filter works, but since some entries are filtered the odd/even schema doesn't work any longer. I guess I have to filter the entries first and then apply the cycle filter. But how would I have to write do that?

As you already found out, the loop.index counter increments for each iteration of the loop, not only if you use or print it within your conditional. The best solution to work against it is to get rid of that conditional.

In this case it is in fact possible to catch only those entries you are after, making the conditional redundent

{% for entry in craft.entries.section('gigs').datum('< ' ~ present) %}

{{ entry.title }

{% endfor %}

if it wasn't, you could have done your own counter that increments within the conditional.

{% set index = 0 %}
{% for entry in craft.entries.section('gigs') %}
    {% if entry.datum < present %}
        {% set index = index + 1 %}

{{ entry.title }

    {% endif %}
{% endfor %}


How to find my Craft ID account details I am developing a website on Craft CMS and now I need to change the domain for my Craft account. Because it's giving me an error "The license located at config/license.key belongs to...."

I do not have any details about the Craft ID all I have is the license key.

Is it possible to recover my Craft credentials using my Craft license key.

You don't automatically get a Craft ID account just from making a purchase.

You'd need to manually create one at https://id.craftcms.com.

If you create one with the same email address you've made purchases with, those purchases and license.key files will automatically be tied to your account so you can manage them and the domains they are associated with.

If you make purchases with different email addresses, you'll have ways of claiming those licenses via alternative email addresses from within your Craft ID account.

If you already have a Craft ID account and you don't remember the password, you can go through the "Forgot your password" link on https://id.craftcms.com by entering your existing username or email.


How can I set the dateCreated attribute on an EntryModel? I've tried this but it doesn't seem to be working:

$entry = EntryModel::populateModel(array(
    'dateCreated' => DateTimeHelper::formatTimeForDb($someTimeStamp),
    'sectionId' => 1
    'typeId' => 1
));

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

The dateCreated, dateUpdated and uid columns are more internal Craft auditing columns that Craft manages for every row in every table.

Maybe what you're looking for is the postDate column for entries, which you can set a custom value to.


Craft adds unwanted date to filename How to remove the date behind a asset filename or prevent add a date behind the filename? I'll have a plugin that's modifies an existing pdf with SETA SIGN. To do so I'm copy the current asset, modify it in the temp folder, unlink original, copy modified file and unlink the temp file. I tried to rename the file (with $rename) but still the date is added behind the filename. I'll found something with avoidFilenameConflicts but as far as I'll see this is for new assets not for moving or renaming assets.
$assetFilePath = $asset->getVolume()->getRootPath() . DIRECTORY_SEPARATOR . $asset->getPath();
....
        unlink($assetFilePath);
        copy($tempPath . DIRECTORY_SEPARATOR . $asset->filename, $assetFilePath);
        unlink($tempPath . DIRECTORY_SEPARATOR . $asset->filename);

...
$newFileName = 'bla.pdf';
$rename = Craft::$app->assets->moveAsset($asset,$asset->getFolder(),$newFileName);

bla.pdf becomes bla_2021-03-26-124307.pdf but I'll want just 'bla.pdf'.

Try using replaceAssetFile(), something like this (untested):
$rename = Craft::$app->assets->replaceAssetFile($asset->id,$asset->getFolder(),$newFileName);


Build a Property Management System with Craft CMS? Is Craft mature enough to build a robust rental property management system like http://www.appfolio.com/features or https://www.tenantcloud.com?

If so, are there any existing plugins that can handle any of the complex features? I will need to build or contract out the rest.

Required Features:

site visitors can search for rental units (on Map too)
tenants can pay rent online
tenants can make maintenance requests online
landlords can look at their accounts (income, expenses, past due, etc)
landlords, agents or admins can add new properties to the system
landlords or agents can book showings
automated notifications/emails (rent due, maintenance complete, etc)
lease document signing (DocuSign API or?)
calendar to schedule maintenance
e-commerce and accounting integration (possibly Quickbooks and banks API)

I've also been researching using ExpressionEngine or using an existing service like the ones mentioned above or even open source, but I really want to use Craft or even EE if possible for flexibility now and in the future.

I think the other answers here are accurate in saying that this could very well be a use case for a more specific application.

That said, I'm optimistic that this would be possible on Craft with enough planning, budget, and development time; and our own efforts while building out the Sprout Plugin Suite have had use cases like this in mind.

So, I'm going to try to answer how I'd approach this as a Craft project. There would be lots of questions to get answered along the way, so this is really just a very top level overview of where I'd start to look and ask questions.

I'll frame my answer around the plugins I'm most familiar with.  It's likely with the amount of custom development necessary, multiple plugins or starting points would take a similar amount of time.

1. site visitors can search for rental units (on Map too)

For this requirement, I'd look into Smart Map and reach out to Lindsey DiLoreto if you have specific questions.

2. tenants can pay rent online

This is possible in some form or another with Charge, Sprout Commerce, and Craft Commerce.  The latter two are in private and public beta as of this posting. Specific details would need to be explored.

3. tenants can make maintenance requests online

A fairly customized workflow is possible for this with normal Entries or Sprout Forms, and Sprout Email. When an Entry for a particular Section is saved via an Entry Form, or an Entry for a Form is submitted via a Form, an event will fire and you can setup a Notification in Sprout Email to trigger emails to different people (admins and users) based on different types of maintenance requests.  You have full control over the custom HTML in your notification emails and can customize the message with the information from the submitted Entry or Form.

If you have any specific questions around Sprout Commerce, Sprout Email, or Sprout Forms, you can reach out to Barrel Strength Design.

Views into your Element Listing Pages can be controlled via Element Hooks to help manage workflows and bring key information to the top level, such as the status of a request. For more specific needs, a plugin may be necessary.

4. landlords can look at their accounts (income, expenses, past due, etc)

This should be possible with default Craft functionality for a member section and you can pull data in from any native elements or any plugins that store their data in the database.

5. landlords, agents or admins can add new properties to the system

This is possible with the default Craft functionality and customizing Member Group permissions to your needs.  You'll need to build out the front-end interface, but all you need to allow people to submit data is there.  If you want to trigger email notifications when certain types of properties get added, Sprout Email has a customizable Event API so you could write or ask someone to write a custom plugin that allows emails to be triggered when certain conditions are met.

6. landlords or agents can book showings

It's unclear to me if this ties in to Calendar needs as discussed in #9 or a more general Event question where you have a showing and many people can come. Craft is pretty powerful out of the box and more specific event needs would probably need to be described for a more specific answer.

7. automated notifications/emails (rent due, maintenance complete, etc)

We have automated notifications planned (at some point) for Sprout Email, and we've worked on a some projects where we have initial implementations of this behavior. Some custom development would be needed here, but it's possible, and the notifications could be managed right in Sprout Email to make their content easy to update and manage for a non-technical user.

For things like notifying somebody when maintenance is complete, you could create a custom Email Event to allow you to trigger an email to the particular user who submitted the request when a maintenance work updates a custom field from one status to another.

8. lease document signing (DocuSign API or?)

Some Digital Signature programs allow you to embed certain document types on your website and allow them to be submitted by multiple people. I've seen various implementations of this functionality - however in my quick search around I'm not finding many examples that don't rely to some extent on the API.  I still believe they exist, but for now, my list to you is just this one:

PandaDoc

9. calendar to schedule maintenance

There are a few Calendar plugins to take a look at (in alphabetical order):

Calendar by Solspace
Calendars by Top Shelf Craft
Venti by Tipping Media

I'd recommend reaching out to each respective developer for specific questions.

10. e-commerce and accounting integration (possibly Quickbooks and banks API)

This is probably going to be the most challenging item to answer without a more detailed spec and understanding of what your budget is. Custom e-commerce and complex integrations, in general, take time to do well and get things right – especially when people are making decisions around the financial data and using that data to run the business.

Both Sprout Commerce and Craft Commerce are being built out with flexibility in mind, but I don't think either of them will be planning to integrate with Quickbooks, Xero, or banks before the more standard Commerce use cases are solved, if at all. It's likely what you're looking for here is a more custom integration targeted specifically at your accounting software and banks.

Depending on your budget, you may want to consider alternative workflows here too that combine programmatic and manual steps.

It's worth noting that most of us plugin developers are pretty friendly, and if you found yourself in a situation where Calendars or SmartMap weren't communicating with Sprout Email in a way that allowed you to send notifications like you need to, or vice versa, we like hearing about it and learning how we can help make the whole plugin ecosystem play more nicely together.

In general, I think these types of applications are a very fine line between custom application and CMS. On one hand, they are going to require customization and the app may be the better route.  On the other hand, enough components of the project revolve around general content management needs that a CMS like Craft already solves well and saves the trouble of managing your own admin UI and many other concepts that are already well established in Craft.

With a project as complex as yours, it may be worthwhile to consider a hybrid approach too. It may be that 80% of your project is a really good fit for Craft and that it makes sense to outsource certain functionality like Scheduling or Commerce to another platform.  Over time, maybe there will be an opportunity to migrate those types of features to Craft at a lower cost.

A lot of trade-offs like that are hard to make, but putting a price tag on your options helps you and your client choose the best approach for the current budget, and prioritize improvements down the road.


How html title is generated in entry index page in CP I am trying to find out how HTML title is generated in entry index page in Control Panel.

i know it is generated in src/templates/_elements/element.html file   by $this->hook('cp.elements.element', [$this, '_getCpElementHtml']); in src/web/View.php and i see there is a line in entry.php which calls author with

return $author ? Craft::$app->getView()->renderTemplate('_elements/element', ['element' => $author]) : '';

but i can't find how craft calls for title attribute.?

it seems that first column of table view is special and is called here
which calls mentioned hook in question.


Frontend form validation I need to validate the form submitted at the frontend by applying additional validation rules.

For that I have created the plugin that listens to "EVENT_BEFORE_SAVE_ENTRY" event and should validate input fields of the form.

Yii2 documentation suggests to override model rules() method to add custom rules, and then to apply validate() method.

The problem is that I cannot find how to override default rules of the Entry class, and how to use overridden classes as entries in Craft3.
Also I need to filter saving entry data from script tags of slashes to prevent script injection.

I am quite new to the Craft3, so please prodive some code examples and where exactly should I put my code
Thank you in advance!

I ended up using the Ad Hoc Validation method of Yii2, here is the link for documentation:
https://www.yiiframework.com/doc/guide/2.0/en/input-validation#ad-hoc-validation

My code for validation:
Plugin.php

class Plugin extends \craft\base\Plugin

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

    $this->setComponents([
        'form1Validator' => Form1Validator::class,
        ...
    ]);

    Event::on(
        SaveController::class,
        SaveController::EVENT_BEFORE_SAVE_ENTRY,
        function(SaveEvent $event) {
            try {
                $response = null;
                switch($event->entry->section->handle) {
                    case 'form1':
                        $response = Plugin::getInstance()->form1Validator->validate($event->entry);
                        break;
                    ...
                        }
                }
                if(!isset($response) || !$response['success']){
                    $event->isValid = false;
                    $event->entry->addErrors($response['errors']);
                }
            } catch (\Exception $e) {
                $event->isValid = false;
                $event->entry->addError('exception', $e->getMessage());
                return;
            }
        }
    );
}

}

Form1Validator.php

class Form1Validator
{
 public function validate(Entry $entry)
{
    $model = new DynamicModel(
        [
            'formGender' => $entry->formGender,
            'formFirstName' => $entry->formFirstName,
            'formLastName' => $entry->formLastName,
            'formEmailAddress' => $entry->formEmailAddress,
            'formPhoneNumber' => $entry->formPhoneNumber,
        ]
    );

    if(!$model
        ->addRule(['formGender', 'formFirstName', 'formLastName', 'formEmailAddress'], 'required')
        ->addRule('formGender', 'in', ['range' => ['male', 'female']])
        ->addRule('formEmailAddress', 'email')
        ->addRule('formPhoneNumber', 'match', ['pattern' => '/^[0-9]+$/'])
        ->validate()
    ) {
        return [
            'success' => false,
            'errors' => $model->getErrors(),
        ];
    }

    return [
        'success' => true,
        'errors' => [],
    ];
    }
}


Map one asset attribute field to another using MySQL In Craft, is it possible to map one field containing string value to another?

I have a bunch of image assets that has a title field and altTag fields. I've entered data into the alt tag field, but now I would like to copy that data for each asset into the title field for that same asset.

Doing this manually for each asset would take forever, but it sounds like something that could be done with mysql queries.

I poked around the database to see where the title fields or the altTag fields are stored. The altTag field is in the craft_fields table, and I can see all my assets in the craft_assetfiles table. But title is not one of the columns in this table, I do see the filename column. But I think my knowledge of the structure of craft tables are lacking to find where the values for the altTag fields are stored or how to copy the value of each alt tag into the corresponding title field for the asset.

You want to look at the craft_content table. There you should find the title column and the field_altTag column. You could set the title to the field_altTag value where that value is not empty.

Back up the database first...


Template caching tag storage options I can see that normal caching can have it's storage specified, but I would specifically like to be able to set the caching storage method for the template tag {% cache %}.

At the moment it appears to be hitting our MySQL database very hard and so I would like to consider using something like Redis instead.

Currently, the template {% cache %} tag can only cache to the database.

See Brandon's comment here ("Template caches always go to the database").


"Unknown "craft" function" Error in Plugin Service Call I'm just starting with plugins and I've downloaded the Business Logic plugin and am trying to call it from my template.

Here's the code in my template:

{% extends "_layout" %}

{% block content %}
{{craft()->businessLogic->exampleService()}}

{% endblock %}

And the code in the BusinessLogicService.php:

class BusinessLogicService extends BaseApplicationComponent

{

    /**
     * This function can literally be anything you want.
     *
     * HOW TO USE IT
     * From any other plugin file, call it like this:
     *
     *     craft()->businessLogic->exampleService()
     *
     */
    public function exampleService()
    {
        return "I've got your data right here!";
    }

}

It returns this error:

Unknown "craft" function.

Would I call it a different way?
Thanks for any help with this.

There are multiple issues happening here...

The Twig code should look like this:

{{ craft.businessLogic.exampleVariable() }}

As noted in that example, Twig can't communicate directly with a Service level method. You'll need to ping the Variable class, and use your Variable method to call the Service method.

Optional...

The Business Logic plugin template currently only works with Craft 2. If you're attempting this on a Craft 3 site, several things would need to be changed.


Is it possible to modify the input format for dates in front end form? From other threads and my own tests a date field needs to be input in the format of 10/15/2012 (mm/dd/yyyy). But that's not very "British", is there any way to modify it?

Paul, when I change the Locale setting to British English (en_gb) within the database, the Post Date field's date-format changes to dd/mm/yyyy.

In DB: databaseName > craft_locales > Change "en" to "en_gb"

Let us know how you get on :)


How to activate a user in a plugin? I'm trying to activate a user via a plugin so that when the user is returned to the login page they are re-directed to their profile page.

I'm making use of the social logins beta plugin by dukt (I have written directly to them as well) which works fine if the user is already a craft user. However if the user is completely new to craft it throws an error saying the 'Account Has Not Been Activated'. When checking the CMS though the account has been set up and is active. So somewhere along the line the activation seems to be too late and is being delayed until after the user is sent back to the template.

The code creates a new user model in the plugin service with the _registerUser function. Which when looking at the object returned has 'pending =>' so not actually set to anything not even zero.

I've tried a couple of things but neither worked firstly adding

craft()->users->activateUser($user);

directly after saving the new UserModel and before returning the model.

Secondly setting the new UserModel with pending = 0 and pending = '0'

$newUser = new UserModel();
$newUser->username = $attributes['email'];
$newUser->email = $attributes['email'];
$newUser->pending = '0';

So can anyone shed any light on this or can advise me if this is possible from within the plugin or how the activation works on a new user when you want to automatically activate them without sending an activation email.

Many thanks

You'll need to save the new user before you can activate them. This code should do the trick:

if (craft()->users->saveUser($newUser)) {
    craft()->users->activateUser($newUser);
}


How to build complex Element Criteria? How to fetch Elements with a complex DB query?
E.g. with some nested AND/OR conditions or just apply two conditions to one field?

For example my Elements have a field eventDate. I want to fetch all Elements where eventDate is NULL or equals "1900-01-01".

The standard way to build Element Criteria is:

$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->eventDate = '=...';
$models = $criteria->find();

It doesn't provide an ability to apply several conditions for same field. Is it possible at all without assembling huge queries manually?

You can apply conditions within the same field but you can't create conditions for multiple fields.

Here are some great examples

$criteria->expiryDate = 'or, :empty:, =' . $yourDateValue;

However you can't combine conditions for multiple fields. So you can't say Where (fieldX = 4 OR FieldY = 5) you would have to create an sql object based on your ElementCriteriaModel and use Yii's great Query Builder for that and use the OrWhere function

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


PHP Fatal error: Allowed memory size of X bytes exhausted Getting the following when just querying the database for all records in a section (channel). There are about 75 entries.

I'm getting the PHP Fatal error:

  Allowed memory size of 33554432 bytes exhausted (tried to allocate 32 bytes)

Why would i be running out of 32MB for these pretty simple entries? The channel entry type just has a title, body, image URL, text field, and a field referencing another channel entry type.

I am using the SortByField plugin. Wonder if that's causing any issues. Here's my query:

{% for entry in craft.entries.section('people').find()|sortByField('lastName', 'asc') %}
     // ... outputting names of people, etc.
{% endfor %}

Craft will run out-of-the-box with 32M of memory, no problem.  However, memory consumption will start to increase depending on several factors including:

The complexity of your site, including the number of fields, sections (and types of sections), categories, tags, users, entries, plugins in use (and how efficient they are working), etc.
More importantly, how your front-end templates are coded and how they are pulling in all of this data in.

Also worth noting that 32M is usually the default on older PHP installs (or really stingy newer hosts) and the latest PHP releases ship with something more reasonable, like 128M.

If you enable devMode, you can view memory profiling information in your browser's console to help you see where the memory is being distributed.


Search in checkbox field with pagination It seems like this should be a simple thing, but it's evading me... I have a checkbox field in my entry named "articles_categories". Just to clarify, these are not actual categories -- they are checkboxes and I cannot modify them at this point.

I want to use the option value of the checkbox as an exact search parameter. I'm using pagination, so it needs to pass through paginate. This is what I have:

{% set topic = craft.request.getQuery('topic') %}

{% paginate craft.entries.section('blogArticles').limit(10).search(topic) as pageInfo, pageEntries %}

The option values are being passed as the topic parameter. For example, '?topic=healthcare',  or '?topic=food-fitness'. I'm getting a different set of results from each query, however, I don't believe that this is set up to return an exact match on the value passed through the search function.

I need only the articles that have an exact match in that field.

The value is stored as a serialized array in your database,  you would need to filter for the string "["healthcare","food-fitness"]"

Since your query parameter is an array you just need to prepend an and parameter to it so it looks like

articles_categories(['and',  '*healthcare*', '*food-fitness*'])

If you have only one parameter and want an exact match you need to search for the exact string

craft.entries.articles_categories('["healthcare"]')


How could I make related entries load faster? I need to show a list of users (around 400). No problem, the list loads in 1.5s, for which I could use {% cache %} to speed it up.
Now, the problem arises whenever I want to display the title of an entry related to the user. The log shows 400 extra queries, so a query per user, if I do this:

{% for user in user %}
    {{ user.relationFieldName.first() }}
{% endfor %}

This seems a bit faster, but not fast:

{% for user in user %}
    {{ user.relationFieldName.find()[0] }}
{% endfor %}

Is there a way to get this information directly when querying for users? Or is there another way to speed this up?

Would eager loading these relations through a plugin help? And if so, what service/model/record would I have to extend to go about this?

You could use a template hook to eager load the related data from a plugin and cache the results for future requests.


Open pop on click of custom action and get filled data I created a new custom action.

A new button is added in getAvailableActions() as we can se in below screenshot in red marked rectangle, now when i click on that button
 (Cusotm Action) i want to open a pop up box ( i used Default pop up js lib.

Template File path : /craft/plugins/tagmanager/templates/_mergetags.twig

{% includeJsResource "tagmanager/js/tagmanager.js" %}

{{ "Merge Tags"|t }}

Modal header

js part

$(function () {
  $modal = new Garnish.Modal($('#mergetags-modal')); //create a new modal
  $modal.show();
});

Not able to open pop up correctly.

Thank you.

I'm not sure what your Question is exactly and what your expected outcome is but to create a Modal you can use this HTML

My Awesome Modal

and via JavaScript you can show it

//create it
var modal = new Garnish.Modal($('#my-awesome-modal'));
modal.show();


Registration into default group is not working as expected Here are my settings for user registration:
\

When front end registration completes the users are added fine but not into the default user group as expected. They are just in the system with no group.
I was expecting them to be registered into the default group - am i missing something?

I get bit by this a lot.
Just like @Stephen Lewis suggested - make sure you are not logged into the same browser.

For example, log into the CP with Safari (or whatever) and then use Chrome to actually register an account via your front-end form.


redirect index.php in urls on Craft site to NEVER show index.php We’ve recently had some issues with a staging site being down and it turned out the reason for this was: In the words of Brad at Pixel and Tonic, the redirect is "intercepting the update request for the plugin causing Craft to no longer think it's a POST request”.

caused by:

# make sure index.php is always removed from url (google analytics   tracks duplicate)
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s/+index\.php(/[^\s\?]+)? [NC]
RewriteRule ^ %1 [L,R=301]

we also have in all our craft sites the normal CRAFT removal of index.php from the urls:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^ index.php%{REQUEST_URI} [L,NC]

Essentially, a lot of our sites are existing sites that we redesigned and developed, so the .htaccess files contain a lot of redirects for analytics. We noticed that google analytics started tracking duplicate URLs (duplicate being some contained index.php). After some investigation, I found out that the URLs containing index.php were from redirects (although none of the redirect rules contained index.php).

So in order to make sure no urls ever contain index.php, I added the above mentioned rule.
However, we learnt the hard way that that doesn’t work with Craft.

What recommendations do you have in order to never have index.php in URLs? I realize that the standard rewrite rule that the Craft CMS comes with is good enough to hide/remove the index.php from the url and you will normally only see the index.php in the url if you type it in manually - but for some reason, it does show up sometimes when people land on a redirect url which messes with the analytics data.

The way we got around it in the end was asking the folks that take care of the analytics to merge the URLs, which ended up being easy enough to do. I was just wondering if there was any other way?

As another option that I usually do in addition to .htaccess, is to also add this to the array in craft/config/general.php file, and it'll stop Craft from ever adding the index.php.

'omitScriptNameInUrls' => true

Doing it this way prevents Craft from ever adding in the index.php to redirects, I believe.


Populate Field Group With Fields From Another Field Group I hadn't seen this asked, so I thought I'd broach the subject.
I would like to copy fields into a new field group, and then add/delete a few of those fields from the new group, to save time of building one again from scratch.
Does Craft have a way to do this?

No, there's nothing built into Craft that lets you do this.

Please note though, that you can reuse fields across sections in Craft. Field groups is just an organizational layer on top of fields to make it easier to add a group of fields to a section, and to be able to find fields more easily. It doesn't give any additional meaning to the fields. So you can't have a field with the same handle in different field groups, and it doesn't make sense to duplicate a field that's actually used across sections.

If you need to duplicate fields (because they're actually suppose to be different fields), I highly recommend the Field Manager plugin by Verbb (Craft 2 and Craft 3 versions available) which makes it super easy do to this, and in general provides a much better interface to manage fields.


How do I disable the default translation feature for a custom field? I am making a custom field that provides granular control of what values will be translated and what values will remain shared across multiple sites.

Because of that, I'd prefer to entirely the disable the default translation feature of the field so users cannot accidentally set the field to be translatable (which would defeat its purpose).

Is this possible?

You can set the translation method  for each field individually

public static function supportedTranslationMethods(): array
{
    return
    [
         self::TRANSLATION_METHOD_NONE
    ];
 }


How to get a list item  using a plain text field every time I hit enter I'm trying to get a list from a simple plain text field which will accept line breaks. I need to find a way to wrap an li tag around the content on that line. So everytime I hit enter, it wraps
Whatever is on that line

So going from this:

Into this:

Thanks!

You'll want to split on the line breaks, then loop through the resulting array...

{% for ingredient in listOfIngredients|trim|split('\n') %}
    <li>{{ ingredient }}</li>
{% endfor %}


How does the Structure section type work? I read the documentation but I'm still confused about the Structure sections..

What they are usually used for? What are the advantages of using it?
And most important how to use them?

Please can you explain with some examples?

I don't know if its possible to be much clearer than the official docs on this matter, but basically a Structure is needed if your entries needs to be in a specific order (and you want to manage that order w/ an easy to use, drag-n-drop interface within the Control Panel), or if they need to be nested (i.e. hierarchical, with parent/child entries).

The alternative to a Structure is a Channel. A Channel doesn't have the ability to nest entries – in other words, it's a flat stream of content – nor can entries be sorted in a specific order; you're stuck with sorting by published date, title, ID or other "standard" meta data. The best example of a good use case for a Channel I can think of is a blog.

If you create a Channel and later realize that it should've been a Structure, you can convert it by visiting that Section's settings and choosing "Structure" for its type. You can also convert a Structure to a Channel, although if you later convert it back to a Structure your ordering/nesting data will be lost.

Some good use cases for a Structure could be:

A "Documentation" type section, with "main" entries (e.g. "Javascript") and sub entries (e.g. "Javascript / jQuery"). The official Craft docs are built using a Structure, where child entries (e.g. "Requirements") are nested under parent entries (e.g. "Installing and updating"). See this answer from Brad Bell for a bit more information on how P&T built the docs.
A "Navigation" type section – some people like to build their site's navigation using a Structure, which makes it easy to edit the order of the nav items, create dropdowns/sub menus etc. Here's a thread with some information more information on this approach.
A "Recipes" section, where you could easily sort the different recipes after course types (meat/vegetarian)

As for using Structures, I'm assuming you're talking about how to display the entries in a template – as the usage within the Control Panel should be fairly self-explanatory. Basically, outputting entries from a Structure is no different from the other section types:

{% for entry in craft.entries.section('myStructureSectionHandle') %}
    ...
{% endfor %}

However, if your Structure's entries are nested, using the nav tag instead of the basic for loop can be helpful in displaying the hierarchical content, because it can recursively output child entries:

{% nav entry in craft.entries.section('myStructureSectionHandle') %}

        {{ entry.title }}
        {% ifchildren %}

                {% children %}

        {% endifchildren %}

{% endnav %}

Beyond this, I think your question is a bit too open-ended to answer in detail, and you should probably create separate questions for any specific issues or problems you encounter working with Structures.


Merge, shuffle, and paginate I'm trying to get a list of users from two different user groups. One user group (premium) must always show first. Whenever the page is loaded, however, the listing of users should show randomly (while keeping premium users at the top of the list).

Also, the listing needs to filter on a particular service which is determined by the entry slug (in the user profiles, that field is set to an Entries fieldtype).

I've been able to get this like so:

{% set thisService = entry.slug %}

{% set premiumMembers = craft.users().group('premium').search('counselingServices:'~thisService) %}
{% set shuffledPremium = shuffle(premiumMembers) %}
{% set basicMembers = craft.users().group('listed').search('counselingServices:'~thisService) %}
{% set shuffledBasic = shuffle(basicMembers) %}

{% set listedMembers = shuffledPremium|merge(shuffledBasic) %}

That all works great, but that of course is an array. I need to paginate the results which isn't possible with an array.

How can I paginate this? Or is there a better way to get the same results in an Element Criteria Model so that I can use the paginate tag?

Got some help and finally got this working. Here's the final code for my future self and anyone else that may need this:

{% set thisService = entry.slug %}
{% set shufflePremium = shuffle(craft.users.group('premium').search('counselingServices:' ~thisService).ids()) %}
{% set shuffleBasic = shuffle(craft.users.group('listed').search('counselingServices:' ~thisService).ids()) %}
{% paginate craft.users().id(shufflePremium | merge(shuffleBasic)).limit(16).fixedOrder(true) as pageInfo, members %}

{% for user in members %}
  (...)
{% endfor %}


Craft 3 beta nginx config I have a Craft 3 beta project working fine on my local laravel/homestead box using nginx, however when I push to Heroku using their heroku-php-nginx build pack I get nginx (not Craft) 404s when trying to access the /admin area.

My Procfile looks like this:

web: vendor/bin/heroku-php-nginx -C deploy/nginx.conf public/

and my deploy/nginx.conf looks like this:

location / {
    try_files $uri @rewriteapp;
}

location @rewriteapp {
    rewrite ^(.*)$ /index.php?p=$1 last;
}

This setup works fine with Craft 3:

Nginx-Craft


How do I get the data from a relation field? If use the following code:

$currentEntry = craft()->entries->getEntryById($entryId);
$currentContent = $currentEntry->getContent()->getAttributes();
$currentAttributes = array();

$fieldLayout = $currentEntry->getFieldLayout();
foreach ($fieldLayout->getFields() as $fieldLayoutField) {
    $field = $fieldLayoutField->getField();
    if (isset($currentContent[$field->handle])) {
        $currentAttributes[$field->handle] = $currentContent[$field->handle];
    }
}

It retrieves all data that I want, but I don't get the data from relation fields. If an asset or entry has been selected, I won't receive that data. The result from that field is always null.

Does anyone know how to do this?

If you already know the custom field name then it is pretty straight forward:

$currentEntry = craft()->entries->getEntryById($id);
$relatedEntries = $currentEntry->customFieldName;

Then you could either loop through each one:

foreach ($relatedEntries as $entry) {
    echo $entry->title;
}

Or simply get the data from the first one:

echo $relatedEntries->first()->title;

Remember that all related entries come back as an array even if you have specified that the user can only select 1.

Hope this helps


I've inherited the Craft website and the developer is long gone. How do I access the templates used to initally build the site? Our website was created by someone who is no longer with the business. I can edit existing data, however am trying to access the original templates used when the site was originally built in order to change a few things. Where would I find these?

I suppose you need access via FTP to the templates directory - which by default is craft/templates. Once you have access to that, you'll have access to the site templates. Do you have FTP access?

There's no way in Craft to view your templates through the Control Panel interface.


How do you "pin" a flash error message in the CP? It's possible to generate a "flash" error message at the top of the control panel like this:

craft()->userSession->setError('Your custom plugin error message.');

The message appears at the top of the control panel when the page loads, but then fades away after a few seconds. Is there any way to "pin" the message to the top of the page, so it stays indefinitely?

I have not tried but you could probably use the CP Custom JavaScript plugin to force display of .notification.error as the flash only sets display: none; and does not remove the element.


How to call abstract method from interface I would like to use a method of fileExists. It belongs to VolumeInterface.
https://docs.craftcms.com/api/v3/craft-base-volumeinterface.html

I suppose the code would be like \craft\base\Volume::fileExists($path).

However, Craft returns an error;

Non-static method craft\base\VolumeInterface::fileExists() cannot be called statically

Could I ask how I should modify the code?

The normal way would be to instantiate and call non-statically like this:

(new \craft\base\Volume)->fileExists($path);

...However, that won't work here because it's an abstract class, which, by definition, cannot be instantiated. Assuming you're dealing with an Asset element(?), try calling getVolume() and then you should be able to call fileExists() from there. E.g:

$asset->getVolume()->fileExists();


How do I hide children of a disabled parent in a nav? So I've got a {% nav %} I'm trying to create with the following code:

{% nav page in craft.entries.section('pages') %}

        {{ page.title }}

        {% ifchildren %}

{% children %}

        {% endifchildren %}

{% endnav %}

My issue is that I've got a top-level page that has been disabled but has some enabled child/sub pages (second-level). So the code above doesn't display the disabled top-level page but it is showing all the enabled children of that disabled page. I've tried wrapping different parts of the {% nav %} code with a conditional but that seems to interfere with the {% ifchildren %} tag.

So my question is, is this the default Craft functionality? If so, what's the best way to solve this problem? Thanks!

This is an example of our "quick and dirty" menu macro we used in older projects. It's recursive so it can have as many levels as you want and will only fetch enabled entries. For mobile devices the parent entry is rendered in the "child" menu as well because otherwise you won't be able to access parent entries with children.

It looks a bit overwhelming at first, because we had many things to consider but it's relative easy

{% macro menu(menuCategory, currentPage, includeStartpage, level = 1, parent = null, original = null, showParentPage = null) %}
    {% set originalPage = (original)? original : currentPage %}
    {% set activeClass = '' %}
    {% if original is not null and currentPage is not null and original.parent is not null %}
        {% if original.parent.id == currentPage.id %}
            {% set activeClass = "active" %}
        {% endif %}
    {% endif %}

        {% if includeStartpage %}
            {% set startseite = craft.entries.section('homepage').first() %}

                {{ startseite.title|raw }}

        {% endif %}

        {% if showParentPage and parent%}

                {{ parent.title|raw }}

        {% endif %}

        {% switch menuCategory %}
            {% case 'mainmenu' %}
                {% set entries = craft.entries.section('pages') %}
            {% case 'topmenu' %}
                {% set entries = craft.entries.section('pages').showInHeaderMenu('1') %}
            {% case 'footermenu' %}
                {% set entries = craft.entries.section('pages').showInFooterMenu('not 0') %}
            {% case 'descendants' %}
                {% set entries = parent.getChildren() %}
        {% endswitch %}

        {% for page in entries %}

            {% set url = _self.getUrl(page) %}
            {% set target = _self.getTarget(page) %}
            {% set title = page.title %}
            {% set class = "" %}

            {% switch page.type.handle %}
                {% case 'internalLink' %}
                    {% set title = page.linkName %}
                {% case 'externalLink' %}
                    {% set title = page.linkName %}
                {% default %}
            {% endswitch %}

            {% if (originalPage.getUrl == url|trim and not page.hasDescendants)  %}
                {% set class = "active" %}
            {% endif %}

            {# Check if entry has descendants #}
            {% if not page.hasDescendants or (menuCategory == "footermenu" or menuCategory == "topmenu") %}
                {# List navigation item if entry has NO child entries #}

                    {{ title|raw }}

            {% elseif menuCategory == "mainmenu" or menuCategory == "descendants" %}
                {# List navigation item if entry does have children #}

                    {{ title|raw }}
                    {% set includeParent = (page.type.handle != 'pageWithoutContent')? true : false %}
                    {{ _self.menu('descendants', page, false, level+1, page, originalPage, includeParent ) }}

            {% endif %}
        {% endfor %}

{% endmacro %}

Edit

You can use it with

{% import '_macros/menu.twig' as menu %}

    {{ menu.menu('mainmenu', entry, true) }}

You can remove all the entry.getType().handle checks. We have the entry types pageWithoutContent so they will only appear in the menu as "placeholders" to open sub menus, but if the entry type is a page with content the entry must appear in the sub menu as well to make it clickable for mobile devices. These pages need to have an active when they appear as "parents" but not as "children". You can see a working example of this menu here or here


Asset filename unicode normalisation? We have a site deployed in Norway, and people have uploaded PDF-assets with Norwegian non-ascii characters in the filenames.

Normally this works fine, the URLs are encoded like this and it works:

http://[oursite].no/assets/files/downloads/%C3%85rsberetning-2014_kladd.pdf

("Årsberetning" - annual report)

But one file didn't want to download, it only gave me 404. However, checking on the server the file was there, and the filename appeared correct. Also, re-scanning asset folders didn't remove it.

BUT - I was not able to rename the file from within craft, nor download it.

After much hair-pulling I established that the file on disk had the Å encoded as '\x41\xcc\x8a' whereas craft looked for a "pre-composed" Å ('\xc3\x85').

NOW the question - where did this break? :)

Does Craft unicode-normalise filenames?
Does MySQL normalise the unicode it stores?

The file has moved around various developer machines and staging servers before making it into production, it could be some other part of the tool-chain that broke it.

This has now been solved by the addition of the convertFilenamesToAscii config setting introduced in Craft 2.4.

If you are working on a multilingual site, you might also find the limitAutoSlugsToAscii config setting useful.


How to create a user editable dropdown field? Trying to figure out the best way of handling this scenario:

We have a data field for a entry type that should allow an editor in the CP to select one option from many (ie. a dropdown). However, we want to give the editors the ability to modify the options for this select list - and can't let them into a superadmin mode in the CP where they'd edit the original field parameters (if this were a dropdown field).

To do so, we're considering using categories. That presents easy UI in the CP to allow them to manage the list of options as needed, from which they'll select one when creating a new entry in the CP.

However, this piece of data isn't a category (as far as a user would think of it) so I am not certain if there is a more elegant way to handle this and avoid using categories? I looked for a field type that might do something like that but couldn't find one.

Thanks!

I'm not 100% I follow, so I apologize if this isn't what you are looking for. Are these values being managed/edited within the CP? Or are the editors adding these values from a front-end form?

A project I worked on needed a base set of values in a drop-down field for each entry. But each entry that was created by the author could have additional values (or less). The way I did this was to create a table field in the CP. It consisted of two columns label and value.

This way I could have a "default" set of values that each entry would inherit. The author could then add additional rows (or remove) as they needed.

In the template, I just treated the table as a drop-down (in your case it will be a multi-select).

<option value="">Select</option>
    {% for option in entry.myField %}
        <option value="{{ option.value }}">{{ option.label }}</option>
    {% endfor %}
</select>

Hope this helps!

Edit/Update

I still think if you don't want to go the category route, you could do this within a field. I've attached a screenshot of what this looked like on a similar project. The label is the left column, and the value is the right. Each row is a new value in my drop-down field that is created on the front-end.

By default all of these values are in the dropdown for each entry. The author can add/remove whatever they want in addition to the default data. But, whenever "New Entry" is pressed, each entry starts with the same data.

Where it might get tricky is if you want these added/removed values to persist from entry to entry. You'd probably have to write some sort of plugin that saved the new values back to the original field.


Can't backup DB locally with MAMP PRO 5.5.1 I have followed the instructions for this article (https://craftcms.com/guides/database-backups-in-craft-3-with-mamp) to get local backups working with MAMP. However, when I attempt a backup, I get this error: exit code 127: sh: mysqldump: command not found.

which mysqldump returns /Applications/MAMP/Library/bin/mysqldump and I can dump a db successfully from the terminal using 'mysqldump` but it does not work from the Craft CP for backing up a DB or when Craft tries to backup a DB when running an update.

Is there something else I should be doing?

The help article referred to above seems to make it pretty clear that this should work.

UPDATE:

After further testing, it seemed that those .env variables just did not seem to be getting used after I added...

'backupCommand' => getenv('BACKUP_COMMAND'),
'restoreCommand' => getenv('RESTORE_COMMAND'),

...to my general.php.

So I tried adding this module instead and now DB backups work as expected.

I'd still be curious to hear from anyone at Craft as to what could be missing in that first method they've laid out.

I have run the following on my computer in order to allow Mac OS's terminal to speak to MAMP's MySQL. I have not done the steps outlined in your linked article. Craft's built-in backup tool works fine for me so perhaps this will help you too.

sudo ln -s /Applications/MAMP/Library/bin/mysqldump /usr/local/bin/mysqldump

Here's a github issue on the matter that runs through a few possible solutions (including the one above).


Output a Twig tag within another Twig tag I have a Matrix with a block for a contact form. I have a field for the email recipients. But the output doesn't work.

How can I render/output the output a tag within another tag, like this?

<input type="hidden" name="toEmail" value="{{ '{{item.mailto}}'|hash }}">

You are hashing the string '{{item.mailto}}'. There shouldn't be any need for the quotes or second set of curly braces.

Twig does not permit curly braces inside curly braces.

Try {{ item.mailto|hash }} instead.


Setting tab 'error' class for tab with error When creating an editor interface within my plugin, I am using the following snippet to create a set of tabs inside a tab pane:

{% include "_includes/tabs" with {
   tabA: { label: 'Tab A'|t, url: '#tabA' },
   tabB: { label: 'Tab B'|t, url: '#tabB' },
} %}

Now, when I submit my editor form and there is an error in a form field that's part of tabB, I want to indicate this by highlighting the tab title in red. This is usually done by adding the class 'error' to the tab. So, using Twig, I could determine which tabs have errors right before defining the actual tabs and apply the class 'error' to the relevant tabs. I could also apply the 'error' class using JavaScript upon form initialization.

Just wondering what the recommended way of doing this is or whether there is some built-in code to easily do this?

I don't believe there is any 'built in code' you could use.

You have 2 options though.

You could either do this in twig by checking all fields in a tab and adding an error class to the tab:

{% set actionClasses = "" %}
{% if (sale.getErrors('discountAmount') or sale.getErrors('discountType')) %}
    {% set actionClasses = "error" %}
{% endif %}

{% set saleClasses = "" %}
{% if(sale.getErrors('name')) %}
    {% set saleClasses = "error" %}
{% endif %}

{% set tabs = {
    0: {'label':'Sale'|t,'url':'#sale','class': saleClasses},
    1: {'label':'Conditions'|t,'url':'#conditions'},
    2: {'label':'Actions'|t,'url':'#actions','class': actionClasses}
} %}

Or you could pre build the 'tabs' variable in the controller and add the errors there:

if ($variables['account']->hasErrors())
{
    // Add the 'error' class to any tabs that have errors
    $errors = $variables['account']->getErrors();
    $accountFields = array('username', 'firstName', 'lastName', 'email', 'password', 'newPassword', 'currentPassword', 'passwordResetRequired', 'preferredLocale');

    foreach ($errors as $attribute => $error)
    {
        if (isset($variables['tabs']['account']) && in_array($attribute, $accountFields))
        {
            $variables['tabs']['account']['class'] = 'error';
        }
        else if (isset($variables['tabs']['profile']))
        {
            $variables['tabs']['profile']['class'] = 'error';
        }
    }
}

Hope that helps.


Feed Me logs access from the front-end So I've created a web portal for a client so they could upload a file which triggers a Feed Me feed (on that file). I handle the upload and triggering of the feed with a custom Module. I trigger the feed using the php exec function and the feed's Direct Feed URL. I would love to show the user the log for the Feed's task while it's running, so they would know if any errors occur. Is there a way to do this?

I would look to the feed-me plugin itself:
The controller:
https://github.com/craftcms/feed-me/blob/develop/src/controllers/LogsController.php
Which calls the service: https://github.com/craftcms/feed-me/blob/3a8246c055240c46ae9307f3ccada3c42d296920/src/services/Logs.php#L71
Essentially it just reads the log file and presents it to a template, so you could use JS/AJAX to return the results every x seconds.


Use sidebar nav icons in modules and plugins When adding a navigation item, there is the option to specify an icon, but it seems to have to be a path to an SVG. I can see that Craft has its own icon library, and it has an icon I want to use.

I want to use the "mail" icon, so I tried this HTML:

'icon' => '',

this is inside my registration of the navigation item:

Event::on(
    Cp::class,
    Cp::EVENT_REGISTER_CP_NAV_ITEMS,
    function(RegisterCpNavItemsEvent $event) {
        $event->navItems[] = [
            'url' => 'contact-enquiries',
            'label' => 'Contact Enquiries',
            'icon' => '',
        ];
    }
);

However, it doesn't show the icon.

I can't see anywhere in the docs that explain how to use these icons in your own navigation items, so is there a way to do it? It'd be a lot easier than having to include an SVG that doesn't match the other icons.

You were almost there with it. You need to specify a path to an SVG. It can be one of the ones that exists within Craft's icon directory.

So your nav item would look like this:

Event::on(
    Cp::class,
    Cp::EVENT_REGISTER_CP_NAV_ITEMS,
    function(RegisterCpNavItemsEvent $event) {
        $event->navItems[] = [
            'url' => 'contact-enquiries',
            'label' => 'Contact Enquiries',
            'icon' => '@app/icons/envelope.svg',
        ];
    }
);

And this is how it will show in the CP nav:


Security Key and Boilerplate We have set up a Craft 3 installation with composer to serve as boilerplate for a number of upcoming projects. The installation sits in a private git repository and the plan is to clone it when we start a new project.

Everything works fine, but since new projects will spawn from the boilerplate, the Security Key is the same for all of them - which probably is a bad idea.

Is there a way to assign a new security key when we clone the boilerplate for a new project? Are there other security considerations to take into account?

Thanks a lot!

You can run the craft setup/security-key console command after cloning the repo.  That'll generate a security key for that Craft install and put it in the local .env file.

Or for that matter, craft setup will run the whole setup process (database credeitials, security key, etc.).

  Are there other security considerations to take into account?

Keep your craft/config/license.key out of the repo so that a new one is generated for each cloned site.