Smart Map - Sorting for closest location in PHP I want to sort entries with a Smart Map address field for closest location. I know how it should be done in a template:

{% set entries = craft.entries.myAddress(params).order('distance').find() %}

Only, I would like to do so in my business logic and not in my template. I tried something like this.

$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section = 'houses';
$criteria->myAddress->target = '90210';
$criteria->order = 'myAddress.distance';

However, this does not work.

Is this possible? I tried related options but can't seem to get anything to work. Can I also do this with the Element API plugin to return the results as JSON?

You're very close!
$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->myFieldHandle = array(
    'target' => 90210,
    'range' => 100
);
$criteria->order = 'distance';

$results = $criteria->find();

I've never actually tested it with the Element API plugin, but in theory it should work just fine.
In response to this question, I've added instructions for PHP to the docs.


How to set base URL on the installation of Craft CMS on server I am a beginner. I just install it on a server and also on localhost. But facing the same problem.
I set it http://www.example.com/ but I go to this URL it shows me the directory but when I go to http://www.example.com/web it goes to the default template.
I want to access default template on http://www.example.com

Create a new web server to host your Craft project. Its document root should point to your public HTML folder. If you’re using Craft’s Composer starter project, then it is the web/ directory by default, but it can be renamed to anything you want as long as your web server is configured to point to it.

If your web host already has a public HTML folder setup to for you that you cannot rename, then you can just copy the contents of Craft’s web folder to it and use your host’s default public HTML folder.


PHP notice unserialize(): Unexpected end of serialized data Ok so this is an incredibly wierd one and I have no idea how to explain the problem in just one sentence so I just put the error message as the title.

So I am building a site with craft...in fact its basically complete. I was developing it in linux ubuntu but also using the vagrant homestead virtual machine to develop from so OS is kinda irrelevant.

Anyway...this is at work and they decided to be nice and get me a mac for work for christmas so I'm just basically trying to set up my working environment on the new computer.

So I set up homestead, pull everything from the git repositories, set up the databases and import everything...go to launch the site and I get the error message that is in the title and it highlights this line: $value=unserialize($value);

ok...interesting...after some googling i read something and decided to try and go into my config file and turn off developer mode...

When I go to a normal page it gives me this error: CDbCommand failed to execute the SQL statement: SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #25 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'db_name.structureelements.root' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

I did some research into this and tried to edit my my.cnf file to modify the sql_mode parameter also with no luck although i think the line I was given was not correct for the version of mysql that I have...perhaps this is where the issue is?

...and when I try to log into the back end aka /panel it gives me this:

Your server doesn’t meet the following requirements to run Craft CMS:

Mcrypt is required.

Please talk to your host/IT department about upgrading your server.

Ok...fair enough...maybe I need this mcrypt thing...the thing is I think it is already installed? It is listed in my phpinfo(); I have gone through the steps to install it (and yes I have restarted nginx and php....and mysql and still nothing...)

I really have no idea what the problem here is...the only thing that i can think is that my vagrant environment is different to the one I had in linux as I downloaded it more recently but I have no idea what setting/software version number/whatever somewhere is different that might be causing this?

Please feel free to ask for more info as I really am not sure what I am looking for here...I know that the vagrant environment is working as well as normal php is running (as I was able to run the phpinfo(); function succesfully.

The vagrant box is running php 7.1

Thanks in advance...

Matt

Update:

Craft 2.6.2957 added support for PHP 7.1

There's a lot going on here, but 1st thing is 1st.

  The vagrant box is running PHP 7.1

Craft 2 (and the current latest version of the Yii framework - 1.1.17) are not yet compatible with PHP 7.1.

When the next Yii 1 release is out that addresses the framework compatibility issues, we'll get Craft 2 up and running on PHP 7.1.

Until then, you'll want to use PHP 7.0.x.


How to output taxCategory in Craft Commerce I'm trying to test for a taxCategory within Craft Commerce and finding it awkward to do so. I can't see much in the docs, but have managed to put this together:

{% if product.taxCategory | length %}
    {% for taxCategory in product.taxCategory %}
        {# loops through the taxCategory with the first string being the id, #}
        {# the second the name and the third string seems to be the slug #}
        {% if loop.index == 3 and taxCategory == "withVat" %}
            +VAT
        {% endif %}
    {% endfor %}
{% endif %}

But it doesn't seem very elegant. Any suggestions? The docs example probably needs updating, I think, because:

{% for taxCategory in craft.commerce.taxCategories %}
    {{ taxCategory.id }} - {{ taxCategory.name }}
{% endfor %}
{% endif %}

...outputs: "Impossible to access an attribute ("id") on a string variable"

You can simplify your first bit of code by using:

{{ product.taxCategory.name == 'withVat' ? '+VAT' }}

The reason you get the error with your second bit of code is because craft.commerce.taxCategories is only an array of Tax Category names. Only the models of each Tax Category would have properties such as .id and .name


RelatedTo relation - checking matrix block status is enabled I need to search for all commerce variants related to a custom element "Account".

The account element is related to a variant through a matrix field with handle
varientaccountmapping, block handle mapping field handle account

{% set allowedVarients = craft.variants().relatedTo({
    targetElement: accountElement,
    field: 'varientaccountmapping.account'
}).all() %}

works, however it returns results whether the matrix block is enabled or disabled - ignoring the status.

How can I get this to return only results where the matrix block it is related to is enabled?

I faced the same problem in Craft v3.4.10 and have been informed that this is a bug, which has now been fixed and will be shipped in v3.4.12.


Tech Support-Provider for Craft CMS we are a small team in Berlin, Germany, developing editorial websites based on craft cms. A major publishing house is interested in our services. A condition to get contracted is us to provide a certain (t.b.d.) level of tech support – a requirement that we can´t match since we are just a small company. Now my question: does anybody know a tech support-provider in germany to whom we could "outsource" this service?

This is Leslie, I'm the Chief Customer Officer for Craft CMS. I'm not sure I can help, but I'd like to know more. Specifically I'm not sure I can source a dev shop in Germany, but I may be able to get close. We do have Service Partners and we are privately testing a couple of service plans both directly from us and from contracting 3rd party shops that specialize in this type of support. Knowing more details will help us figure out how to develop this type of support from the community and directly from us. Please email me directly at Leslie@Craftcms.com.


Saving related entry in a Matrix block programmaticially I'm trying to add entries to a Matrix block with one field type of 'entry' using the following:

$block = new MatrixBlockModel();
$block->fieldId    = 9;             // Matrix field's ID
$block->ownerId    = $collectionID; // ID of entry the block should be added to
$block->typeId     = 2;             // ID of block type
$block->getContent()->setAttributes(array(
    'contentRss' => array($entry->id)
));

$success = craft()->matrix->saveBlock($block);

The code saves the new block and entry, but when I view the entry it has not linked the entry. I notice in the database tables it has not created an entry in the craft_relations table.

Where am I going wrong? :)

Possibly a duplicate of this one here but hey, here is where I think you are going wrong:

Change this part:

$block->getContent()->setAttributes(array(
  'contentRss' => array($entry->id)
));

To this:

$block->getContent()->contentRss = array($entry->id);


Error accessing entry when title has special characters I came across a weird bug with a title containing a "%" character not converting into a proper slug. So the website editor created the title "Berlenga: a 100% sustainable island" that didn't get turned into a proper slug. It generated the slug exactly as the title. When she went to make changes, Craft threw in a bad request error.
I was able to edit the slug inside the database and she got back access the entry, but I am wondering if there is a way to prevent this from happening again. I'm using the "Slug Equals Title" plugin, which works greatly for localised entries, and I did activate "limitAutoSlugsToAscii". Is there something else I need to do?
Thanks!

I've never used that plugin, but it looks like they do respect Craft's limitAutoSlugsToAscii config setting, which should prevent a % from getting into the slug.
https://github.com/internetztube/craft-slug-equals-title/blob/master/src/SlugEqualsTitle.php#L45-L47
But that setting only applies to new entries and newly created slugs, and I'm guessing you enabled the Craft limitAutoSlugsToAscii config setting after the entry in question was already created.
You should be good going forward, though.


Limit number of sessions per user Is there a way to limit the number of sessions per user? That is, I can be logged into one machine/browsers only once.

It is essential that we limit the number of times a user can be logged in and I can't seem to find a way to do so.

Has anyone dealt with this situation?

This can be done with a plugin.

The plugin would create an 'activity' table that saves the current user's ID and a timestamp of their last known activity.

You can insert the first row by listening to the onLogin event and remove their row by listening to the onLogout.

All subsequent requests, you'd compare the last known activity timestamp to the userSessionDuration config setting to still see if they have an active session.

You'd also be listening to the onBeforeLogin event. If someone tries to login on another computer, you'd see that they already have a row in the database and their last known activity timestamp is still in a valid userSessionDuration window.  Then you'd pass $performAction = false as a property of the event, and that will prevent the login action from occurring.


Where should the .all() be placed in Craft 3 I'm confused, I have ended up with 2 similar queries in a template after converting them from Craft 2.

{% set events = craft.entries()
    .section('events')
    .eventDate('>' ~ now|date('Y-m-d H:i:s'))
    .limit(3)
    .orderby('eventDate')
    .all()
%}
{% for entry in events %}
...
{% endfor %}

and

{% set entries = craft.entries()
    .section('news')
    .orderBy('postDate desc')
    .limit('4')
    .with(['imageGallery'])
%}
{% for entry in entries.all() %}
...
{% endfor %}

Both work without any errors reported but which one is better or correct?

Both approaches are valid. In your first example, you could have moved .all() into the for-loop; and in the second example, you could have moved .all() out of the for-loop, and into the {% set entries = ... %} statement.

Until you call .all(), you are working with an entry query, and after you call .all(), you’re working with an array of the actual entries (the query results).

So which approach is better depends on what else you’re doing in your template.

For example, if you need to output the total number of entries, you could do this:

{% set entryQuery = craft.entries()
    .section('news')
%}

{% for entry in entryQuery.all() %}
    ...
{% endfor %}

Total: {{ entryQuery.count() }}

But it would result in two database queries getting executed – once to get the entries for the for-loop, and a second query to get the total matching entries.

If you know you’re going to need that info, then it would be better to just fetch the entries ahead of time, and check the length of the array instead:

{% set entries = craft.entries()
    .section('news')
    .all()
%}

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

Total: {{ entries|length }}

Regardless of the approach you decide to go with, you might want to make sure you are using semantec variable names. In your two examples you have events (an array of actual event entries) and entries (an entry query).

I would say that if you are not going to call .all() when defining your entries variable, then you might want to rename that to either entryQuery or query, just so it’s easier to remember what sort of variable you’re working with later on in the template.

{% set entryQuery = craft.entries()
    .section('news')
    .orderBy('postDate desc')
    .limit('4')
    .with(['imageGallery'])
%}

{% for entry in entryQuery.all() %}
    ...
{% endfor %}


How to Redirect After Successful Registration Confirmation When a user registers on the front-end of our site, we'd like the default behavior be that when they click on the confirmation link in the email they receive, they are automatically logged in and taken to a "My Account" page that we've created. Is this possible? Right now, they're redirected to the home page, and it doesn't appear that they're logged in.

We updated the postLoginRedirect variable in our config to the My Account page, but that didn't seem to do the trick.

The config settings you're looking for are probably 'activateAccountSuccessPath' and 'autoLoginAfterAccountActivation'.


Output Matrix Block with Element API Plugin Below is my code to output the news entires under the "news" section of my site using the Element API. My question is how do I output the matrix block with a block type of "text" with a field called "blockText"?

https://craftcms.stackexchange.com/qcuestions/13118/how-do-you-use-the-element-api-plugin-to-output-matrix-blocks-for-an-entry

<?php
namespace Craft;

return [
    'endpoints' => [
        'api/entries' => [
            'elementType' => 'Entry',
            'criteria' => ['section' => 'news'],
            'transformer' => function(EntryModel $entry) {
              // Check to see if there are any images
              $featuredImage = $entry->featuredImage->first();
              $bodyBlocks = [];
               foreach ($entry->bodyEnhanced as $block) {

                   switch ($block->type->handle) {
                       case 'text':
                           $bodyBlocks[] = [
                            //'text' => $block->type->attributeConfigs,
                            'content' => $block->type->bodyText
                           ];
                       break;
                   }
               }

                return [
                    'id' => $entry->id,
                    'url' => $entry->url,
                    'postDate' => $entry->postDate,
                    'title' => $entry->title,
                    'excerpt' => !empty($entry->excerpt) ? $entry->excerpt : false,
                    'image' =>   !empty($featuredImage) ? $featuredImage->url : false,
                    'body' => $bodyBlocks,
                ];
            }
        ],
    ],
];

This is the only line that is breaking my JSON. Any help would be greatly appreciated.

'content' => $block->type->bodyText

you have to call

$block->text->getParsedContent()

or another method of RichTextData Model


getting the current user entries from elementapi How do I use the elementapi to get the list of entries for the logged in user?

I've tried a couple of options to no avail, like

'api/v1/user/<userId:\d+>.json' => function($userId) {

            $author = craft()->users->getUserById($userId);

            return [
                'elementType' => 'Entry',
                'criteria' => [
                    'section' => 'jobs',
                    'author' => $author
                ],
...

as an example of one I thought should have worked but it just returns everything.

If you really want the entries for the currently logged in user, having a parameter for userId in your endpoint URL doesn't really make sense.

Not tested, but something like this should work:

'api/v1/user.json' => function () {

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

    if (!$author) {
        HeaderHelper::setHeader(array('status' => 404));
        craft()->end();
    }

    return [
        'elementType' => ElementType::Entry,
        'criteria' => [
            'section' => 'jobs',
            'authorId' => $author->id,
        ],
    ];
}

Notice that the above example endpoint would be available at http://example.com/api/v1/user.json, where your example code would create an endpoint with a required userId parameter, i.e. http://example.com/api/v1/user/12345.json.

Also notice that the currently logged in user is pulled via the UserSessionService (craft()->userSession).

Finally, note that you should use 'authorId' => $author->id in your criteria – not 'author' => $author.


Merge a structure and a single section That is written so inefficently:

{% set indexNavi = craft.entries.section('pageContent').level(1).all() %}
{% set bookingLink = craft.entries.section('booking').all() %}

  {% for item in indexNavi %}

      {{ item.title }}

  {% endfor %}
  {% for item in bookingLink %}

      {{ item.title }}

  {% endfor %}

Is there a better way?

I wanted to creat a single variable:

{% set merger = craft.entries.section(['pageContent','booking']).level(1).all() %}

But this only outputs the pageContent. I guess because booking is a single section and therefore has no level?

But this only outputs the pageContent. I guess because booking is a single section and therefore has no level?

In short, yes. It's not super clean but you could fetch everything without worrying about level:

{% set merger = craft.entries.section(['pageContent','booking']).all() %}

Then check for level in your loop ('normal' entries return null as a level)

{% for item in merger %}
    {% if item.level is null or item.level == 1 %}
        {{ item.title }}<br>
    {% endif %}
{% endfor %}


Get all Variant SKUs using getCriteria I want to create an array of all SKUs on Craft Commerce. The end goal is to create a plugin that only applies Sales to certain variants. It does this by  checking the Sale's description for any mention of SKUs and comparing this against the list of all available SKUs.

I thought this would do the trick…

$allvariants = craft()->elements->getCriteria('Commerce_Variant');
$allskus = $allvariants -> sku;

But it doesn't appear to work. The full code of the plugin is…

craft()->on('commerce_sales.onBeforeMatchProductAndSale', function($event){
    $sale = $event->params['sale'];

    $allvariants = craft()->elements->getCriteria('Commerce_Variant');
    $allskus = $allvariants -> sku;

    if (stripos($sale->description, 'only') === false) {
       return; /* do nothing, and let the sale match as it normally would, because the sale does not have 'only' in the description. */
    } else {
        if (stripos($sale->description, $allskus) === false) {
            $event->performAction = false; /* since this SKU is not in the description string, then don't apply this discount */
        }
    }
});`

(Full credit to @luke-holder who wrote the plugin to do this for Discounts)

This should grab all of the variant's SKUs like you're looking for:

$criteria = craft()->elements->getCriteria('Commerce_Variant');
$allVariants = $criteria->find();
$allSkus = array();

foreach ($allVariants as $variant)
{
    $allSkus[] = $variant->sku;
}


Craft Commerce cart product as unique product with different notes Our client wants a specific option built in Craft Commerce. I guess is possible, but don't know how? Maybe you can help me out?

A customer selects a box: for example "giftbox custom 4" (priced $ 15). After selecting the box. The customer can pick 4 different tastes of chocolate cookies (e.g. 2 brownies, 2 white choco. etc). After picking the cookies, the client can add this to the cart.

My initial thought is to use a note fields for this, storing all the cookie data. But how can I make sure that each "giftbox custom 4" is a unique line item? Now Craft is adding all the "giftbox custom 4" together.

This is what I want to create:

2x Giftbox custom 4
Containing: 2 caramel, 2 brownies

1x Giftbox custom 4
Containing: 1 white choco, 3 caramel

2x Giftbox custom 4
Containing: 2 dark choco, 1 caramel, 1 fruit

In total there a more than 14 different giftbox sizes.
Giftbox custom 2, Giftbox custom 4, Giftbox custom 6, etc.
And you can choose from > 30 different cookies

@Luke Holder:
When I am using line-item options: For example: Giftbox 4 -> with options ABCD.

After submitting: they appear in my basket. Perfect, and i can change the quantity of Giftbox 4 -> with options ABCD .

But when I go back to the shop and add an extra giftbox to the cart: Giftbox 4 -> with options EFGH. Giftbox 4 -> with options ABCD are removed from my cart.

So i want the "Giftbox 4" products separated:
1x Giftbox 4 -> with options ABCD .
1x Giftbox 4 -> with options EFGH

Line item options are built in and are designed exactly for this use-case:

https://docs.craftcms.com/commerce/v2/adding-to-and-updating-the-cart.html#line-item-options-and-notes


Can I set a JS variable to a Twig output tag? This came out of a previous question

I need to set a variable of a tag group that I can reference in jquery for use with a plugin.

I'm declaring this variable in a  tag so my included js files can access it.

Here's what I want to do:

<script type="text/javascript">
    var gameTags = {{ craft.tags.group('gameTags') }};
</script>

Javascript clearly doesn't like that syntax, so I tried setting the variable with Twig and calling that:

{% set gameTags = craft.tags.group('gameTags') %}

<script type="text/javascript">
   var gameTags = gameTags;
</script>

JS considered that undefined.

I'm probably going about this the wrong way. I'm relatively new to javascript and very new to craft, so I'm a little stumped.

In your first example, you are outputting an ElementCriteriaModel. That is a query for tags rather than the tags themselves. It doesn't output anything usable by JS You're almost doing the same in the second example, except that your reference to gameTags in the JS is just referencing itself rather than any Twig output.

What you want to do is to query the tags and output in the way that JS can use. Something like this:

<script type="text/javascript">
    var gameTags = [{% for tag in craft.tags.group('gameTags') %}"{{ tag.title }}",{%endfor %}];
</script>

That should output a JS array of strings with each string being a tag. Something like below.

<script type="text/javascript">
    var gameTags = ["action","adventure","platform","rpg","sports",];
</script>

If you're a stickler for commas in arrays, there's ways to not output that after the last tag.


Unknown error occurred after install on MAMP Successfully installed Craft on MAMP but whenever I load the dashboard, I get the error message "Unknown error occurred". The message clears after a few seconds. The CMS appears to be functioning correctly except when I create a Section, it only allows me to select Single as a type.

Can anyone shed light on this error?

Chances are your craft/config folder isn't writable, but you can see the underlying error in your craft/config/storage/runtime/logs files.  Just search for [error] or [warning].


Display all the data in one entry How can I display all entries in one page? I have a jobs Channel and inside of it there are 5 entries:

Title | Company  | Email
-------------------------
title1  company1   email1
title2  company2   email2
title3  company3   email3
title4  company4   email4
title5  company5   email5

I want it to be display in one page

Use craft.entries:

{% for job in craft.entries.section('jobs') %}

    Title: {{ job.title }}

    Company: {{ job.company }}

    Email: {{ job.email }}

{% endfor %}


Update entry programatically Im trying to update an entry field programatically. I can load an entry by any field with a function i created

    /**
 * Returns an element by any attribute.
 *
 * @param int $elementId
 * @param string|null $type
 * @param string|null $localeId
 * @param string $localeId
 * @return BaseElementModel|null
 */
public function getElementByField($elementId, $elementType = null, $localeId = null, $field)
{
    if (!$elementId)
    {
        return null;
    }

    if (!$elementType)
    {
        $elementType = craft()->elements->getElementTypeById($elementId);

        if (!$elementType)
        {
            return null;
        }
    }

    $criteria = craft()->elements->getCriteria($elementType);
    $criteria->$field = $elementId;
    $criteria->locale = $localeId;
    $criteria->status = null;
    $criteria->localeEnabled = null;
    return $criteria->first();
}

but i cant save the new values of the fields i want.
This is my save code:

$entry = $this->getElementByField("3081001100390", ElementType::Entry, null, "variantSku");
    $entry->variantSku = 1;
    craft()->entries->saveEntry($entry);

And the error is  Property "Craft\EntryModel.variantSku" is not defined. I know the variantSku exists since im loading a product by that attribute and i can see it when dumping $entry->variantSku.

Complete error here: https://www.diigo.com/item/image/4u33k/972k

Did anyone achieved this?

After some research, i found a way to achieve this. Here is my full controller:

<?php
  namespace Craft;

  class Module_ControlController extends BaseController {
   protected $allowAnonymous = true;
public function actionChangeStock()
{
    $entry = $this->getElementByField("3081001100390", ElementType::Entry, null, "variantSku");
    $entry->enabled = false;
    $entry->getContent()->setAttributes(array(
        'variantSku' => "Hello my friend!",
        'variantStock'  => "3"
    ));
    $success = craft()->entries->saveEntry($entry);
    die(var_dump($success));
}

/**
 * Returns an element by any attribute.
 *
 * @param int $elementId
 * @param string|null $type
 * @param string|null $localeId
 * @return BaseElementModel|null
 */
public function getElementByField($elementId, $elementType = null, $localeId = null, $field)
{
    if (!$elementId)
    {
        return null;
    }

    if (!$elementType)
    {
        $elementType = craft()->elements->getElementTypeById($elementId);

        if (!$elementType)
        {
            return null;
        }
    }

    $criteria = craft()->elements->getCriteria($elementType);
    $criteria->$field = $elementId;
    $criteria->locale = $localeId;
    $criteria->status = null;
    $criteria->localeEnabled = null;
    return $criteria->first();
}}


Craft 3 icons not found in craftcms/cms/src/icons Craft 3 version 3.0.4

When logging into the admin panel on Craft3 for some reason I'm getting a Yii2 PHP Warning for missing icons.

Error message:

PHP Warning – yii\base\ErrorException
file_get_contents(<pathtocraft>/craft/vendor/craftcms/cms/src/icons/c.svg): failed to open stream: No such file or directory

For some reason this icons folder is not being generated when installing craft3 via composer. This is currently happening on craftcms/cms/src/web/Application.php at line 363 where it tries to load the Yii logo.

Gitignore had a line for Icon? which was causing the icon folder to not show up in git commit.


Redactor settings: stripping out classes from table I have a site (Craft 2.5.2754) and am trying to add a class to a table within Redactor. Even if I disable Clean up HTML and Purify HTML (which would rather not do) the style is getting stripped out on save.

I've had a look through the config/settings for Redactor and there is an 'allowedAttr' setting for earlier versions but seems to have been removed in Redactor II.

Any suggestions on stopping the class being stripped out, preferably without having to disable Clean up HTML and/or Purify HTML?

If all your tables should use the same class or classes, you could use my Retcon plugin to add the classname(s) in Twig:

{{ entry.body|retconAttr('table', {class: 'someclassname'}) }}

If different tables need different classes, this isn't a solution, though.


Assets S3 Cache Duration and CP Thumbnails What does everyone consider a sensible cache duration to use when using Assets with S3/Cloudfront? Is 3 hours sensible or should it be longer?
Secondly, does this have any impact on the assets being displayed within Craft? Listing Asset directories takes a while due to my connection speed I'm sure but aren't these assets cached locally?

With the correct cache busting, files can remained cached for as long as possible. Craft handles a lot of this for you.
I typically cache items for a year but do take caution to ensure every reference to assets within the site has a cache busting string on it. It's important to note that Cloudfront needs to be setup to use these query strings.
On the frontend, Craft appends an mtime attribute to the query string. If you ever replace an asset, the mtime is updated and subsequently a new cache is created.
Within the Craft CP, thumbnails of your remote images are generated rather than serving them from a CloudFront URL, generally there are no worries with caching here as Craft handles that.
Volumes with an expiry set will automatically load the mtime parameter when fetching the URL from Craft. Alternatively, you can implement your own cache busting with the url() function shown here.


Redactor - doesn't generate unordered list I'm using Redactor v2.8.5. it doesn't render an unordered list in HTML? How do I fix it?

Redactor is perfectly capable of rendering an unordered list, so perhaps your question is a little unclear.
If you mean that there's no formatting button to format an unordered list, check that you're using an appropriate redactor config which allows the use of 'unorderedlist' in your field definition:

More instructions about how to configure Redactor in Craft can be found at https://github.com/craftcms/redactor


Check if other locale exists I have just one page on my site with only one language:

Every other page has two languages.

I want to disable certain things on that page (like language switchers). How do I determine this?

This just returns all avalable languages no matter what languages are activated:

{% set otherLocales = craft.i18n.getSiteLocaleIds() %}
  {% for locale in otherLocales %}
    {{ locale }}
  {% endfor %}

I tried to do it with status:

{% set otherLocales = craft.i18n.getSiteLocaleIds().status('live') %}

but that returns an error as well. I tried status because it's labeled that way in the cp.

This returns the opposite language although the other locale doesn't exist on this page.

{% set otherLocales = craft.i18n.getSiteLocaleIds()|without(craft.locale) %}
{% for locale in otherLocales %}
  {{ locale }}
{% endfor %}

Any other ideas?

You can query for the same entry in another locale by explicitly setting the locale parameter.

{% set de = craft.entries.id(entry.id).locale('de').first() %}
{% set en = craft.entries.id(entry.id).locale('en').first() %}

German:  {{ de ? 'OK' : 'nope' }}
English: {{ en ? 'OK' : 'nope' }}


Display an entry's level 1 categories only if the entry is not related to any of that category's children I'm struggling with how to do this in Twig... I feel like it would be easier in a full programming language.

If an entry's categories look like this:

A
    - A1
    - A2
B
C
    - C1

I need to output a list like this:

A > A1
A > A2
B
C > C1

I can't seem to figure out how to avoid printing all the top-level categories on their own. This is what I've managed to output:

A
A > A1
A > A2
B
C
C > C1

I have a feeling I'm going to feel dumb when someone answers this, but any help is appreciated.

Edit: I've found a solution.

Before listing the categories, I run a for loop on just the entry's level 2 categories and collect their parents' IDs using an empty array and the merge filter. Then, when listing the categories, I put a conditional so that level 1 categories are not listed if their ID is in the array.

It seems an awkward way to do it, and I'm still interested in better solutions.

Collecting all of the categories' ancestors is probably the way to go in that case. So the solution you already posted within your question is more or less the same as I was about to post.

Instead of having a conditional in the output loop, you could also prepare an array of your bottom level category models using Craft's without filter (I always try to separate output from query / logic blocks in my templates).

This works with any number of category levels.

{% set allCategories = craft.categories.relatedTo(entry) %}

{% set ancestorCatIds = [] %}
{% for category in allCategories %}
    {% set ancestorCatIds = ancestorCatIds|merge(category.ancestors.ids()) %}
{% endfor %}

{% set bottomCatIds = allCategories.ids()|without(ancestorCatIds) %}
{% set bottomCategories = craft.categories.id(bottomCatIds) %}

    {% for category in bottomCategories %}

{{ macros.catBreadcrumbs(category) }}

    {% endfor %}

I made a macro that outputs the category breadcrumbs, to have even less logic in the output block.

{% macro catBreadcrumbs(category) %}
    {% set ancestorCategories = category.ancestors.find() %}
    {% set ancestorCategories = ancestorCategories|merge([category]) %}
    {{ ancestorCategories|join(' > ') }}
{% endmacro %}


Can't update Craft 3, permissions issue Upon running the update tool in the Craft CMS, I get this error.

Error: file_put_contents(path/to/file/composer.json): failed to open stream: Permission denied

What permissions are causing this error? Is it simply the case of changing the perms on the composer.json file? If so, what should they be?

Thanks!

Here are the required Craft 3 file permissions: https://docs.craftcms.com/v3/installation.html#step-2-set-the-file-permissions


$PATH variable location for backups Folks:

This is surely something real basic. I have not been able to create a database backup manually or when updating.

Mysqldump is installed.
I know the location of mysqldump (/usr/local/bin/mysqldump).
The log doesn't appear to reveal anything.

I have modified the .env file using the info from the MAMP database backup article (substituting the path for the MAMP one in the article). No joy.

According to the config docs, I need to change the PATH variable.

The question is: how do I do this? Specifically:

Where is this change made? Which file? general.php? .env? Elsewhere?
What is the syntax to make this work?

It's not just editing the .env file; you also need to modify the config to make use of those options; which is part two of that article you linked to.
You could also try adding a PATH variable to your .env which includes "/usr/local/bin" in it.
Update:
The .env won't override an existing environment var by default. In most linux server setups this isn't a problem because the "www-data" or "apache" user doesn't have that set by default.
For MAMP, local dev or vagrant development; that path is likely set. If you want your .env settings to overwrite existing settings; change the web/index.php file to use Dotenv\Dotenv::create(CRAFT_BASE_PATH)->overload();
instead of
Dotenv\Dotenv::create(CRAFT_BASE_PATH)->load();


RedactorStyles Plugin Not Working I'm having trouble getting the redactorStyles plugin to work. I am running Craft 2.3.2627

Redactor Styles v. 0.2

Here's the json in the json field:

 {
"btnName":"Drop Cap",
"className":"redactorDropCap",
"spanClass":"dropCap",
"forceBlock": "-1"
}

I have an external stylesheet, the field is set to: /assets/css/redactorStyles.css

I am not getting any errors in the CP but I also don't get the styles nor do I see the want icon for the plugin dropdown.

Here's the content from the redactor config file:

{
buttons: ['html','formatting','bold','italic','unorderedlist','orderedlist','link','image','video'],
plugins: ['fullscreen','video','styles'],
toolbarFixed: true,
stylesJson: RedactorStyles.stylesJson

}

Can anyone tell me if I am doing something wrong here or if there is a bigger issue? I'm new to Craft.

Thanks,

Brian

Craft 2.3 upgraded Redactor to version 10, which comes with a completely new API for plugins. This broke RedactorStyles which relied on the old API.

I've updated the plugin now, so downloading version 0.3 should make it work with Craft 2.3. Beware that the plugin isn't 100% backwards compatible, due to changes in Redactor and its API, so read the docs.


How do I set where the user is sent from a custom login form? Is there a way to send the user to a different page than the control panel when logging in from a custom login form?

I've tried..

<form method="post" action="" accept-charset="UTF-8">
    <input type="hidden" name="action" value="users/login">
    <input type="hidden" name="redirect" value="apply">

I've also tried setting the returnUrl session in a login event within a plugin. There's a bit left to do in the init function but you get the idea. Currently the code should redirect all logins.

public function init()
{
    craft()->on('userSession.onLogin', function(Event $event) {
        // load the user info and determine user group
        // if part of applicant user group
        // load any existing unfinished applications
        // set a session for the unfinished application
        // redirect to /apply which should load the unfinished application
        craft()->session['returnUrl'] = "/apply";
    });
}

You can set a variable in your craft/config/general.php. Here is the option taken from the default config file which is located here craft/app/etc/config/defaults/general.php:

Updated:

/**
 * The path that users should be redirected to after logging in from the front-end site.
 *
 * This setting will also come into effect if the user visits the Login page (as specified by the loginPath config
 * setting) when they are already logged in.
 */
'postLoginRedirect' => '',

From that page you can also easily route them to another page based on conditionals in twig using {% if something %}{% redirect url %}{% endif %}.

And although I haven't tried this personally, it looks like (based on this answer) you can redirect from within your plugin using the following (perhaps only from a controller however):

$this->redirect('/apply');

I also see in UserSessionService.php line 371 the following which should also work:

$url = UrlHelper::getUrl(craft()->config->getLoginPath());
craft()->request->redirect($url);


Craft 2: get default user group from user settings In Craft 2, I know I can get general config settings.

How can I get the current Default User Group (set in Settings > User Settings) for use in my templates?

You can do this via a small plugin that provides you with a template variable. I've made you a working example here with usage example.

It's a main plugin class with the basics then a variable class that fetches the group id from your settings and retrieve the handle associated to that id.

I'm sure there are other ways to do this but that's one. Download, change... Make it yours :)


Turning off a site in multi-site/multi-environment config Given a multi site setup (domain1.com, domain2.com) that also uses multiple environments (dev, staging, production) - how would one configure one of the sites to be turned off in the production environment?

I'm currently trying the following.

return [
    // Global settings
    '*' => [
        // removed for clarity
    ],

    'dev' => [
        'devMode' => true,
        'isSystemLive' => [
            'domain1.com' => true,
            'domain2.com' => false
        ]
    ],

    // Staging environment settings
    'staging' => [
        'devMode' => true,
        'isSystemLive' => [
            'domain1.com' => true,
            'domain2.com' => false
        ]
    ],

    // Production environment settings
    'production' => [
        'devMode' => false,
        'isSystemLive' => [
            'domain1.com' => true,
            'domain2.com' => false
        ]
    ]
];

Which I would have expected to have domain2.com turned off but domain1.com remains on. However, both sites are on.

I have also tried rearranging the config using the following structure (stripped back for brevity)

return [
    'domain1.com' => [
        '*' => [
            // default for domain1
        ],

        'dev' => [
            'isSystemLive' => true
        ],

        'staging' => [
            'isSystemLive' => true
        ],

        'production' => [
            'isSystemLive' => true
        ]
    ],

    'domain2.com' => [
        '*' => [
            // default for domain2
        ],

        'dev' => [
            'isSystemLive' => false
        ],

        'staging' => [
            'isSystemLive' => false
        ],

        'production' => [
            'isSystemLive' => false
        ]
    ],
]

But this also doesn't work.

So how should I specify different multi-environment configs for each site?

The isSystemLive config setting isn't multi-site aware. It sets the entire Craft installation on or off, rather than per site, so you'll need to find a different method to disable domain2.com on the production server.

Untested, but you could try to set the baseUrl for domain2.com to an empty string on production and see if that works.


Another index.php?p= problem I can't get rid of that pesky index.php?p= from my urls.

http://mysite.com/index.php?p=about/people

If I manually remove index.php?p= e.g. http://mysite.com/about/people it works, but then goes back to adding the index.php?p= as soon as I navigate away.

I've tried adding 'usePathInfo' => true, and 'omitScriptNameInUrls' => true, to general.php

PathInfo works, http://mysite.com/index.php/testPathInfo = 'success'

When I add garbage to htaccess I get server error, so htaccess works.

And I have another site with a very similar build on the same server that's working fine.

Is there anything else I can look at?

Have you seen this on the Craft site: http://buildwithcraft.com/help/why-index.php ?


Checking if a field contains information I have read docs on Craft CMS site and Googled some related articles but can't seem to get my head around checking for conditions for a field.

For example, if I have a 'Fruit' field drop-down:
Apple
Banana
Orange

Should I add a 4th value with 'null'? So in my template, I want to display the field if it is Apple, Banana or Orange but not if null.

I get confused when to to use '|length'  or 'is empty' or 'is not' conditionals.

In another example, I tried to setup a drop-down for a field called 'Rating'
The values were 1, 2, 3, 4, 5
I couldn't get the conditional to work, so I thought to make the field a number type. And then I tried a conditional 'rating > 0' but also didn't succeed.

If you want a Dropdown field with the option to not select a value (or to clear out the current selection), you can just add an option (typically the first) with an empty value column. If the empty value/option is selected, the following conditional will evaluate to false, and if any other, non-empty value is selected it will evaluate to true:

{% if entry.dropdownFieldHandle %}
    I have a value: {{ entry.dropdownFieldHandle }}
{% else %}
    I have no value in the dropdown
{% endif %}

Note that for Dropdown fields its also possible to leave the label column empty, or to use something like "Pick a value..." as a placeholder.

If you use null instead of an empty value, the above conditional will always evaluate to true, because Twig will treat the value null as a string (i.e. "null"), not an actual NULL value.

As for the |length filter, since your question brings it up – the only thing |length does is to return the length of whatever variable its suffixed to. For an iterable object (like an array or a relational field like Assets or Entries) the length will be the amount of elements in that object (for instance, the number of Assets selected in an Assets field); for strings and numbers it will be the number of characters (meaning "foo"|length and 123|length will both return 3).

The reason |length is often used in conditionals, is that 0 is considered a "falsey" value, and any length larger than 0 is considered a "truthy" value. In other words, a conditional like {% if ""|length %} will be evaluated to false, because "" is an empty string and hence will return 0 characters, while a conditional like {% if "foo"|length %} will evaluate to true because the length filter will return 3 characters and 3 is a "truthy" value.

That being said, the reason why the |length filter isn't neccessary in the above example conditional is simply because Twig will automatically evaluate conditionals testing empty strings to false. So while {% if entry.dropdownFieldHandle|length %} would also work (i.e. evaluate to false for empty values), it isn't actually neccessary.

Finally, is not (or simply not) is simply Twig-speak for the != operator, i.e. is not equal to. So if you wanted to reverse the conditional above, here's how that would look:

{% if not entry.dropdownFieldHandle %}
    I have no value in the dropdown
{% else %}
    I have a value: {{ entry.dropdownFieldHandle }}
{% endif %}


What would be the best way to select and display featured entries? What would be the best way to select and display featured entries? For example, if I want to choose at least 3 entries to feature in a sidebar apart from the main content?

It always depends on your needs, so there is not really a best way to do feature entries, at least if you don't give more specific info on what your exact situation is.

To have a nice overview of which entries are featured, you could add a new section (structure or channel), with an entries field to collect the entries you want to be featured.

Another idea would be to collect the feature entries in a global set using matrix. You need just a single block type, again with an entries field to make the relations.

A Matrix field or a structure section enables you to (optionally) re-order the entries to your liking.


Options not rendering on Sprout Reports report My Sprout Report I just set up is not rendering the "options" template.

The results and options template both exists, and have been copied from the examples directory that came with Sprout Forms. This options template is rendered on the build in "Users and User Groups" report - but not on mine.

The only difference is my report has a data source of "Custom Twig Template" as opposed to "Users" - but that shouldn't matter.

The docs and the built in examples aren't shedding any light on the situation. Thanks.

It looks like the issue here is that the Results Template and Options Template include the file extension .twig. Removing the extension .twig should get things working:

_reports/dealer-export/options

I've added it to our list to improve this functionality in the future. We should be able to strip off the extension behind the scenes or do what we need to do with it regardless of whether you add it or not. Sprout Reports does loop through and check for all supported extension types for your site on the back end when no extension is provided.


Front End Editing with Entry From I need to allow store managers to edit their store. I'm most of the way there and have the title field and a couple of other plain text fields set up. However there isn't any documentation available for other field types including:

categories
assets
lightswitch
relationship (entries)
Store hours https://github.com/craftcms/store-hours/

The documentation is only includes examples for input and textarea fieldtypes and not any other first party custom fieldtype .
What is the best approach to being able to edit these field types?

There is actually quite a bit of documentation on templating for various field types. Go to the Fields section of the online docs and then select the field you are interested in, e.g. you will find a very comprehensive templating guide for assets here


How can I use a session consistently in a service and variable? I’m working on a simple cart and trying to utilize the user session id to keep track of things.

The session getting saved to the database doesn't match the session that’s being displayed in templates. I have a template variable set-up to output the session on the front end for comparison.

There’s quite a bit of code with a plugin so I’ll include what’s most relevant.

I have a service setup that included methods for saving an item and loading a session through a variable. In the service constructor the session is set like so:

class EyeCart_CartService extends BaseApplicationComponent
    {
    private $_cartSession;

    public function __construct()
    {
        $session = new  HttpSessionService;
        $session->open();
        $this->_cartSession =  $session->sessionID;
    }
    etc.

I then use _cartSession in the saveItem method. This works fine.

public function saveItem(EyeCart_CartModel $item)
{
    ….
    // Set the cart record attributes
    $cartRecord->session = $this->_cartSession;  // the session saves as bakg59bu9lmbbs50s8meg5jk71
    $cartRecord->itemId = $item->itemId;
    etc…

In the service I also have a cartSession method for outputting the current session in the template via variables (for testing).

public function cartSession()
{
   return $this->_cartSession;
}

This returns a different value than is being saved in the database (9m9g3msjo3v9f8ke7gf4b3qfv0). I tried including the cart variable on different templates and it displays consistently across page states just not when saving to the db.

Any advice?

I suspect you're getting different session IDs because you're creating a new instance of HttpSessionService (which ultimately is a wrapper for PHP's session handling).

What you should be doing is using Craft's existing session off of craft()->httpSession and grab the existing PHP session ID with craft()->httpSession->getSessionID().

No need to call craft()->httpSession->open(), because Craft will automatically start the session as soon as the HttpSessionService gets loaded.


Cannot get category.title to show up {% set slug = craft.request.getParam('s') %}

{% if slug | length %}
    {% set category = craft.categories.slug(slug) %}
    {% set faqs = craft.entries.section('faq').order('title').limit(null) %}

{{ category.title }}

        {% for entry in faqs.relatedTo(category) %}
            {% if entry.level >1 %}

{{ entry.title }}

            {% endif %}
        {% endfor %}

{% else %}

 No matching results found

{% endif %}

In the code above, I cannot get {{ category.title }} to display. It is empty. If I put {{ category.slug }} instead, it shows the correct value. The other items in unordered list are displaying perfectly. I am confused as to why the title is not showing

Try changing this:

{% set category = craft.categories.slug(slug) %}

to

{% set category = craft.categories.slug(slug).first() %}


Element API: Get Entries Related to Category with Query Parameter I'm using the Element API Plugin to create an API, with which I want to get entries related to one category, but dynamically with the category set in the Url.
What I have so far in the config/element-api.php:
<?php

use craft\elements\Entry;
use craft\helpers\UrlHelper;

return [
  'endpoints' => [
    'api/projects.json' => function() {
      $projectCategory = \Craft::$app->request->getQueryParam('projectCategory');

      // dump for test purpose
      var_dump($projectCategory);

      return [
        'elementType' => Entry::class,
        'criteria' => [
          'section' => 'projects',
          'relatedTo' => "{$projectCategory}",
        ],
        'elementsPerPage' => 2,
        'transformer' => function(Entry $entry) {
          return [
            'title' => $entry->title,
            'url' => $entry->url,
            'jsonUrl' => UrlHelper::url("projects/{$entry->id}.json"),
            'thumbnail' => $entry->projectThumbnail,
            'description' => $entry->projectDescription,
            'credits' => $entry->projectCredits,
          ];
        },
      ];
    },
  ],
];

When I go to http://domain.test/api/projects.json?projectCategory=category, I get the right value dumped, but the relatedTo doesn't seem to work. I get zero entries, although there are some related to a specific category.
Am I doing something wrong here?

Are you passing the projectCategory parameter as a string or ID? In any case, the relatedTo parameter will receive a string in your code, which might trip up the query. If the parameter is passed as an ID, passing it as an integer instead of a string might be enough:
'relatedTo' => (int) $projectCategory,

However, it might be cleaner to get the actual category element based on the ID and pass that to relatedTo. This will also allow you to check if the specified category actually exists (and optionally return an HTTP error for invalid parameters).
$criteria = ['section' => 'projects'];
$projectCategory = \Craft::$app->request->getQueryParam('projectCategory');
// this assumes the category is passed as an ID
$category = \craft\elements\Category::find()->id((int) $projectCategory)->one();
if ($category) {
    $criteria['relatedTo'] = $category;
}


Multilingual MAMP port number siteUrl issue I have my local dev setting up using MAMP on port 8888

  'mydomain.dev:8888' => array(
    // ...
    'environmentVariables' => array(
        'basePath' => '/Users/mypath/SiteCode/mydomain/dev/',
        'baseUrl'  => '//mydomain.dev:8888/',
        'logDumpMethod' => 'print_r'
    ),
    'logDumpMethod' => 'print_r',
    'devMode' => true,
    'useCompressedJs' => true,
    'siteUrl' => array(
        'en' =>  'http://mydomain.dev:8888/en/',
        'ar' =>  'http://mydomain.dev:8888/ar/',
        'zh' =>  'http://mydomain.dev:8888/zh/',
        'fil' => 'http://mydomain.dev:8888/fil/',
        'fr' =>  'http://mydomain.dev:8888/fr/',
        'hi' =>  'http://mydomain.dev:8888/hi/',
        'id' =>  'http://mydomain.dev:8888/id/',
        'ru' =>  'http://mydomain.dev:8888/ru/',
        'es' =>  'http://mydomain.dev:8888/es/',
        'tr' =>  'http://mydomain.dev:8888/tr/',
        'uk' =>  'http://mydomain.dev:8888/uk/',
        'ur' =>  'http://mydomain.dev:8888/ur/'
    ),

),

In the admin general settings I am using {siteUrl} for siteUrl settings. This gets read from the local dev config array as above.

However the admin link on the site in the control panel top left gets the url wrong.
Instead of http://mydomain.dev:8888 it shows
http://mydomain.dev:8888/admin/%7BsiteUrl%7D/

I have other local craft sites setup with port number 8888 O.K. The only difference here is that the siteUrl is specified in a multilingual array.

Is this a bug or am I missing something?

Pretty sure the issue is that a port number won't work as part of the key in a multi-environment config.  Because unless you explicitly set CRAFT_ENVIRONMENT to use it, Craft is just going to use $_SERVER['SERVER_NAME'], which doesn't include the :port (that's at $_SERVER['SERVER_PORT']).

There's another thread here with some solutions/workarounds.


How to create plugin pivot table entries? I have a record for an entity my plugin needs and that may be related to many Entries, so I have a pivot table, much like Craft's usergroups_user table.

I'm creating and updating my table fine and I'm not looking at my pivot table. I notice the the user group approach is to delete any entries before creating new ones:

public function assignUserToGroups($userId, $groupIds = null)
{
    craft()->db->createCommand()
        ->delete('usergroups_users', array('userId' => $userId));

    if ($groupIds)
    {
        if (!is_array($groupIds))
        {
            $groupIds = array($groupIds);
        }

        foreach ($groupIds as $groupId)
        {
            $values[] = array($groupId, $userId);
        }

        craft()->db->createCommand()->insertAll('usergroups_users', array('groupId', 'userId'), $values);
    }

    return true;
}

I take it this is the best way to handle pivot tables and there is no 'sync' functionality similar to that found on Laravel's Eloquent class http://laravel.com/docs/5.1/eloquent-relationships?

There isn't an explicit sync command, but Yii does support MANY_MANY relationships through Active Record and will keep the data in the join table up-to-update automatically if you stick purely with Active Record.


How can I use the entry UID in the entry URI The entries in my Craft app need a unique ‘non-guessable’ URL, so I figured I could use the UID in the URI of the entry.

So in the section, where I need to provide the URI format I entered "section-name/{uid}".

But this is giving me issues, since when I initially save an entry, the URI is "section-name". I think this is because the UID is not available on creation of the URI.

If I save the element for the second time, my problem is solved and the correct URI is generated.

Is there a way to prevent this issue from happening?

I already thought about creating a route, but that means that I need to generate the URI myself in every template, and this is prone to error and not future proof if we would like to change the URI format.

I also thought about creating a module which saves the entry for a second time when a new entry is saved for that section, but I can't find a way to create the correct event-listener.

Does anyone have a better solution or can help me with the event listener in a module?

I think this can be a starting solution. It rewrite slug of Entry after the Entry is saved to database. The URI is constructed from it. You can try it in any plugin, only register the EVENT_AFTER_SAVE_ELEMENT in init() function of Plugin.

use craft\events\ElementEvent;
use craft\services\Elements;

Event::on(
    Elements::class,
    Elements::EVENT_AFTER_SAVE_ELEMENT,
    function (ElementEvent $event){
        //identify the right Entry for example test sectionId, typeId, authorId
        if ($event->element instanceof craft\elements\Entry) {
            $entry = $event->element;
            //only newly created
            if($event->isNew){
                $entry->slug = $entry->uid;
                Craft::$app->elements->saveElement($entry);
            }
        }
    }
);


Possible to have a single entry page with multilingual slugs and only one index.html? How can I be able to have a single section page (so that clients can't create another one of this) that only needs 1 index.html template across different languages AND be accessible through following different slugs:

x.dev/muziektoerisme
x.dev/fr/tourisme-musical/
x.dev/en/music-tourism/

I currently have a setup similar to this one: Add home page to a structure?, which is a structure section 'Pages' with my custom page entry type 'musictourism' under 'craft/templates/_pages/_types/' (so 'musictourism.html' sits in this folder)
This works great, except for the fact that users are able to recreate a page of this entry type, which I don't want.

Does my question make any sense? Or am I missing something fundamental here? :) I'm new to Craft by the way.

Thanks in advance!

What you're asking for is fine. Create a subfolder within your public directory for each locale with it's own index.php and define the new path to craft/ and the locale. For example, within public_html/fr/index.php you might have:

// Path to your craft/ folder
$craftPath = '../../craft';

// Tell Craft to serve the FRENCH content
define('CRAFT_LOCALE', 'fr');

With the single, you set the slug yourself within the section's settings (one slug for each locale that section is available to).


Dealing with missing images How Craft reacts to missing images is one of the very few places where I find Craft less than ideal.

TL:DR;

Is there a way to make missing images not become a fatal error?
How do you find elements that are referencing the missing image?

Long version:

There are a number of ways images can be missing, for example:

Our workflow involves developing locally, then putting up to staging for clients to add content. Sometimes we need to then do more local development, local and stage both share the same database... but not images.

An image is simply corrupt, due to transfer or disk failure (it happens)
A filesystem is reverted to a previous state but the database is not
A live server dies and a project is restored to a new machine from SVN/GIT, but the assets are not in version control and therefore not available
Getting hold of the images on local isn't possible temporarily because you're working on a restricted internet connection; like on a plane.

Any of these result in instances of 'blahblah.jpg could not be found' in Dev mode or Internal Server Error in production. Sometimes those images actually get lost; they just don't exist any more; but they're in the database. So...

How do you find what element is referencing these lost files? Besides manually trawling through entries, related entries, etc? Crafts error gives no useful information about that, and rebuilding asset indexes doesn't seem to make Craft aware that the image isn't available anymore.

And...

Is there an option to just ignore these types of error - it's not helpful in production to have a whole page 'internal server error' just because a single image referenced on the page is missing from the file system for whatever reason. A missing image is not a throw-the-baby-out-with-the-bathwater problem.

I do all images through a macro, that substitutes in our logo if an image happens to be missing.

{% macro imageTransform(image, transform, caption, extraHTML) %}
  {# Fallback to our logo if the image is null... #}
  {% if not image|length %}
    {% set image = craft.assets.id('84').first() %}
  {% endif %}
  <img src="{{ image.getUrl( transform ) }}" width="{{ image.getWidth( transform ) }}" height="{{ image.getHeight( transform ) }}" title="{{ caption|default('') }}" alt="{{ caption|default('') }}"{% if extraHTML %} {{ extraHTML }}{% endif %}>
{% endmacro %}

We have a more complicated version for responsive images but that's the basic idea...

Also, to find things using assets, although I have never used it, I hear this is good:
https://github.com/iainurquhart/craft_introvert


How do I check if a lightswitch field is false? I have a Resources page and an archived Resources page made up of entries. I want to show all current resources on the main page (this list should not include the archived ones) and on the archived page I only want to show only archived resources. I am using a lightswitch field to toggle whether a resource is archived or not.

The archived-only page works as expected, it shows only the archived resources, using this:

{% set resources = craft.entries.relatedTo({ targetElement: category }).order('title').archivedResource('1') %}

The main page, which should show all resource entries except archived ones actually shows all resources (archived and unarchived). I’m using this code:

{% set resources = craft.entries.relatedTo({ targetElement: category }).order('title').archivedResource('0') %}

It appears that the .archivedResource(‘0’) bit is not having any affect. Should I be using some other method to check whether a switch field is toggled or not?

You have to use 'not 1' instead of '0':

{% set resources = craft.entries.relatedTo({ targetElement: category }).order('title').archivedResource('not 1') %}


Entries from all categories in a category group via URL? I'm familiar with the option in the category settings that allows for categories within a category group to each have their own URLs:

I have this setup and it is working fine. However, I'm wondering if there is a URL structure that will allow me to have a category group "home" URL in which entries from all categories within the category group are shown.

I know there are a couple of different ways I could do this by setting up templates for each category group "home" page, but I would prefer a way to do this using a single template that took into account the URL structure.

Create a URL structure like this:

yourwebsite.com/categories/groupName

Then in your template:

{% set group = craft.request.getSegment(2) %}

{% set categories = craft.categories.group(segment) %}

Once you have the categories you can loop over them and fetch entries related to each. It may however, be more beneficial to do this via a plug-in where you can construct a more complex query based on the categories and therefore be more efficient.

{% for category in categories %}

    {% set entries = craft.entries.relatedTo(category) %}

    {% for entry in entries %}
        // template stuff
    {% endfor %}

{% endfor %}


Element API - Order results by Category Is there a way to order the Craft Element-API results by the category title?

I'm just getting the error

SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

The "hostingCompany" field is a category field.

'hostings.json' => [
        'elementType' => Entry::class,
        'criteria' => [
            'section'   => 'hostings',
            'orderBy' => 'hostingCompany desc'
        ],
        'paginate' => true,
        'transformer' => function(Entry $entry) {

            return [
                'hostingDomain'  => $entry->hostingDomain,
                'hostingCompany' => (string)$entry->hostingCompany[0],
                'url'            => $entry->url,
            ];
        },
    ],

Updated error message:

PHP Warning 'yii\base\ErrorException' with message 'Header may not contain more than a single header, new line detected'
in /Applications/AMPPS/www/crm.local/vendor/yiisoft/yii2/web/Response.php:380
Stack trace:
0 /Applications/AMPPS/www/crm.local/vendor/craftcms/cms/src/web/ErrorHandler.php(81): yii\base\ErrorHandler->handleError(2, 'Header may not ...', '/Applications/A...', 380)
1 [internal function]: craft\web\ErrorHandler->handleError(2, 'Header may not ...', '/Applications/A...', 380, Array)
2 /Applications/AMPPS/www/crm.local/vendor/yiisoft/yii2/web/Response.php(380): header('HTTP/1.1 404 SQ...')
3 /Applications/AMPPS/www/crm.local/vendor/yiisoft/yii2/web/Response.php(339): yii\web\Response->sendHeaders()
4 /Applications/AMPPS/www/crm.local/vendor/yiisoft/yii2/base/Application.php(392): yii\web\Response->send()
5 /Applications/AMPPS/www/crm.local/web/index.php(21): yii\base\Application->run()
6 {main}

This seems more like it may be an error in your code somewhere, do you have dev mode turned on?

I think you may want to output the title of the category:

'hostingCompany' => (string)$entry->hostingCompany[0]->title,

See if that helps, if not I would update your question with your complete element-api.php


I can't add a body field? I have made a new "section" called Blog. In the dashboard I now have a quick post panel but I can only input a title and nothing else? How can I add the ability to have a body etc?

You've probably gone through the process of creating a new Section, but have not assigned any fields to it.

In Craft, the differences between each of your Sections and Entry Types comes in the various fields you assign to them.

I suggest you take a look at the intro to Sections and Entries, then at Fields.

The typical content structure definition process looks something like:

Create a Section and at least one Entry Type
Create a Field Group
Add Fields to the Field Group
Add the Field Group or individual Fields to your Entry Type(s)
Add or Edit your content by creating or modifying an Entry.

In your case, you've probably done step 1 and step 5. Try adding some fields (like "Body" or "Tags") and assigning them to your Entry Type.


MANY_MANY relationships in plugins I replicated what was mentioned here: (Plugins: Managing Related Records)

However I'm not seeing any new table created to on plugin install.

I have a "LeaderRecord" with

'trips'     => [static::MANY_MANY, 'pluginexample_TripRecord', 'pluginexample_trip_leaders(tripId, leaderId)']

with the same relation defined in a "TripRecord", am I missing something to have the tabled created?

Thanks!

Craft won't create the join table for you when specifying a MANY_MANY relationship.  You'll still need to manually create a record for that join table.  See Craft's own craft/app/records/UserGroup_UserRecord.php as an example.

What it will do, as mentioned in the answer you linked to is keep the data up-to-date in the join table without having to specifically reference it in your queries.


When to hide show more button I am use a load more button in place of pagination. I just using jquery and ajax using this post as a starting point.

The problem I'm having is how to hide the button when there is no more posts to show. I thought I could do this with pagination but its not working out.

Here is my blog index:

            {% paginate craft.entries.section('blog').limit(2) as pageInfo, blogEntries %}

            {% for entry in blogEntries %}

{{ entry.title }}

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

Continue reading

            {% endfor %}

        {% if pageInfo.nextUrl %}

            <button id="more-button" data-page="{{craft.request.getPageNum()}}" data-batch="2">Load More</button>

        {% endif %}

Here is my javascript:

import $ from 'jquery';

$("#more-button").on('click', function () {
var btn = $(this),
    page = btn.data('page'),
    batch = btn.data('batch'),
    offset = page * batch,
    newPage = page + 1;

loadPosts(offset, batch);
// set the buttons page attribute to the new page it is on.
btn.data('page',newPage);

console.log('page');
console.log(newPage);
});

function loadPosts (offset, limit) {
$.get('/ajax/posts', { offset:offset, limit:limit }, function (data) {
    var postOutput = $('#post-output');
    postOutput.append(data);
});
}

and here is the ajax/_posts:

{% set offset = craft.app.request.getParam('offset') %}
{% set limit = craft.app.request.getParam('limit') %}
{% set moreitems = craft.entries.section('blog').limit(limit).offset(offset).all() %}

{% for entry in moreitems %}

{{ entry.title }}

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

Continue reading

{% endfor %}

Here is what I did in my blog index:

        {% paginate craft.entries.section('blog').limit(1) as pageInfo, blogEntries %}

            {% for entry in blogEntries %}

{{ entry.title }}

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

Continue reading

            {% endfor %}

        {% set numOfpages = pageInfo.totalPages %}

        <button id="more-button" data-page="{{craft.app.request.pageNum()}}" data-batch="1" data-total="{{ numOfpages}}">Load More</button>

and in my javascript:

$("#more-button").on('click', function () {
var btn = $(this),
    page = btn.data('page'),
    batch = btn.data('batch'),
    total = btn.data('total'),
    offset = page * batch,
    newPage = page + 1;

console.log(newPage);
console.log(total);

if ( newPage <= total ) {

    loadPosts(offset, batch);
    // set the buttons page attribute to the new page it is on.
    btn.data('page',newPage);
}

if ( newPage == total ) {
    $('#more-button').hide();
}

});

function loadPosts (offset, limit) {
$.get('/ajax/posts', { offset:offset, limit:limit }, function (data) {
    var postOutput = $('#post-output');
    postOutput.append(data);
});
}


Forgot password URL in email returns an error When hitting the "forgot password" link on the CP login form, an email is sent but the URL provided returns "Bad Request Param "id" doesn't exist."

Is this a bug or have I done something silly?

This is a site running on a local development environment with Craft 2.3.2636

I know why this happens - we have the same problem. It is related to the escaping of the & in the password reset URL not being escaped:

http://yoursite/admin/actions/users/setpassword?code=abcd&id=1234

somehow, this arrives at our (and your I guess) server as:

http://yoursite/admin/actions/users/setpassword?code=abcd&amp;id=1234

Then the code is abcd and a parameter called amp;id is 1234.

In our case, we have craft setup to send HTML emails, and have an email template like:

Click here to reset your password: {{link}}

and end up with the link http://yoursite/admin/actions/users/setpassword?code=abcd&id=1234 directly in the HTML - this is WRONG, since the & symbol has to be escaped as &amp;.

Now, we could compensate, and make our template:

Click here to reset: {{link|escape}}

Then we get correct HTML, but the plain-text version of the email is now broken.

AFAIK there is no way to have separate templates for text and html emails in craft?

I guess your problem is also HTML emails, OR you have a user with an overzealous email client, that adds the escape of the & for you.


How to process CSV files within a Matrix field? I'm trying to import and process CSV data within a matrix field.
My situation is the following:

I have a matrix field with one block and several fields inside. One of these is an asset field to upload a CSV file. Now I don't just need to upload this file to a specific destination but also directly want process the given data inside of my CSV file to write it into the database and also display the data in the backend after saving the entry. Furthermore I need to be able to edit the output of the CSV in the backend. The best case would be a table.
I specifically don't want to have a standalone plugin which provides the given data to a matching entry. That would kinda ruin the workflow for editors.
I would really love to have the upload inside of the suitable entry.

Maybe I'm just overlooking one simple solution but I don't see how I should do it.

I hope I explained it good enough and am looking forward to some solutions.

Thanks in advance and best regards,

JohN

You're not overlooking anything. What you're asking for is not a core feature of Craft and probably will never be. There's also no plugin yet that does something like this.

So the only answer I can give you right now is that you have to find someone who makes such a plugin for you. The jobs board on straightupcraft.com is probably a good address to find a developer.


Basic Bootstrap + Matrix Implementation I've got a project where I'm trying to set up a basic page layout – header, body, footer. But I also want the option for a user to add an image or bit of content (let's call it a "sidebar") that splits the body section into two columns – one for body copy on the left and one for the new content on the right.

For this, I'm using a Matrix field (for the user to create sidebar content on the fly) and Bootstrap (for the grid). When sidebar content is created for the entry, I'm hoping to be able to add a "col-sm-8" class to the body wrapper, as well as add a div with the "col-sm-4" class for the sidebar column for it to reside in.

Now, I have experience with creating static layouts in Bootstrap, but I'm woefully inexperienced at dealing with anything related to coding logic that isn't an if/else statement, and I can't seem to work out the code for Matrix in Twig.

I also need to be able to add different kinds of content (or blocks) in the sidebar, so the logic should also need to check for whether one or more kinds of blocks are populating, but still apply the same effect.

Can anyone provide an example of how to do this?

edit: BTW, I have read the documentation on templating Matrix fields. I just don't know how to check for multiple block types in order to print a class name & create a new column.

Why not use:

{% if block.sidebar|length %}

{% else %}

{% endif %}

This way the column will automatically be smaller IF the side bar exists.


Send Emails to dynamic list of recipients I would like to send an Email to a dynamic list of recipients with SproutEmail.

I've created a Plugin that adds custom element actions in the users indexview that raise a custom SproutEmailEvent to send a Notification. The event works fine already, but I want to send the notification to the dynamically selected list of users.

Let's say I select 4 Users in my user indexview and click on my custom action "Send Reminder email", then all of the four selected users should receive the notification email.

Also of course, I would need to address the selected users in the email template, like "Dear {firstName} {lastName}"

I understand how I could do that with a single user, but how about a dynamic list of selected users?

Thanks for your help.

Robert

There are two things to consider here:

How to approach sending to a list
How to approach populating a notification with dynamic information

Sending email to a list of users

Sprout Email notifications use the default Craft email service. Each notification is sent to a single individual. To send to a list, what you'll need to do behind the scenes is loop through all the people in that list and send them each an email one by one.

Sending notifications with dynamic information

While Sprout Email uses the default email sending behavior in Craft, to send notifications programmatically you'll want to use the sendNotifcation method:

craft()->sproutEmail_defaultMailer->sendNotification($campaign, $object);

The $campaign variable should be an instance of a SproutEmail_CampaignModel and can be created by retrieving the Notification you want to send by it's ID like so:

craft()->sproutEmail_notifications->getNotificationById($id);

The $object is the data that will be processed in your template and any fields that accept dynamic variables such as the Subject, From Name, From Email, Reply To, and Recipients fields.

In your situation, it sounds like you are sending User-specific notifications and your template might be expecting a UserModel for any dynamic variables.

A very rough starting point for how to approach the sending could be as follows:

// Get all your users first

foreach ($users as $user)
{
    // Get your Campaign (SproutEmail_CampaignModel)
    $campaign = craft()->sproutEmail_notifications->getNotificationById($campaignId);

    // Get your User (UserModel)
    // This step is only needed if $user is not already a UserModel
    $user = craft()->users->getUserById($userId);

    // Send your Notification
    craft()->sproutEmail_defaultMailer->sendNotification($campaign, $user);
}


Is there a way to avoid content duplication on multi site setup? I have just crated a multi site according to the instructions on Crafts page.
Lets just say I have:

siteone.com with template forlder templates/siteone
sitetwo.com with template forlder templates/sittwo

It all works fine however all templates from templates/siteone can also be accessed on sitetwo by simply going to sitetwo.com/siteone/site-one-only-template

Is there a way to prevent that?

I've went through all the pages and added "_" to the template filename, then updated template paths of each single to reflect that. This now works as expected, however what's the point of site specific template folder if it's still routed to by other sites?

That would probably be the Propagation Method setting in the channel´s settings. There you can choose "Only save entries to the site they were created in" (among other options). The thing is not your template path, but that the entry is stored to both sites (which is useful for, say, two sites that are just different language versions of the same site, and should have the same content).


How do multiple date queries differ between Craft 2 and 3 After spending a lot of time solving this for myself I thought I'd share it.
In my Craft 2 template I had this query:

{% set result = craft.entries({
    section: 'events',
    eventDate: ['and', '<' ~ now.w3c(), '> ' ~ now | date_modify('-6 days')],
    results: ':notempty:',
    order: 'eventDate desc',
    with: ['imageGallery'],
    limit: 3
}) %}

My Craft 3 version is:

{% set result = craft.entries()
    .section('events')
    .eventDate( ['and', '<' ~ now|atom, '>' ~ now|date_modify('-6 days')|atom ] )
    .results(':notempty:')
    .orderBy('eventDate desc')
    .limit(3)
    .with(['imageGallery'])
    .all()
%}

Note the extra |atom after the date_modify('-6 days')


Empty .getParam() does not return an array with dump() craft.request.getQuery() returns:

array (size=5)
  'tags' => string 'anxiety' (length=7)
  'maxPrice' => string '' (length=0)
  'sessions' =>
    array (size=4)
      0 => string 'email' (length=5)
      1 => string 'chat' (length=4)
      2 => string 'skype' (length=5)
      3 => string 'phone' (length=5)
  'hours' =>
    array (size=3)
      0 => string 'office' (length=6)
      1 => string 'evenings' (length=8)
      2 => string 'weekends' (length=8)

Whereas craft.request.getParam() throws an error:

  PHP warning

  Missing argument 1 for Craft\HttpRequestVariable::getParam(), called in /home/vagrant/Sites/counselling-anywhere/craft/app/vendor/twig/twig/lib/Twig/Template.php on line 609 and defined

This should have changed in Build #2465 right? I'm assuming it'll still work the same, but it's confusing that they don't return the same results.

Is this by design?

The behaviour you're seeing is by design – craft.request.getQuery() will return all GET variables if it's called without arguments, whereas craft.request.getParam() requires the name argument – i.e. craft.request.getParam('foo').

The changelog notes for build 1.3.2465 does reference a couple of issues related to these methods, but nothing suggesting any changes in regards to the required name argument for getParam(). Unfortunately, the GitHub repo for Craft builds doesn't go back as far as 1.3.2465, so I'm unable to verify this though.


Output getSegments() array in template Is it possible to output a getSegments() array in a template to then run conditions on?

I can output one segment fine using getSegment(), but if I try to select one or more segments using getSegments() it outputs 'Array'.

Thanks in advance for any help.

That's because getSegments() returns an array. You can either get one of those segments by using:

{% set segments = craft.request.getSegments() %}
{{ segments[0] }}

Or loop through all returned segments:

{% for segment in craft.request.getSegments() %}
    {{ segment }}
{% endfor %}


hi! can you recommend a good basic tutorial for Craft? can anyone recommend a good video or any tutorial for Craft? Thanks

Both of these sites are run by Ryan Irelan

https://mijingo.com/craft

https://craftquest.io/


Front end login form with ajax Im trying to get a front end login form to work over ajax and running into issues, it seems to always pass back success and not sure how to actual make sure the cookie gets created and the user is logged in?

here is the gist of what i have right now:
https://gist.github.com/keithmancuso/29e8446ec5fa66fb2b01

If you’re getting the {success: true} response, then the user is getting logged in successfully, and the cookie would have actually been created by that response.


Discount for subscription plans? In the CP there are discounts that are applied to products in cart.

Is there an option in the CP to apply discounts to subscription plans or would this need to be done by creating a module? Just need confirmation before building a custom module as the docs doesn't specify such a option.

Using: https://github.com/craftcms/commerce-stripe

Commerce: Latest to this date

CraftCMS: Latest to this date

"Not yet" is the short answer. https://github.com/craftcms/commerce/issues/295


Retrieve Asset Filename from an entry, inside a matrix field I must simply be blanking this morning, but for whatever reason, this has me stumped... I have a Structure section I use for the different sections of my site which sets titles for each page, etc.

Additionally, I have another section called "Widgets". These widgets are stored in the template folder and each widget is linked up to a dedicated entry in an Asset field. Finally, each Structure entry (take the home page for example) has a Matrix field. This allows me to rapidly add new pages from templates I have already built. Unfortunately this time around I am having trouble pulling the filename for the widgets, though I seem to be able to grab the asset IDs. Following is the code. Thank you in advance for the help; I am sure it is simple but I've been banging my head against my desk for a little too long now...

                {% block contentPrimary %}
                {% switch entry.type %}
                    {% case "mainContentLeft" %}
                        {% for block in entry.contentPrimary %}
                            {% switch block.type %}
                                {% case "text" %}
                                    {{ block.text }}
                                {% case "widget" %}
                                    {% if block.widgetPrimary|length and block.entry[0].widgets|length %}
                                        {{ block.widgetPrimary[0].widgets[0].filename }}
                                    {% endif %}
                            {% endswitch %}
                        {% endfor %}
                    {% case "mainContentRight" %}
                        Main Content Right
                    {% case "singleColumn" %}
                        Single Column
                {% endswitch %}
            {% endblock contentPrimary %}

After trying a few different things, I've seen a couple different errors, but the error I see at present states:

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

Thank you again, in advance!

I would first check if you actually set up the Field handles you are currently using in your template:

Matrix Field handle: 'contentPrimary'
Block Type handle: 'widget'
Entries Field handle: 'widgetPrimary'
Assets Field handle: 'widgets'

Then try to use the first() method instead of direct access to the array.
Or use direct access only after adding find() method that creates an array out of your ElementCriteriaModel. Edit: Direct access like this: myArray[0] should also work with an ElementCriteriaModel, but throws errors if no first elements exists (→ read Brandon's answer on this topic for more info).

{% for block in entry.contentPrimary %}
    {% switch block.type %}
        {% case "widget" %}
            {% set relatedEntry = block.widgetPrimary.first() %}
            {% if relatedEntry %}
                {% set asset = relatedEntry.widgets.first() %}
                {% if asset %}
                    {{ asset.title }}
                {% endif %}
            {% endif %}
    {% endswitch %}
{% endfor %}


How can I output the territories array with craft.i18n? I found this code in the Craft documentation:

{% set localeData = craft.i18n.getLocaleData() %}
{% for month in localeData.getMonthNames() %}
    {{ month }}
{% endfor %}

What I need is the whole list of countries (from Ascension Island to Zimbabwe).
I tried .getTerritories() but it doesn't exist:

{% set localeData = craft.i18n.getLocaleData() %}
{% for country in localeData.getTerritories() %}
    {{ country }}
{% endfor %}

Is there any solution?

Looks like Yii doesn't expose a way to grab all of the territories for a given locale by default.

I've just added it to Craft 2.2, though.  So when that comes out, you'll be able to do this:

$localeData = craft()->i18n->getLocaleData('en_us');
$allTerritories = $localeData->getAllTerritories();


Create new entry from related Entry field It would be really nice to create a new entry in a section (say "Dates"-channel) direct from a related entries field in another section (say "Events"-channel). Is this possible already, or are there any plugins for this?

I have asked this before on Google+, but not sure if it's been answered.

Not sure when this was added, but this is now available in Craft core. The select modal has a button to create a new entry of that type.


I'm getting unexpected output within media queries It outputs the same image, which shouldn't and I am suspicious, that it causing it curly brackets followed after media queries and after twig code.

{% set news = craft.entries.section('news').limit(3) %}
{% for news in news %}

            {{ news.promotionNewsText|ucfirst }}

{% endfor %}

Try it this way. Why are your outputting multiple images for the same background image for the same class.  The last item will override the previous.

{% set news = craft.entries.section('news').limit(3) %}
<style type="text/css">
  {% for item in news %}
    @media (min-width: 1200px){
        .hero{
            background-image:url(
               {% set cover = item.promotionImage %}
               {% if cover|length %}
                   {{ cover[0].getUrl('gtLg') }}
               {% endif %}
             );
         }
    }
  {% endfor %}
</style>


Access env variables in custom php files Craft Version 3.2
PHP Version 7.2

Below is my folder structure:
Root
  - Other Craft Folder
  - Web
     - Services
         - Db.php
     - env file

I want to read the connection string of the SQL SERVER from the env file.
Things I have already tried:

App::env
require_once 'C:\wamp64\www\craftApp\vendor\autoload.php'; use craft\helpers\App;

print_r(Craft::parseEnv('$sqlServerName')); // Throws Error

But it doesn't work.

If that is really all that you're doing, and you have no other integration with Craft, you can parse the .env however you like. Craft uses vlucas/phpdotenv internally so that library is already in your vendor directory. You should be able to pick that up after including Composer's autoloader.
If however you have any kind if integration with Craft, look at web/index.php and see what's going on in terms of bootstrapping there, copying the parts necessary for your application.


How can I set an entires status via ajax from a front-end form? I am trying to set an entires status to disabled from a front-end form.

Here is the click event listener I am using:

$(document).on('click', '.delete', function (event) {
    let $this = $(event.currentTarget);
    let verify = confirm("Are you sure you want to remove this?");

    if (verify) {
        let params = {
            'entryId': $this.data('id'),
            'sectionId': $this.data('section'),
            'enabled': 0
        };

        // append CSRF token.
        params[window.csrfTokenName] = window.csrfTokenValue;

        onSetEntryStatus(params, function (res) {
            console.log(res);
        });
    } else {
        console.log('do nothing');
    }

    event.preventDefault();
});

Here is my ajax method:

function onSetEntryStatus(data, callback) {
    $.ajax({
        type: 'post',
        contentType: 'application/json; charset=UTF-8',
        cache: false,
        data: data,
        url: '/actions/entries/save-entry',
        processData: false,
        dataType: 'json',
        timeout: 50000
    }).done(function (response) {
        console.log('response', response);
    }).fail(function (error) {
        // Total fail.
    });
}

(also tried posting to actions/entries/save-entry)

Request payload is coming across as: [object Object] so clearly I'm having a brain-fart moment there.

Everything I have commented out, are things that i've seen in the console when setting the status from the CP. Currently, I am getting a 403 error back. I am able to verify that I am passing in the csrf token, so I am guessing it is because of the (incorrect) way I am sending data.

Grateful for any suggestions!

EDIT

When logging out what params I'm sending to the ajax method:

enabled: 0
entryId: 1465
sectionId: 5
_token: 'really-long-string'

My best guess, based on what you want to do, is that you don't have the correct permissions to change the entry's status. The requirePermission method kicks in and will send a 403 if you don't have permission to enable an entry.

I think the only way to change this, is to make sure that the logged in user has the correct permission(s).


Running plugin migrations when other plugin is installed? I'm creating a plugin (A) that has optional support for another 3rd party plugin (B). When my plugin A is installed, I create a number of tables. If plugin B is also installed my migrations create further tables specifically for plugin B.
The problem is if someone installs plugin A, then only installs plugin B afterward, my custom tables are never created.
How can I create tables/run migrations only when a plugin (B) is installed?
EDIT
I've been able to get this working with the following:
Event::on(
  Plugins::class,
  Plugins::EVENT_AFTER_INSTALL_PLUGIN,
  function (Event $event) {
    if ($event->plugin->handle == "pluginB") {
      $migration = new migrations\m201031_120401_add_pluginB_support();
      $migration->safeUp();
    }
  });

You can have plugin A listen for the EVENT_AFTER_INSTALL_PLUGIN event.
It could then check if $plugin->handle is for plugin B and if so, run any additional install migrations or logic.
You could do something similar for the EVENT_AFTER_UNINSTALL_PLUGIN event to clean things up in the case where one gets uninstalled.


Can't access admin panel It's the first time I'm using Wamp for local hosting my Craft website.
I've changed my Windows and Wamp apache host file for accessing my domainname instead of localhost. (ronvanderwerf.loc instead of localhost)

The front-end of the website looks fine:

(I'm getting a error because I still need to setup Craft)

The problem is, I can't access the admin panel. I get a 404 Not Found.

I've changed the directory order of my project for some hosting reasons:

My apache host file:

<VirtualHost *:80>
ServerName ronvanderwerf.loc
DocumentRoot c:/wamp64/www
<Directory  "c:/wamp64/www/">
    Options +Indexes +Includes +FollowSymLinks +MultiViews
    AllowOverride All
    Require local
</Directory>

My root htaccess file:

<IfModule mod_rewrite.c>
RewriteBase /

# Send would-be 404 requests to Craft
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]
RewriteRule (.+) index.php?p=$1 [QSA,L]

I hope someone can help me.

I had the same issue on my mac and struggled for hours.

Having the right .htaccess file in place was key, but if you are not getting Craft's error messages, that's a sign your .htaccess file is not having any effect (you can verify this by placing some random text in there and see if you get an internal server error or not).

Making the following changes to httpd.conf made .htaccess work and solved this issue for me:

Change from "AllowOverride None" to AllowOverride All" in the
document root directory block
Uncomment LoadModule rewrite_module...

I hope this helps someone solve this quicker than I did.


How do I update the content of a field type in the onAfterElementSave() method? I am building a field type for Craft that needs to do additional processing to the saved data once the element id is available. For this reason, the prepValueFromPost() method won't work, since the element id isn't available yet.

So how to update the content of the current element from the onAfterElementSave() method?

This will return the content for the specific element instance you're on:

$this->element->getContent()

And from there you can do your additional content processing.

When you're ready so save it, you can call:

craft()->content->saveContent($this->element);

There are several examples in craft/app/fieldtypes folder where Craft's native field types do additional processing like this.


Possible to Directly access related records (Laravel ORM style)? This post may scream ignorance (Still delving into the plugin world). I'm coming from a background using mostly laravel for PHP application development and building a few plugins now on Craft has felt a bit verbose to access related objects. Is there any "nice" way to allow something like the following in Craft?

$phone = User::find(1)->phone;

or in terms of craft plugins, just include related data in the model itself instead of having dozens of findXbyId methods littering the code?

related: populateModel usage with eager loading related records

Any generic solutions?

Thanks!

Not 100% sure I'm following what you're looking for, but if you have a UserRecord defined with a phone relation, then something like this should do what you want:

$phone = UserRecord::model()->with('phone')->findById(1)->phone;


Make dimensions common for all variants in Craft Commerce When I enable multiple variants for product type that has Dimensions and Weight, fields "Dimensions and Weight" become available for every single variant. Product is tablet and all variants have a same dimensions and weight.
Is it possible to have common "Dimensions and Weight" fields for a single product, not for every variant?
Application info:

Craft Pro 3.4.27
Craft Commerce 3.1.11

This is actually one of Commerce's best features IMO - that you CAN have separate dimensions/weights for variants - for us this is absolutely essential.
Of course, there are definitely times when it is not needed, too.
In these cases, we have a 'Standard Box' section that we store standardised entries in, with the appropriate data.
We then just relate these to the variant using a relations field.
Works really well...however, the behaviour is of course not the same as using the in-built fields - e.g. your shipping calculator needs to be aware of this etc.