Add settings to plugins cp section instead of settings page I've setup a plugin like so http://domain/admin/plugin-handle (cp section) and a settings page here http://domain/admin/settings/plugins/plugin-handle

I can edit my plugin settings under the latter URL, however I would like non admins to be able to do so as well, but under http://domain/admin/plugin-handle

How can I go about this? Adding e.g.

{{ forms.textField({
    label: 'Headline'|t('craft-terms-of-service'),
    instructions: 'Enter the headline of your TOS here.'|t('craft-terms-of-service'),
    id: 'tosHeadline',
    name: 'tosHeadline',
    value: settings['tosHeadline']})
}}

to the http://domain/admin/plugin-handle template (src/templates/index.twig) (cp section) non-admins have access to, I get Variable "settings" does not exist. I can't figure out how to make it accessible/exist.

Thanks in advance

Edit

Figured out how to add fields to the cp section through the "Getting Started with Craft Plugin Development" course on craftquest.io, however the way I'm saving the settings to the db is rather crude. I'm just doing Craft::$app->db->createCommand(.... to update the plugins table. It works, but I'm sure there are much more elegant ways of doing it?

Solution

In my src/template/index file I added this to make the form work

{% extends "_layouts/cp" %}
{% import "_includes/forms" as forms %}

<form action="" method="post">
{{ csrfInput() }}

{{ forms.hidden({
    name: 'action',
    value: 'craft-terms-of-service/default/save-tos'
}) }}

{{ forms.hidden({
    name: 'tosCurrentVersion',
    value: now.timestamp
}) }}

{{ forms.lightswitchField({
    label: 'Enable TOS?'|t,
    id: 'tosEnabled',
    name: 'tosEnabled',
    on: craft.craftTermsOfService.get('tosEnabled'),
    first: true
}) }}

{{ forms.textField({
    label: 'Headline'|t('craft-terms-of-service'),
    instructions: 'Enter the headline of your TOS here.'|t('craft-terms-of-service'),
    id: 'tosHeadline',
    name: 'tosHeadline',
    value: craft.craftTermsOfService.get('tosHeadline')
}) }}

{{ craft.craftTermsOfService.redactorField({
    label: 'Terms of Service'|t('craft-terms-of-service'),
    instructions: 'Enter the TOS every user must accept before using the site below.'|t('craft-terms-of-service'),
    name: 'tosBody',
    rows: 4,
    value: craft.craftTermsOfService.get('tosBody')|raw
})|raw }}

<input type="submit" class="submit btn" value="{{ 'Save'|t }}">

Using the actions/craft-terms-of-service/default/save-tos controller I took the data from the request and updated the data in the plugins table. Also in the form in my index template I used the craft.craftTermsOfService.get variable to fetch the settings from the plugins table and give each form element its appropriate value.

For details, see the controller on github and the variable on github. Note this is the first time I make a plugin, so it's probably a mess, sorry about that.


How do I pass dynamic year and month to the .after() and .before() functions? I've a URL /news/archive/2014/12

A route parses that as going to an archive template and captures a year and month variable. I then want to select all the entries from that month, and I can't work out how. Here's what works for just the year:

{% set entriesInPeriod = craft.entries.section('news').limit(null).after(year).before(year+1) %}

And the docs say the after and before functions need things specified in the format:

YYYY
YYYY-MM

I can't get that passed in because I don't know how Craft is interpolating the contents of the parenthasise; if I do

{% set entriesInPeriod = craft.entries.section('news').limit(null).after(year-month).before(year-month+1) %}

I'm not getting any results.

UPDATE: Answer below (use ~ to concat strings) doesn't work correctly because in reality months 'loop' after 12. What gets put in the query when starting in December evaluates to 'month after 12 and before 13', which is garbage.

Is there a way to get something like:

{% set entriesInPeriod = craft.entries.section('news').limit(null).postDate(year~'-'~month) %}

This doesn't work, but I can find no documentation on how postDate should be formatted in this use case.

In Twig, you concatenate strings with the ~ operator. So, if year and month are variables in your template, you can create a string in the required format like this

{% set yearMonth = year ~ '-' ~ month %}


Get HTML of rendered template inside module I'm getting started with plugin/module development. I want to get the template file, pass some variables to it, and get rendered HTML of that template into a string variable.

How do I do that?

I figured it out. I will paste it here in case someone needs it:

$html = Craft::$app->getView()->renderTemplate('template.twig', $variables);


Migrate to a test site I'm new to Craft CMS, and was wondering if it is possible to migrate a Craft CMS website to a test domain, to do redesign work, before moving the update site back to the live domain?

and will this effect any license?

looking forward to hearing from you.

Kindest regards
Anrich Vigus

Yes it's possible.

You may get a notice that the licence key is in use on another domain if your testing domain is publicly accessible (rather than running on your local machine). But the site will continue to work just fine.

What you can't do is run 2 "live" sites with the same key. That's a violation of the licence.

Furthermore, by going to https://id.craftcms.com/ you can manage the licences for any Craft sites you have.


Is it possible to create a field group that can be modified across entry types? Sorry if this is asked/answered elsewhere. I tried to search for it with no success.

Suppose I have a common group of fields that I want to include in different entry types, and each entry will have unique data entered in the fields. A concrete example is:

SEO / Meta

meta title
meta description
meta keywords

Later on I want to remove the "meta keywords" field from every entry type that has this "field group". Is there a way — preferably with core Craft abilities — to set it up so I can update the field group in one place and not have to touch every entry type?

A matrix field with max 1 would get the job done but feels plain wrong for this.

I have the feeling there is another way I just don't know about yet.

No, field groups are just a way to have your fields grouped in the field layout designer and fields index page. Another advantage is the possibility to drag a whole group in the designer to create a new tab.

Approaches, other than a max 1 Matrix field you mentioned, that I can think of are:

multiple predefined rows in a Table field
multiple predefined rows in a Set Table field, which allows you to have a read only "Label" column and set a max rows
custom solution implementing a new field type that has multiple input fields


Section and template folder problem I hope anyone can help me to get started. I think I have a brain freeze or something.

I have created a section (structure) that is called "House".
I want this section to use a template. In craft/templates/ I have created the folder "house" with the file index.html in it. I have also tried _entry.html.

When I then go my URL (for example): project.com/house it can´t find anything. Could not find the path on the server.

Is there something "wrong" on the server that don't allow access to that URL?

Whatever template path you decide to go with, make sure you set that in the section’s settings. So if it’s house/_entry.html, make sure you put house/_entry in your section settings.


Plugin not updating in the plugin store from changelog updates I have a custom plugin registered with id.craftcms.com.

The plugin store currently sees it at as 2.0.0, but I have since updated the plugin to 2.0.1 (and subsequently tried to force a silent 2.0.2 update) and noted so in my changelog but the plugin store is not seeing this update.

The contents of my changelog look like this:

# Release Notes for Craft User Manual

## 2.0.2 - 2019-02-27
### Updated
- Forcing new version for deprecation issues

## 2.0.1 - 2018-08-24
### Fixed
- Deprecation Issues

## 2.0.0 - 2018-08-24
### Added
 - Initial Craft 3 release

This was lifted directly from Craft's documentation on changelogs so I'm not sure what I'm missing. Is there anything else I can try or debug?

The reason the Plugin Store hasn't picked up the 2.0.1 release is that you've got 3 different 2.0.1 tags in the repo.

Usually, that's not a problem as it will just pick the first one by date.

In this case, if you browse the first "V2.0.1" tag, you'll see that its composer.json file has a listed version of 2.0.0, which is a version mismatch, so the Plugin Store will ignore it. https://github.com/hillholliday/Craft-User-Manual/blob/00e2808e328e5bfe793fd343a59b5d2445d84d27/composer.json#L5

The reasons 2.0.2 never got picked up is because there is no 2.0.2 tag in the repo.


Adjust the config to change the order of the formatting menu in Redactor II I'm trying to adjust the order of the options in the formatting dropdown menu in the Redactor ii fieldtype but it's not picking up my changes. I have made other changes in this config that have been picked up and working, just not this one.

See below for my Standard.json config file.

{
    buttons: ['format','bold','italic','lists','link','file','image','video'],
    plugins: ['fullscreen','video','table','source'],
    formatting: ['h3', 'p', 'blockquote', 'pre', 'h1', 'h2', 'h4', 'h5'],
    toolbarFixed: true
}

Looks like the Redactor formatting config setting only affects what shows up or not from Redactor's default's of ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5'].

Can't say whether that's a bug or intended behavior, but you could probably set the defaults to empty [], then add them back in the order you want with formattingAdd.


Busted control panel after migration Recently migrated a site from staging server (Digital Ocean VPS) to client's production server – pretty basic shared hosting (their choice). They were running PHP 5.3 so got them to upgrade to PHP 7.3. I also ran the Craft Server Check first and everything passed fine. No composer so had to FTP everything and set permissions etc...

Front end is live but Typogrify and Map plugins aren't working for reasons so far unknown. The bigger problem though is the control panel cannot load styles or scripts (403 errors on cpresources dir) and cannot login. I upped permissions on that directory to 774 and still no luck. Hosting support hasn't responded so I'm kinda stuck. Never encountered these dramas before. Any advice very much appreciated.

Okay, so this is a really weird one. On a hunch the host decided to change all permissions to their default 755, and now everything works! I'm left scratching my head but there it is. Not quite sure how those permissions impact Craft security but at least it's not 777, which I was worried they'd need.


Why am I getting "no sources available" when adding/editing a field of type Assets? Anyone else suffering from this issue after doing an upgrade/update?

This may be in the category of bugs because it appeared to be working earlier today before upgrading Craft from the Free version to the Pro version I've been unable to save fields that are of type "Assets".

Current install is:
Craft Pro 2.1.2564 Released on 7/15/2014

The issue is pretty straight forward. Attempting to save or edit a field that is set to the type "assets" fails.

Additionally, the sources available for assets on the create new field page incorrectly indicate that no sources are available. Error reads "No sources exist yet."

I did a run down where I verified the directory paths were properly set, and the permissions for those directories were also properly set. Both checked out okay.

Additionally, uploads to all my defined sources work as expected. This issue seems to only impact fields.

Result of trying to save or edit a field produces an error that appears saying "save failed". No further warnings show up.

Here's a shot of the available sources defined on my install, these were defined after my upgrade if that makes a difference.

I would not consider this to be the best solution, but I was able to fix my issue.

I downloaded a fresh copy of Craft and replaced the craft/app/ directory with the fresh download. This restored all functionality back to normal. Not the most ideal, but it worked.

Hope this helps someone.


Loop through fields in field layout when `entry` is not set Is there a way in a template to loop through the fields in a field layout without having to tie them to an entry? I'm currently grabbing that list with entry.getFieldLayout(3).getFields(), but that only works when entry is set.

This can be done by reaching through the section and entry type to the final field layout. Like this:

{% set section = craft.sections.getSectionByHandle('sectionName') %}
{% set entryType = '' %}
{% for type in section.getEntryTypes %}
    {% if type.handle == 'entryType' %}
        {% set entryType = type %}
    {% endif %}
{% endfor %}
{% set fieldLayout = craft.fields.getLayoutById(entryType.fieldLayoutId) %}

You should be abel to use getFields as normal.


Best Method of Handling Repeated Content Within Existing Fields? We are trying to find the best solution for handling repeated content within existing Fields in the CMS.

That is, there are bits of information which could be used nearly anywhere within existing fields in the CMS (e.g. inside a Plain Text field / Rich Text field etc) (things like the event booking link, booking deadline, event start date etc etc). The ideal solution would be that these bits of information are housed in one place in the CMS (probably will be a global), and can cleanly be pulled through to other areas of the CMS with a super user-friendly bit of syntax.

-

We've explored a few options, namely the following...

Reference Tags

As these are limited to Plain Text field types, these are not an option.

Globals

As per this SE question.

This would involve having to add include(template_from_string()) almost everywhere where a content is output from the CMS, which would be a pain and also the syntax might be a little confusing for the end user.

Create our own plugin

Whilst this might mean the syntax could be a bit more user friendly (e.g. something like [main-event-dates], we would still have to pass every field output to the plugin (i.e. craft.myPlugin.parseSyntax(entry.body)

Events

I'm just starting exploring Hooks and Events, and this looks like the best solution so far to me. From my understanding, the approach which would be most suitable for us would be something like this:

myPluginPlugin.php

function init() {
    craft()->on('elements.onPopulateElement', function(Event $event) {
        craft()->myPlugin_main->parseSyntax($event);
    });
}

myPlugin_MainService.php

function parseSyntax($event) {
    // Parse the content of the fields, using something like the following
    $event->params['element']->getContent();
}

Considerations with using the 'Events' method

We would need to build in a mechanism of programatically clearing all template caches when one of those bits of central information is changed (as Craft will not be aware of which templates need their cache clearing)
Is there a risk that this will be super php intensive to essentially loop though each field for each bit entry model / matrix block model etc etc?

-

Does anyone know of a better way to achieve what we are trying to achieve? Or feel strongly any way about any of the above?

Forgive me but after re-reading everyone's input, I lean towards Moto_Nomad relationships suggestion, mostly because it will make life as easy as possible for the content-administrator.

In your latest comment you write:

  ...but the issue is not about relating entries, but smaller bits of information, for which there is not a prescribed location.

Q: Could you give us an example of a 'smaller bit of information', please?

  That is, there are bits of information which could be used nearly anywhere within the CMS (things like the event booking link, booking deadline, event start date etc etc)

I'd suggest that the 'smaller bits of information' as well as the info you mention above, which are relevant to a Festival/Event should be stored within those (Event) Entries.

Especially if these 'bits of info' are updated over time i.e. from from one event to the next.

(I'll avoid going into an explanation of the Entries field type)

;)

  The ideal solution would be that these bits of information are housed in one place in the CMS (probably will be a global), and can cleanly be pulled through to other areas of the CMS with a super user-friendly bit of syntax.

Check out this thread: Is it possible to use Twig in a Rich Text Field?

I realise the above is about the Front-End but thought it might be useful.

Let us know how you get on, Mike :)


Product Combination Discount in Commerce 2? Is there a way to set a discount in Commerce 2 that applies when, for example, three various products are in the cart?

Use case;
Say you have a blue shirt, a black pant and a red cardigan, in the cart, and you wish to treat those as a kit. When all three are in the cart (either specific color variant, or simply a product), subtract $20 (or a percentage) from the total.

Edit;
It would seem that adjusters is the way to go. Can someone shed some light on where those go, and how one would go about it when checking for multiple products against each other? Is the best way to create a module? Is there no admin UI whatsoever for adjustments? Is there a way to build adjustments with twig? Sorry, that's a lot of questions in one topic.

Indeed, the way to go is setting up a module or plugin for this sort of thing. While I did get that working in practice, I still have questions regarding how one can loop through and compare using the Craft CMS 3 Commerce 2 APIs to actually apply the discount based on custom fields on the variants. That will be a separate question entirely.

If you stumble upon this issue, the starting point I used was this;
https://github.com/oof-bar/commerce-example-adjuster

Here's a link to the new question


Solspace Freeform upload multiple image files I've had a good look around and can't find any template reference to uploading multiple images with Freeform.  In settings i've allowed for 5 files in 'File Count'.  I'm using the following template code but it only allows a single file.

  Upload photos of the fault
  <input id="uploadPhotos" type="file" name="uploadPhotos.handle[]" placeholder="Please provide any images of the fault" />

Any guidance appreciated.

Martin

There appears to be 2 errors in your code. name="uploadPhotos.handle[]" should be name="uploadPhotos[]", assuming your field name is uploadPhotos. The handle part is unnecessary, unless you were using it like name="{{ uploadPhotos.handle }}[]", but it's redundant since you already are calling the handle to get the handle (but makes more sense when you're automating the template code).

Secondly, you need to specify multiple attribute if you wish to have more than 1 file uploaded.

The correct code should be:

  Upload photos of the fault
  <input id="uploadPhotos" type="file" name="uploadPhotos[]" multiple />


Simple PayPal connection with Craft? I'm creating a simple site where the user can buy exactly 1 product for exactly 1 price. My client wants to offer PayPal to the users for paying this product.

Which solution/plugin/whatever do you propose? Commerce seems to be a bit too big for this, I don't have lots of products with specifications, etc. But I didn't find any other plugin that can handle PayPal. Any ideas?

Depends on your requirements, but seems like you'd just be able to use the standard PayPal checkout button for this, no?

https://www.paypal.com/us/webapps/mpp/paypal-payments-standard


Setting selected elements in a BaseElementSelectorModal (or BaseElementIndex) I'm writing a Javascript based plugin which creates an instance of Craft.BaseElementSelectorModal.

When the modal is created, I'd like to have some of the entries in the modal's element index auto-selected (i.e. their containers should have the sel class added, just like when the user actually selects an entry). I have an array of entry IDs to work with, but I'm struggling to find a way to actually set the element index' selected entries.

As far as I can tell, there aren't any parameters I can set to the BaseElementSelectorModal (aside from disabledElementIds, which I can't use as I don't actually want the entries to be disabled, only selected).

I can get to the modal's BaseElementIndex instance – is there a way to programmatically select an array of entries?

After much exploring in craft.js, I've concluded that this can't be done in a clean way.

However, I found a workaround which seems to do the trick.

First, here's (a simplified version of) the code that creates the modal (which is stored in the variable modal):

var modal = new Craft.BaseElementSelectorModal('Entry', {
    criteria: criteria,
    onSelect: onElementSelect
});

After creating the modal, I use setInterval to look up the modal.elementIndex property. The reason I use a poller is that this property is actually null until the internal AJAX call to actions/elementIndex/getElements is completed. Anyway, I poll the elementIndex property every 10ms, until the property is found (or after 5 seconds have passed, when its safe to assume something has gone awry).

Finally, the element index' method selectElementAfterUpdate is used to select the entries. The method only takes a single entry ID, so I have to call it once for every entry ID in the entryIds array.

var pollCount = 0;
var pollInterval = 10;

var poller = setInterval(function () {
    pollCount++;
    if (pollInterval * pollCount >= 5000) clearInterval(poller);
    if (modal.elementIndex)
    {
        clearInterval(poller);
        $.map(entryIds, function (entryId) {
            modal.elementIndex.selectElementAfterUpdate(entryId);
        });
    }
}, pollInterval);

Not very smooth! But it works.


Craft 3 - Matrix Block for currentUser I have a Matrix field named -> certificado

with block -> certificados

and fields -> nomeDoCurso, curso, certificado

My Matrix block has no entries but is associated with a user.

How can I fetch the content of the Matrix block for a particular user in the frontend?

I'm trying with:

{% for item in currentUser.certificado %}
    {{ dump(item) }}
{% endfor %}

But this is wrong.

How can I do it?

Well, many tries later, I found a way to do it.

{% for block in currentUser.certificado %}

{{ block.nomeDoCertificado }}

{{ block.curso[0] }}

    {{ block.nomeDoCertificado }}

{% endfor %}

It is as simple as that :)


Content from two sections but one of which is related to a specific category I am looking to do the following.

I'd like to display a list of entries from two sections. That much is straightforward; however the kicker is that I only want entries related to a specific category of one of the sections.

So:

Everything from SectionA
Only CategoryC from SectionB

Possible?

You would do such things by first getting the entries IDs and then do a query to get all entries with these IDs:

{% set entryIdsA = craft.entries.section('SectionA').ids() %}
{% set entryIdsB = craft.entries.section('SectionB').relatedTo('CategoryC').ids() %}

{% set allEntryIds = entryIdsA|merge(entryIdsB) %}

{% set allEntries = craft.entries.id(allEntryIds).order('mySortByField desc') %}


Allow anonymous submission on a custom element type? I have a custom element type that I want to allow anonymous submission from the front-end. I have a solid concept on how the form data is passed but I seem to be missing something.

I have the controller setup like so:

class PluginNameController extends BaseController
{
    /**
     * @var Allows anonymous access to this controller's actions.
     * @access protected
     */
    protected $allowAnonymous = array('actionSubmit');

    /**
     * Allow public submission of the element type
     */
    public function actionSubmit()
    {
        // require post request for this action
        $this->requirePostRequest();

        $entry = craft()->request->getPost();

        // set the form id from the post request
        $formId = craft()->request->getPost('formId');
        $entry = craft()->request->getPost();

        // if form id is empty, throw exception as we can't continue
        if (!$formId) {
            throw new Exception(Craft::t('The formId is required to submit.'));
        }

        if (craft()->pluginName->publicSubmission($formId, $entry))
        {
            $this->redirectToPostedUrl();
        }
        else
        {
            die('failed submission');
        }
    }

My element type has 4 fields that are required and those submit anonymously as expected as I am grabbing them using getPost. However, my plugin also utilizes the getSources method and each formId has a field layout assigned to the custom element type, lets say 'entry'.

Whats causing the trip up is the fact that since this is an element type that utilizes a field layout, I will need to account for the fields based on the formId. So when using getPost I can namespace the attributes for the element type, but I am trying to find the best way to capture the fields specified in the field layout and save those to the appropriate table..

Any thoughts?

Ok, so I finally figured it out. The trick was using the following two methods:

assembleLayoutFromPost()
setContentFromPost('fields')

The controller now looks like this:

public function actionSubmit()
{
// require POST
$this->requirePostRequest();

// assume new element type
$elementtype = new PluginName_ElementTypeModel();

// assign the attributes specific to the element type
$elementtype->formId    = craft()->request->getPost('formId');
$elementtype->fieldName1 = craft()->request->getPost('fieldName1');
$elementtype->fieldName2  = craft()->request->getPost('fieldName2');

// if form id does NOT exist
if (!$elementtype->formId)
{
    // @TODO figure out how to return errors/validation
    dd('need a form id');
}
// if form id exists but we can't find it in the system
elseif (craft()->elementtype_forms->getFormById($elementtype->formId) == null)
{
    // @TODO figure out how to return errors/validation
    dd('form does not exist');
}

// setup a new form model
$form = new PluginName_FormModel();

// shared attributes
$form->id = $elementtype->formId;

// set the field layout
$fieldLayout = craft()->fields->assembleLayoutFromPost();
$fieldLayout->type = ElementType::Asset;
$form->setFieldLayout($fieldLayout);

// set content from post with the fields namespace
$elementtype->setContentFromPost('fields');

// Save it
if (craft()->elementtype->save($elementtype))
{
    $this->redirectToPostedUrl($elementtype);
}
else
{
    dd('not saved');
}

}

The main difference was on the front-end where I namespaced the fields that were assigned via the field layout, so the template to submit looked like this:

<form id="plugin-form"guinname method="post" action="" accept-charset="UTF-8">
    <input type="hidden" name="action" value="pluginname/submit">
    <input type="hidden" name="redirect" value="pluginname?submit=success">
    <input type="hidden" name="formId" value="1">

<!-- Required Fields -->
<label>Field 1
    <input type="text" name="fieldName1" />
</label>
<label>Last Name
    <input type="text" name="fieldName2" />
</label>
<!-- End Required Fields -->

<!-- My Custom Fields -->
<textarea name="fields[body]" rows="8" cols="40">OMG IT WORKED</textarea>

<button type="submit">Submit Now</button>
</form>


Check if includeCss set I have created a field named inlineCss, which i'm using to set a pageCss variable. However, when no CSS is added to the entry, the {% includeCss pageCss %} is still adding a style tag in the head, albeit empty.

{% set pageCss %}
    {{ entry.inlineCss }}
{% endset %}

{% includeCss pageCss %}

Is there a way to only show the style tag if the pageCss variable is not empty?

I've tried checking for is defined and not null but it just keeps outputting the empty style tag.

It looks like you should be able to wrap it in an if statement like this...

{% set pageCss %}
    {{ entry.inlineCss }}
{% endset %}

{% if pageCss != ''  %}
    {% includeCss pageCss %}
{% endif %}


Adding entry type using setContentFromPost I'm creating a new user using $user->setContentFromPost(). It all works fine except I can't attach an entry to an Entries field.

$user = new UserModel();
$user->username         = $email;
$user->email            = $email;
$user->unverifiedEmail  = $email;

$user->setContentFromPost(array(
  'companyName' => $admin->companyName,
  'companyId' => $admin->companyId,
  'partnerManager[]' => $admin->partnerManager[0]->id
));

This will create user but the partnerManager Entries field will be empty. I've tried a few different syntax variations, but none of them seem to work:

'fields[partnerManager][]' => $admin->partnerManager[0]->id
'partnerManager' => $admin->partnerManager[0]->id
'partnerManager[0]' => $admin->partnerManager[0]->id

How to fill this field?

Relationships are always added as arrays of IDs, even if you are only relating a single element:

$user->setContentFromPost(array(
    'companyName' => $admin->companyName,
    'companyId' => $admin->companyId,
    'partnerManager' => array($admin->partnerManager[0]->id)
));


Get count of new entries since last visit I'm relatively new to craft, but thanks to this board I am making great progress :-) But here is my first question, which is not answered in here:

I would like to get the count of entries of a certain section, which have been published since the last visit of a user. I'm pretty sure I have to somehow use a cookie for this, but am completely unaware of how to do this in combination with twig :(

You can use the cookies Plugin (or for Craft 2)  to store the value of the timestamp when the users has visited the page for the last time. Or you can create your custom code like explained in the question: How to set a cookie

You can get the current timestamp like it's stated in the docs

{% set currentTimestamp = now|date('U') %}

And store the cookie like explained

{# Set the cookie using 'set' variable #}
{% do craft.cookies.set( NAME, VALUE, DURATION, PATH, DOMAIN, SECURE, HTTPONLY) %}
{% set yourTimeStamp = getCookie( NAME ) %}

Then you'll search for entries after the specific date

{% set newEntries = craft.entries.postDate('>= ' ~ yourTimeStamp)|length %}


Using modifyElementsQuery() to build a Radius Search? I am looking to build a radius search from my field type’s modifyElementsQuery() method.

I am storing lat/lng values in a separate table, and am trying to integrate the location search based on the following:

https://developers.google.com/maps/articles/phpsqlsearch_v3?csw=1#findnearsql

Here’s my current code. It throws an error saying "unknown column 'distance' in having clause".

public function modifyElementsQuery(DbCommand $query, $value)
{

    if($value !== null)
    {
        $settings = $this->getSettings();
        $this->plugin->pluginLog($value);

        $unitAdjustment = $settings->unit == 'mi' ? 3959 : 6371;
        $lat = 37;
        $lng = -122;
        $radius = $value;

        $query->addSelect('( '.$unitAdjustment.' * acos( cos( radians( '.$lat.' ) ) * cos( radians( fruit_geo.lat ) ) * cos( radians( fruit_geo.lng ) - radians( '.$lng.' ) ) + sin( radians( '.$lat.' ) ) * sin( radians( fruit_geo.lat ) ) ) ) as distance');
        $query->join('fruit_geo fruit_geo', 'fruit_geo.elementId = content.elementId');
        $query->having('distance < '.$radius);

        // Here's the SQL statement that will find the closest 20 locations that are within a radius of 25 miles to the 37, -122 coordinate.
        // It calculates the distance based on the latitude/longitude of that row and the target latitude/longitude,
        // and then asks for only rows where the distance value is less than 25, orders the whole query by distance,
        // and limits it to 20 results. To search by kilometers instead of miles, replace 3959 with 6371

        //SELECT id, ( $unitAdjustment * acos( cos( radians( $lat ) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians( $lng ) ) + sin( radians( $lat ) ) * sin( radians( lat ) ) ) ) AS distance FROM table HAVING distance < $radius
    }

}

Template errors:

CDbCommand failed to execute the SQL statement: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'distance' in 'having clause'. The SQL statement executed was: SELECT `elements`.`id`
FROM `craft_elements` `elements`
JOIN `craft_elements_i18n` `elements_i18n` ON elements_i18n.elementId = elements.id
JOIN `craft_content` `content` ON content.elementId = elements.id
JOIN `craft_fruit_geo` `fruit_geo` ON fruit_geo.elementId = content.elementId
JOIN `craft_entries` `entries` ON entries.id = elements.id
JOIN `craft_sections` `sections` ON sections.id = entries.sectionId
LEFT JOIN `craft_structures` `structures` ON structures.id = sections.structureId
LEFT JOIN `craft_structureelements` `structureelements` ON (structureelements.structureId = structures.id) AND (structureelements.elementId = entries.id)
WHERE (((((((elements_i18n.locale = :locale) AND (content.locale = :locale)) AND (elements.archived = 0)) AND ((elements.enabled = 1) AND (elements_i18n.enabled = 1) AND (entries.postDate <= '2015-02-06 11:57:46') AND ((entries.expiryDate is null) OR (entries.expiryDate > '2015-02-06 11:57:46')))) AND (elements_i18n.enabled = 1)) AND (content.field_date>=:contentfield_date1)) AND (sections.handle=:sectionshandle1)) AND (`elements`.`id` IN ('5747', '5823', '8529', '8865', '8913', '8972', '8973', '8978', '8979', '10228', '10370', '10912', '11780', '13366', '14673', '14675', '14759', '14764', '14770', '20516', '20682', '20683', '21042', '21043', '21143', '22247', '22570', '22814', '22817', '22827', '22830', '22834', '22835', '22836', '22844', '22855', '22859', '22860', '22867', '22899', '22909', '22916', '22945', '22970'))
GROUP BY `elements`.`id`
HAVING distance < 50
ORDER BY `field_date` ASC. Bound with :locale='en_gb', :contentfield_date1='2015-02-06 00:00:00', :sectionshandle1='events' (/var/www/vhosts/findarace.com/beta.findarace.com/craft/app/framework/db/CDbCommand.php:543)

#0 /var/www/vhosts/findarace.com/beta.findarace.com/craft/app/framework/db/CDbCommand.php(396): CDbCommand->queryInternal('fetchAll', Array, Array)

So it turned out that the distance column error was sending us down the wrong path.

The issue was caused by 2 things:

1) As the original Craft entries query was using ids() any select string added via addSelect was being disregarded, the answer here was to move this logic into the having clause.

2) The second issue that was preventing the having clause from working was a missing groupBy clause.

The modifyRadiusQuery code in full:

private function modifyRadiusQuery(DbCommand $query, $value)
{
    $settings = $this->getSettings();
    $measurementUnit = $settings->unit == 'mi' ? 3959 : 6371;

    $geo = craft()->logic->stringToGeo($value['location']);

    if($geo)
    {
        $haversine = $this->haversine($geo['lat'], $geo['lng']);

        // ids()
        $query->join(Logic_GeoRecord::TABLE_NAME.' geo', 'elements.id = geo.elementId');
        $query->having($haversine.' < '.$value['radius']);
        $query->group('geo.lat, geo.lng');

        // find()
        // $haversine = $this->haversine($geo['lat'], $geo['lng']);
        // $query->addSelect($haversine.' AS distance');
        // $query->join(Logic_GeoRecord::TABLE_NAME.' geo', 'elements.id = geo.elementId');
        // $query->having('distance < '.$value['radius']);
        // $query->group('geo.lat, geo.lng');
    }
}

The DBCommand query that was fixed:

        $query->join(Logic_GeoRecord::TABLE_NAME.' geo', 'elements.id = geo.elementId');
        $query->having($haversine.' < '.$value['radius']);
        $query->group('geo.lat, geo.lng');


How can I add in new Locales to the locale list? I have a site that has a few different countries that speak the same language but want to have them as different Locales.

Mexico (english)
Mexico (spanish)
USA (english)
USA (spanish)
Peru (english)
Peru (spanish)

These might all share some content but the manager of each region might want to change the content for their own region.

How can I add in new Locales in the locale list in Craft?

There are several locales that Yii comes with but Craft doesn't, simply to keep Craft's filesize down a bit (they add a lot of weight). You can see the master list of Yii locales here: https://github.com/yiisoft/yii/tree/master/framework/i18n/data   - If you see a locale in there you want that Craft doesn't come with, just view the raw version of the file on GitHub and then save it to your craft/app/framework/i18n/data/ folder. Then Craft will start supporting it.

If you need a locale that Yii doesn’t offer, find the closest locale Yii/Craft does come with, and copy it with a new name (e.g. en_us.php => en_mx.php).


Change name of Singles Is there an updated version for Craft 3 showing how to change the name of 'Singles' and 'Structures'? https://www.youtube.com/watch?v=ObC4mhXjiOE

Add a /translations/ folder to your project root and within that folder a /fill-in-locale-here/ folder. Add a file "app.php" to that /translations/fill-in-locale-here/ folder which returns an array of those translations. Here's an example => view screenshot


How flexible is tying content to a structure? I'm trying to decide how to organize my content on a site with a few levels of hierarchical content. I'm toying with the idea of creating structures for all my top level navigation items, with a few levels of nested content for sub-navs and sub-sub-navs.

My main concern is that if there are 100+ sibling entries deep inside one of my structures, how coupled are the entries to the hierarchy of the structure? Would I be able to later move that section to a completely different main navigation structure?

Or would I be better decoupling the a lot of my content into singles and smaller structures or channels, and sacrifice the relationships between the pages and the neat tree-like representation that gives clients a better overview of their site structure?

Structures simply add an extra bit of sorting and querying. You can look for entries in a structure the same way you look for entries in a channel. The difference is that you can also have parents and children in a structure with a manually set order.

If you look at the section page for a structure and hover over an entry, you will see a move handle. You can use that to resort your entries in any order you wish. You can also move the entries to become the child of any other entry. Taking three child entries of a top-level nav and moving them to another top-level nav is no problem.

How you organize your content is highly contextual. I don't know what kind of site you're building, so I can't say what's best for you. Most sites I've built thus far have only needed channels save for one. And for that one, I have two structures and two channels. I'm using one channel for news entries, and the other for event entries. I'm using a structure for static pages so I can sort them into a hierarchy (and it gives me breadcrumbs). I'm also using a structure for the main menu because it needs to be set up somewhat different than the static pages (and I need extra fields). This was all chosen based on the needs of my client's site. So just think about your client's needs. Will they be editing it? Is how you have it set up now easy for them to understand how to edit?


Date filtering returning wrong results - timezone issue? I'm running into an issue where incorrect results are being returned when filtering Craft Commerce orders by date in a template. Can anyone help? I cannot figure out what is going on.

FACTS:

Craft install is using America/Denver for timezone.
I'm passing dates via the query string with this format: YYYY-mm-dd
PHP version is 7.1.
Problem timestamp from the DB is (2017-11-10 00:14:04)... this doesn't match the screenshot below because I've been fiddling with dates.

This is my reduced code:

{% set start = "2017-11-09" | date('Y-m-d 00:00:00', 'America/Denver')  %}
{% set end = "2017-11-09" | date('Y-m-d 23:59:59', 'America/Denver') %}
{% set orders = craft.commerce.orders.dateOrdered('and', '>= ' ~ start, '<= ' ~ end).find() %}

{% for order in orders %}
    {{ order.dateOrdered | date('Y-m-d H:i:s e') }}<br/>
{% endfor %}

This is the returned data with the incorrect entry:

Essentially you're running into this same issue: Using user-selectable timezones to show localized post dates

Not terribly pretty, but as a workaround, you can do something like this:

{% set start = date("2017-11-09 00:00:00")|date_modify("+7 hours")|date('Y-m-d h:i:s')  %}
{% set end = date("2017-11-09 23:59:59")|date_modify("+7 hours")|date('Y-m-d h:i:s')  %}

{# +7 hours is because America/Denver is UTC-7, but would need to be adjusted to +6 hours when observing daylight savings time #}

{% set orders = craft.commerce.orders.dateOrdered('and', '>= ' ~ start, '<= ' ~ end).find() %}

{% for order in orders %}
    {{ order.dateOrdered | date('Y-m-d H:i:s e') }}<br/>
{% endfor %}

Also, note that this should "just work" in the upcoming Craft 3 as well.

There might be a cleaner way to do this using @carlcs's workaround, but I'm not seeing it at the moment.


Is it possible to POST to an action if the system is offline? There are easier ways to do this for sure, but...

I have the Mailchimp Subscribe plugin installed to build our email list etc... and it works perfectly!

However, we are now building a "Coming Soon" page with the site turned off to the public while we build out the site.

Is it possible to accept a certain action while the system is offline so that the POST request is accepted and doesnt return a 503 error?

Again, this is possible through using just a Mailchimp form itself but I'm interested to see if this sort of thing is possible if I ever needed this sort of control in the future.

Completely untested, but something like this in your craft/config/general.php file should work:

return array(
   'isSystemOn' => (isset($_REQUEST['action']) && !$_REQUEST['action'] != 'mailchimpSubscribe/list/Subscribe'),
);


How can I prevent my client from auto-updating Craft in production? How can I prevent my client from auto-updating Craft in production? I don't want them to run Craft updates on the production site, but the "updates" badge seems irresistible to them. I would prefer to run Craft updates in my dev environment, version control with Git, test, and then deploy at my leisure.

You can use the config/general.php file to specify whether auto-updating is allowed:

Craft 2

'allowAutoUpdates' => false

  https://docs.craftcms.com/v2/config-settings.html#allowAutoUpdates

Craft 3

'allowUpdates' => false

  https://docs.craftcms.com/api/v3/craft-config-generalconfig.html#property-allowupdates

Combined with a multi-environment configuration, this can be very helpful.

Admittedly, this doesn't prevent the "Updates are available" notification from appearing... There have been some discussions about future versions of Craft possibly adding a separate config setting which will allow you to disable that notification as well.


Custom or complex nav tag Is it possible to build something like this with a structure and the {% nav %} tag?

         Dropdown

                    ...

This is my code for now:

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

      {% nav entry in entries %}

            {{ entry.title }}

            {% ifchildren %}

                  {% children %}

            {% endifchildren %}

      {% endnav %}

The problem is, i need custom html inside the children

You'll want to make use of the level property of your entry...

{% if entry.level == 1 %}
    <!-- Top Level Links -->
{% else %}
    <!-- Child Links -->
{% endif %}


Structure Navigation - Not returning sub nav entries I'm trying to set up a sub nav from a Structure Section on my site.

Current code is:

{% set mainEntry = craft.entries.slug(craft.request.getSegment(1)).first() %}
{% set subnav = craft.entries.descendantOf(mainEntry).level(2) %}

{{ subnav.total() }}

But my when loop through sub nav below it returns nothing.
I am outputting subnav.total above but it is returning 0, but there is a lot of entries  in the CMS.

mainEntry gets loaded with the correct info ok, but I don't get anything in subnav.

Is there a chance that you're getting the another entry with the the same slug as your mainEntry? I'd try to further filter it down by adding section() for example.

As I wrote in the comments, try to loosen the second ElementCriteriaModel by removing the level parameter.

Another idea would be to use the dump() function on your mainEntry (only works with dev-mode turned on).


Sections, Categories, and EntryTypes. Which, when? bit of a 'best practice' question, as I'm very sure there are many ways to do this sort of thing, but...

When/how do you decide whether to use a section, category, or entry type to organise your entries? I've been finding that my EntryTypes match 1:1 to the categories in my 'global' group, and that's lead me to wonder if there's any point in having them as global categories too, and whether I'm just not understanding how to use these tools properly.

For example, I've got sections: webDevelopment, generalWriting.

And categories (in a global group): Article, Tutorial, Links.

And EntryTypes in each section: Article, Tutorial, Links.

It's starting to look like there's little point in having global categories, but not having categories feels very weird / wrong.

So... how do you decide how to organise your stuff?

Sections are for completely separate areas of content. They have their own URLs, and are conceptually different. Like blog posts and press releases would be different sections. Your sections could easily be one section with a different set of categories defining web development and general writing. This is entirely up to you.

Categories are for separating entries into smaller groups. Your use of categories is correct. You just use it to categorize entries.

Entry types are when you have common content that require different field layouts. Think Tumblr and how it has one stream that shows text, pictures, links, and quotes as separate types. For your setup, if no entry will be both an article and a tutorial at the same time, you can remove the tutorial entry type and simply use the article one. Then in your template, use the category to decide how to lay it out. The link has a different field layout so it can stay separate.


Getting `modifyUserSortableAttributes` to work during plugin development I have a plugin that is creating a custom field. I am using the modifyUserSortableAttributes method to make my field appear in the columns available for the Users Table and wanted to be able to sort and filter by this column. The field values is stored as a simple alphanumeric string.

More on hook/method at https://craftcms.com/docs/plugins/hooks-reference#modifyUserSortableAttributes

Call in plugin code is:

public function defineAdditionalUserTableAttributes()
{
    return array(
        'institution' => "Institution"
    );
}

public function modifyUserSortableAttributes(&$attributes)
{
    $attributes['institution'] = Craft::t('Institution');
}

However, when I use this method whilst I can add the requisite column to my User table in the admin area and sort the fields alphabetically in ascending order I cannot sort the table by descending order. No errors turning up in the console or site logs. Any suggestions on resolving or debugging greatly appreciated.

Regards,

Cole

The underlying issue you're running into is this, which is an issue on both Craft 2 and 3 currently: https://github.com/craftcms/cms/issues/859

Can't think of a clean way to work around it, either.


Order grouped entries I need to group and order member profiles alphabetically but I can't get it to work. Have a look here: http://ffsd.de.w0129b45.kasserver.com/mitglieder
(It's german but you should get the idea :))

In everything I tried either the groups are ordered correctly or the contents (profiles) of the group are… but never both. Here's the relevant code:

{% set allProfiles = craft.entries.section('members').order('profileLastname').limit(null) %}
{% for letter, profiles in allProfiles|group("profileAlphabet") %}

                    {{ letter }}

        {% for profile in profiles %}

{{ profile.title }}

        {% endfor %}

{% endfor %}

As you can see, I'd like to order the profiles by the custom field "profileLastname" and the groups by "profileAlphabet".

Any ideas?

The probably most easy way to do this is to sort the grouped array by key, which unfortunatelly is only possible with
a plugin, as Twig's sort filter only allows to sort by value.

Here I'm using Michael Rog's Supersort, but there are also other plugins that do this.

{% set allProfiles = craft.entries.section('members').order('profileLastname').limit(null) %}
{% set allProfilesGrouped = allProfiles|group("profileAlphabet")|supersort('ksort') %}


How to add a conditional elements into the title of a page? I need to set the page title like this:

{% if entry.artistFirstName | length %}
    {{ entry.artistFirstName | capitalize }}
{% endif %}

{{ entry.title | capitalize }}

So if a first name is set I need to display it, but if not I only need to display the entry's title.

Here is one of the solutions I've tried but unfortunately does not work:

{% set title = {% if entry.artistFirstName | length %}
    {{ entry.artistFirstName | capitalize }}
{% endif %}

{{ entry.title | capitalize }} %}

It does not seem possible to define something in something that is being defined. Any idea how to get around this?

I suggested an edit to Jamies suggestion (hope that's okay - don't know all the rules yet).
Here's the suggestion

{% set title = (entry.artistFirstName) ? [entry.artistFirstName, ' ', entry.title]|join : entry.title %}
{{ title | capitalize }}

Here i'm joining the two variables if entry.artistFirstName exists, by first putting all the parts into an array, and then using the join filter to glue them together. I like this approach, because it's easy to add many parts without having to put ~ ' ' ~ for every space you need.

In general, if you want to glue strings like this together, you use the ~ operator, like this:

{{ 'string1' ~ 'string2' ~ 'string3' }} -> {{ string1string2string3 }}

An alternative approach to the one I suggest above is therefore like so:

{% set title = (entry.artistFirstName) ? entry.artistFirstName ~ ' ' ~ entry.title : entry.title %}

This is just as fine, but the first approach might be nicer if you have more parts.

A third way is this, which might be just as nice/clean, but maybe slightly less readable?

{% set title = (entry.artistFirstName) ? '%s - %s'|format(entry.artistFirstName, entry.title) : entry.title %}


Can I have a textarea field which isn't rich text? I have a rich text field that I don't want wrapped in anything.

I just want a text area field, but I'm not sure how to get a text area without making it rich text, as the only multiline text field is the rich text field.

If it is going to be rich text, I need to be able to remove wrapping tags and control those.

If what you want is a multi-line plain text field, then check the Allow line breaks checkbox for that field.


Is it possible to use the assets modal on the front end? Part 3 of a 3 part question:

I am creating a proof of concept for a client in Craft where the client's customers can manage projects from the frontend of a Craft install.

A missing piece to the puzzle for full management is being able to give the user access to the assets modal and asset relationship field so they can better manage the files that are associated with the entry. Ideally they would be able to edit a field with existing content with the ability to associate new files or remove them all together (while still preserving the file in the upload directory, for this use case).

Is it possible to access the asset modal and manage the relationship field from the front end?

Craft supports all of the fields within the Control Panel, but not on the front-end – the number of scenarios they would need to support on the front-end increases the scope of supporting a field dramatically.

Craft does however support submitting Assets from the front-end (an example with Guest Entries) and restricting Assets to user specific folders using Dynamic Subfolder Paths.

So you can do what you are describing, and may even be able to reuse some of the code they use to build out the functionality, but (currently) you will have to adapt it to your scenario and maintain it yourself.


File empty on all asset uploads I've already adjusted the php.ini with max values for timeout and file size. This is really perplexing me. I'm on Dreamhost VPS. I've triple checked all file permissions. I consistently get this error: "Upload failed for brooklyn_bridge.jpg. The error message was: “Error uploading the file: Uploaded file was empty" no matter what I try.

Here was a recent error after turning devmode on:

$_FILES=array (
  'assets-upload' =>
  array (
    'name' => 'brooklyn_bridge.jpg',
    'type' => '',
    'tmp_name' => '',
    'error' => 6,
    'size' => 0,
  ),
)

$_COOKIE=array (
  'b8d03c16c0ad94ea360e045e078389acusername' => 'fef6a177a0a30714376a5da4ec0d0f325256546as:60:"19b3e1b40c907258470bb0eada9aea0a67c491cdczo2OiJqb3NodWEiOw==";',
  'CraftSessionId' => 'XgGRKqGqqi1,Yosu0A37i0',
  'b8d03c16c0ad94ea360e045e078389ac' => 'dfb0e07d4a3e09dd9d62a5b04372e50bb9480660s:396:"315becd5240726fc3c5e92aca8e9c9b29fc61fdfYTo2OntpOjA7czo2OiJqb3NodWEiO2k6MTtzOjMyOiJIelM3UzhNWER0ODNlbEdmRUlTUXhORnFXOVFrRVUzbiI7aToyO3M6MzY6IjM4MmM2YzllLTY3NjItNGNiMy1iNjkzLTAxZjZmODQ2MTRmZiI7aTozO2k6MDtpOjQ7czoxMjE6Ik1vemlsbGEvNS4wIChNYWNpbnRvc2g7IEludGVsIE1hYyBPUyBYIDEwXzExXzUpIEFwcGxlV2ViS2l0LzUzNy4zNiAoS0hUTUwsIGxpa2UgR2Vja28pIENocm9tZS81MC4wLjI2NjEuMTAyIFNhZmFyaS81MzcuMzYiO2k6NTthOjA6e319";',
)

$_SESSION=array (
  'b8d03c16c0ad94ea360e045e078389ac__id' => '1',
  'b8d03c16c0ad94ea360e045e078389ac__name' => 'joshua',
  'b8d03c16c0ad94ea360e045e078389ac__states' =>
  array (
  ),
  'b8d03c16c0ad94ea360e045e078389ac__timeout' => 1465416905,
  'b8d03c16c0ad94ea360e045e078389ac__auth_access' =>
  array (
    0 => 'uploadToAssetSource:36',
  ),
  'assetsSourcesBeingIndexed' =>
  array (
    0 => '1',
  ),
  'assetsMissingFolders' =>
  array (
  ),
)

It was an issue with the /tmp folder filling up. Have to regularly make sure it's emptied. If the /tmp folder has proper permissions this should happen automatically.


How do I access table field type value? I'm going through(learning) class reference TableFieldType in Craft 2 and I'm having trouble pulling out the value from a table field and save it as variable. I'm not sure I've started with the right approach.

This is the piece of code I'm working on where contact details are saved to the table field. The problem starts when I need to get the email address value from that table field and use it further on.

public function init()
{
    craft()->on('guestEntries.success', function (GuestEntriesEvent $event)
    {

        /** @var EntryModel $entryModel */
        $entryModel = $event->params['entry'];

        if($entryModel->getSection()->handle === "orderId")
        {

          $emailSettings = craft()->email->getSettings();
          $email         = new EmailModel;
          $emailAddress = '';

          // Questionable, not complete block of code
          // Get value of "emailAddress" singleline type column from the "contactDetails" table field type
          foreach ($entryModel->getFieldLayout()->getFields() as $fieldLayout)
          {
            $field = $fieldLayout->getField();

            if ($field->getFieldType()->getName() == Craft::t('Table'))
            {

              foreach ($entryModel->{$field->myHandle}-> ??? as $input)
              {
                 $emailAddress = $input->???;
              }
            }
          }

          $email->toFirstName = $entryModel->getAuthor()->firstName;
          $email->toLastName  = $entryModel->getAuthor()->lastName;

          // Test if email address from "contactDetails" table field is present
          $email->toEmail     = !empty($emailAddress) ? $emailAddress : $entryModel->getAuthor()->email;

          $email->fromEmail   = $emailSettings['emailAddress'];
          $email->replyTo     = $emailSettings['emailAddress'];
          $email->sender      = $emailSettings['emailAddress'];
          $email->fromName    = craft()->config->get('siteName');
          $email->subject     = craft()->config->get('siteName') . " - New order received";
          $email->body        = "...";
          craft()->email->sendEmail($email);

        }

    });
}

You can grab the content of a field for an element with

$myTableField = $entry->getContent()->getAttribute('fieldHandle');

You can modify the variable and send it back with

$entry->getContent()->setAttribute('fieldHandle', $myTableField);

Since you are probably in an event you should make sure your entry has the correct type and the correct section

$entry->getSection()->handle === 'mySectionHandle' && $entry->getType()->handle === 'typeHandle'

If you want to change every table field and not just a certain one you can do

foreach($entry->getFieldLayout()->getFields() as $field){
    if($field::class === 'insert the class of the field here'){
        $table = $entry->getContent()->getAttribute($field->handle);
   }
}


Individual Content dripping per user I am building a site where I need to give each individual user access to site content according to the user progression of content consuming.

For the example, User A has access to watch entry no.1, than only a week later, he can get access to entry no.2 and so on.

What would be the best approach for to create such hierarchy in Craft 3?

Thank you for any hint!!

You'd most likely need to write a custom plugin. I think it might be doable (but maybe not advisable) with Twig.

The plugin would contain an array of the entries in the sequence. How you specify this is up to you. It could be from within plugin settings, or a specific entry, or even just hard coded into your plugin.

Then you need to create some way to store user ids against the last entry they watched and a date. Perhaps in a database table created by your plugin. Alternatively each user would have a custom field on their profile that contained the ids of the last entry they viewed plus the date they watched it.

When visiting the url for an entry, there is a check performed against that field.
If this is the next entry in the sequence, and sufficient time has passed since they viewed the previous entry then allow them access. Also update the database table (or their hidden profile field) with the new entry ID and current date.

It's really down to scoping out the exact way you want it to work, not worrying about the method or code involved. Once you've got that you can determine how to write the plugin.


Not All Entries showing in feed page but do show in Page Source XML Creating an RSS feed in craft and I have it to loop through all the entries via:

    {% set sermons = craft.entries.section('sermonEntry').limit(null).find() %}
    {% for sermon in sermons %}

On my feed url (example.com/feed) I can only see 17 of my entries. However when I view the page source. I see all of my entries in XML format (roughly 31 entries)

Anyone have an idea why this may be? Or if it will affect my podcasts that go to itunes?

I am not sure if there is a limitation on atom or rss with craft but I have seen 100's of entries on a rss feed page so maybe I am overlooking something?

Any help is appreciated. Thanks!

I accidentally had loop inside of the description tag which strangely caused only 17 entries to post to the RSS feed. Below is an example of what was causing the issue:

<description><![CDATA[
  {% set speaker = craft.categories.group('speaker').relatedTo(entry).find() %}
  {% for name in speaker %}
  A Sermon from {{ entry.sermondate | date("l, F j, Y") }}: {{ entry.title }} by {{ name.title }}]]></description>
        <category>Podcasts</category>
        <category>Christianity</category>
        <author>{{ name.title }}</author>
        <itunes:explicit>No</itunes:explicit>
        <itunes:author>{{ name.title }}</itunes:author>{% endfor %}

After I set it outside the Description tag if gave me all my entries on the RSS feed. Here is my final feed code:

    <?xml version="1.0" encoding="utf-8"?>
    <rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0">
    <channel>
    <title>Sermons at Example Church</title>
    <atom:link href="{{ url() }}" rel="self" type="application/rss+xml" />
    <link>http://www.examplechurch.org/sermons/</link>
    <description>Weekly morning sermons from Example Church in Sab Diego, CA. For all of our sermon archives, please visit http://www.example.org/sermons.</description>
    <lastBuildDate>Sun, 17 Sep 2017 00:00:00 -0600</lastBuildDate>
    <language>en-us</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <itunes:author>Example Church</itunes:author>
    <itunes:summary>Weekly morning sermons from Example Church in Sab Diego, CA. For all of our sermon archives, please visit http://www.example.org/sermons.</itunes:summary>
    <itunes:owner>
      <itunes:name>Example Church - San Diego, California</itunes:name>
      <itunes:email>web@examplechurch.org</itunes:email>
    </itunes:owner>
    <itunes:explicit>No</itunes:explicit>
    <itunes:category text="Religion &amp; Spirituality">
    <itunes:category text="Christianity"></itunes:category>
    </itunes:category>
    <itunes:category text="Health"></itunes:category>
    <itunes:category text="Society &amp; Culture"></itunes:category>
     {% if podcastImage.podcastimage|length %}
    <itunes:image href="{{ podcastImage.podcastimage.first.getUrl() }}"></itunes:image>
     {% endif %}
    {% set entries = craft.entries.section('sermonEntry').limit(null).find() %}
     {% for entry in entries %}
    <item>
      <title>{{ entry.title }}</title>
      <link>{{ entry.url }}</link>
      <pubDate>{{ entry.postDate.rss }}</pubDate>
       {% set audio = entry.audio.first() %}
       {% if audio %}
      <enclosure url="{{ audio.url }}" type="audio/mp3"></enclosure>
       {% endif %}
      <guid>{{ entry.url }}</guid>
       {% set speaker = craft.categories.group('speaker').relatedTo(entry).find() %}
      {% for name in speaker %}
      <description><![CDATA[A Sermon from {{ entry.sermondate | date("l, F j, Y") }}: {{ entry.title }} by {{ name.title }}]]></description>
      <category>Podcasts</category>
      <category>Christianity</category>
      <author>{{ name.title }}</author>
      <itunes:explicit>No</itunes:explicit>
      <itunes:author>{{ name.title }}</itunes:author>{% endfor %}
      <itunes:keywords>Example Church,Sermons,Christianity,Jesus Christ,Bible Teaching,Discipleship,Service</itunes:keywords>
     </item>
     {% endfor %}
   </channel>
   </rss>


order by Table Number Field % set entriesList = craft.entries.section('parks').relatedTo(entry.Line.one()).all %}
    {% if entriesList|length %}

            {% for entry in entriesList %}

{{entry.title}}

            {% endfor %}

    {% endif %}

Every Element has a Table where a Number is set
I want to order it by the Number. How can i do it?

Thanks

orderBy() should do the trick.
The docs show following syntax: .orderBy('elements.dateCreated asc')

Maybe something like:

{% set entriesList = craft.entries.section('parks')
   .relatedTo(entry.Line.one())
   .orderBy('elements.tableName.row(n).columnName asc')
   .all
%}


Stay on the same page after logout Is it possible to stay on the same page after logging out from the frontend, assuming that guests can still view that page?
By default, when logging out we are redirected to the homepage or some specific page set with postLogoutRedirect config setting.

Yep, postLogoutRedirect can be set to a function instead of a static value. So for example, in your template you can generate a hidden field in your logout form (or append a querystring parameter to the logout URL) that contains the path of the current page. Then set this in your general.php:
'postLogoutRedirect' => function($siteHandle) {
  return Craft::$app->request->getParam('myLogoutPathParameterName', '/');
}

This defaults to the homepage ('/') if the parameter is not found.


Counter for entries to show most read Articles How can I add a counter or something similar to my entries, so that I could loop through the most read articles?

Updated: There is an Entry Count plugin that is designed to do exactly this, written by Ben Croker. Thanks Ben!


Calling action from main class init() I'm trying to call an action from my main class in Craft 3. This is working fine with my services like this:

AbandonedCart::$plugin->serviceExample->serviceMethod();

I've tried to do something similar for my action but it doesn't work and I can't find any solution to it.

AbandonedCart::$plugin->actionExample->actionFunction();

Any ideas on how to do this?

Thanks in advance,
Sam

You need to call your setComponents function before you are trying to access your components otherwise - logically - they are not defined

public function init()
{
    parent::init();
    self::$plugin = $this;

    // define the components / services
    $this->setComponents(
        [
            'serviceExample' => ServiceExample::class
        ];
    );

    // access them
    $this->serviceExample->serviceMethod();
    // if it's easier for you to remember you can as well use the longer/slower syntax
    AbandonedCart::$plugin->serviceExample->serviceMethod();
);


ServiceUnavailableHttpException on front end, and 404 on admin Trying to get started with Craft CMS 3 for the first time, and it's running locally via Valet. from the front end, I get:

> HTTP 503 – Service Unavailable – craft\web\ServiceUnavailableHttpException

And on the admin side, I'm getting a 404. I've looked at similar questions, but none of the answers are helping me. I've set this up twice following this article on running Craft with Valet, and gotten the same result both times.

It turns out it was because I had Apache running and on port 80. I saw something about this somewhere in the guides I followed, but forgot to come back and stop Apache. Oops.


CRAFT_CSRF_TOKEN is failing to write Seeing some odd behavior in Chrome where we can no longer log into our dev site, which is currently served over HTTP.  But, if we try logging in using an incognito window, it works.  It looks like the CRAFT_CSRF_TOKEN cookie is not getting written - error message in the console (under headers->set-cookie) is "This Set-Cookie was blocked because it was not sent over a secure connection and would have overwritten a cookie with the secure attribute". Have cleared out all cookies, but this does not help.  The login DOES work using an incognito window, but hoping to be able to get it working on a regular window as well, if possible.

Ok - think I figured this out.  Our dev site is hosted on a sub-domain of our production site, which is served over HTTPS.  Seems like the CRAFT_CSRF_TOKEN
cookie set by our production site is the same that's trying to be set by our dev site, and since dev is served over HTTP, it's unable to overwrite the one set by the production server.  Clearing out cookies on production fixed the problem. I imagine setting up HTTPS on dev would also do the trick, but clearing the prod cookie is a quicker fix at the moment.


Best SEO plugin for Craft CMS - SEOmatic vs SEO plugin SEOmatic vs SEO plugin (https://github.com/ethercreative/seo) - which one is better? Ignoring the fact that one is paid and one is free.

I'm creating a blog site and I need to also implement SEO related functionalities.

I have used SEOmatic for years on Craft 2, but since it became a paid plugin on Craft 3 I trialled other SEO plugins.

I realised the extra work needed to make other plugins have a result like SEOmatic's wasn't worth the time over the extra cost to install SEOmatic and be on my way.

I'd recommend SEOmatic, but if you have the time to make a free SEO plugin do what you need it to do, then go for it.


Ajax pagination not loading last entries if not equal to pagination number I've got ajax working on a page but if the number of articles is not exactly 3 (this is the pagination limit) then the remaining 1 or 2 entries do not get loaded. I'm not sure why or how to resolve this.

I used this post as a guide to my code.

My js code is here:

  {# set current url so we can page with the correct entries #}
  {% set current_url = "improve-your-club/topic/" ~ craft.request.getSegment(3) %}

  $(function () {

      // load the first page of entries
      var page = 1;

      // set this equal to pagination number
      var count = 3;

      // Get the total count that we set above
      var totalCount = $("#totalRelatedCount").val();

      $('#loadMore').click (function (e) {
          e.preventDefault();

          if(count < totalCount){
            $('#loading').fadeIn();

            $.get( "/{{ current_url }}/p"+page , function( data ) {

              $( ".remaining .feat-box-container" ).append( data );

              // this won't hide why not?
              $('#loading').fadeOut();

              // increase page
              page++;

              // Increment count by 3 entries
              count = (count) + 3;

              // Check if count is greater than or equal to the total count. If so hide the load more button.
                if(count >= totalCount){
                    $("#loadMore").fadeOut();
                    console.log('count is larger than total count');
                }

            });
          }// endif

      });
  });

I've recorded a gif showing that the page only loads the first 6 entries despite there being 8 entries available to load - dropbox link to gif (too large to upload here) https://www.dropbox.com/s/79datzwa2qktpi0/ajax.gif?dl=0

** link to pastebin with full template** https://pastebin.com/cNUJW4xr
removed google tags from this template but otherwise intact

This is just a math/logic error caused by:

// Increment count by 3 entries
count = (count) + 3;

if (count >= totalCount) {
    $("#loadMore").fadeOut();
    console.log('count is larger than total count');
}

Let's say you have a totalCount of 4.  If count was initially 3, then it will now be 6 and greater than totalCount and you bail, never loading the remainder of the results.

100% untested, but something like this should work:

$(function () {

  // load the first page of entries
  var page = 1;

  // set this equal to pagination number
  var count = 3;

  // Get the total count that we set above
  var totalCount = $("#totalRelatedCount").val();

  var diff = totalCount;

  $('#loadMore').click (function (e) {
      e.preventDefault();

      console.log('count is ' + count);
      console.log('total count is ' + totalCount);

      if (diff > 0) {
        $('#loading').fadeIn();

        $.get( "/{{ current_url }}/p"+page , function( data ) {

          $( ".remaining .feat-box-container" ).append( data );

          // this won't hide why not?
          $('#loading').fadeOut();

          // increase page
          page++;

          diff = totalCount % count;

          if (diff === 0) {
              $("#loadMore").fadeOut();
              console.log('count is larger than total count');
          } else {
              // Increment count by 3 entries
              count = count + diff;
          }

        });
      }

    });
});


An exception has been thrown during the rendering of a template ("") Struggling to debug this one.

The full log is as follows:

Next exception 'Twig_Error_Runtime' with message 'An exception has been thrown during the rendering of a template ("") in "book/poll-availability" at line 4.' in /var/www/craft/app/vendor/twig/twig/lib/Twig/Template.php:355
Stack trace:
#0 /var/www/craft/app/vendor/twig/twig/lib/Twig/Template.php(314): Twig_Template->displayWithErrorHandling(Array, Array)
#1 /var/www/craft/app/vendor/twig/twig/lib/Twig/Template.php(325): Twig_Template->display(Array)
#2 /var/www/craft/app/vendor/twig/twig/lib/Twig/Environment.php(293): Twig_Template->render(Array)
#3 /var/www/craft/app/services/TemplatesService.php(223): Twig_Environment->render('book/poll-avail...', Array)
#4 /var/www/craft/app/controllers/BaseController.php(74): Craft\TemplatesService->render('book/poll-avail...', Array)
#5 /var/www/craft/app/controllers/TemplatesController.php(55): Craft\BaseController->renderTemplate('book/poll-avail...', Array)
#6 [internal function]: Craft\TemplatesController->actionRender('book/poll-avail...', Array)
#7 /var/www/craft/app/framework/web/actions/CAction.php(109): ReflectionMethod->invokeArgs(Object(Craft\TemplatesController), Array)
#8 /var/www/craft/app/framework/web/actions/CInlineAction.php(47): CAction->runWithParamsInternal(Object(Craft\TemplatesController), Object(ReflectionMethod), Array)
#9 /var/www/craft/app/framework/web/CController.php(308): CInlineAction->runWithParams(Array)
#10 /var/www/craft/app/framework/web/CController.php(286): CController->runAction(Object(CInlineAction))
#11 /var/www/craft/app/framework/web/CController.php(265): CController->runActionWithFilters(Object(CInlineAction), Array)
#12 /var/www/craft/app/framework/web/CWebApplication.php(282): CController->run('render')
#13 /var/www/craft/app/framework/web/CWebApplication.php(141): CWebApplication->runController('templates/rende...')
#14 /var/www/craft/app/etc/web/WebApp.php(279): CWebApplication->processRequest()
#15 /var/www/craft/app/framework/base/CApplication.php(184): Craft\WebApp->processRequest()
#16 /var/www/craft/app/index.php(62): CApplication->run()
#17 /var/www/public-imperialhotels/en/index.php(22): require_once('/var/www/craft/...')
#18 {main}
REQUEST_URI=/en/book/poll-availability?token=9923444c-13b4-41bb-b7ab-9e339277bacc&iframe=true&room-urns=

And the template in question looks like this:

{% set token = craft.request.getParam('search') %}

{% if (not craft.request.isAjax and not token ) %}
    {% exit 404 %}
{% endif %}

{% hook 'microsGetAvailabilityResults' %}

{% header 'Content-Type: application/json' %}

{% set data = {
    'complete': results.complete,
    'urn': results.urn,
    'pollUrl': craft.request.url ~ '?' ~ craft.request.queryStringWithoutPath
} %}

{{ data | json_encode | raw }}

So line 4 specifically is this:

    {% exit 404 %}

That should only be called if token is blank and as you can see from the REQUEST_URI, it should be set:

REQUEST_URI=/en/book/poll-availability?token=9923444c-13b4-41bb-b7ab-9e339277bacc&iframe=true&room-urns=

Any suggestions?

What's most frustrating is that this has been picked up in server log monitoring on a live box and we can't replicate it.

The template exits correctly if we hit the URL with a non-Ajax request and if no token is defined, so what gives?

You're searching in the URI for a param with a key called search:

{% set token = craft.request.getParam('search') %}

But the in the URI it's called token:

REQUEST_URI=/en/book/poll-availability?token=9923444c-13b4-41bb-b7ab-9e339277bacc&iframe=true&room-urns=

Therefore when it's not an AJAX request this passes:

{% if (not craft.request.isAjax and not token ) %}

And a 404 is thrown:

{% exit 404 %}


How do you use the Element API plugin to output Assets from Matrix block for an entry? I have Single Section(entry) with Matrix field which contains Assets in blocks. I'm trying to fetch assets from a single Matrix block.

My element-api.php code is:

<?php

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

return [
  'endpoints' => [
    'api/portfolio/<blockId:\d+>.json' => function($blockId) {
      return [
        'elementType' => MatrixBlock::class,
        'criteria' => ['ownerId' => '4351', 'fieldId' => '218', 'id' => $blockId],
        'pretty' => true,
      ];
    },
  ]
];

Part of output is:

   "join": [
            [
                "INNER JOIN",
                "{{%relations}} relations",
                [
                    "and",
                    "[[relations.targetId]] = [[elements.id]]",
                    {
                        "relations.sourceId": "4402",
                        "relations.fieldId": "219"
                    },
                    [
                        "or",
                        {
                            "relations.sourceSiteId": null
                        },
                        {
                            "relations.sourceSiteId": "1"
                        }
                    ]
                ]
            ]
        ],

so it looks like I'm trying to access related field id 219 which is Assets field inside Matrix block.

Fields structure:

Any ideas?

You need a transformer

'transformer' => function(MatrixBlock $element){
    return [
       'image' => $element->getFieldValue('assetFieldHandle')->one()->getUrl()
    ];
}


How to attach an order PDF in an order confirmation email? I am currently adding a link to download the order PDF in the confirmation email with {{ order.getPdfUrl() }} but also want this to be an attachment.

You can send an email via your plugin's init() function like so:

craft()->on( 'email.onBeforeSendEmail', function( Event $event ){
    $email = $event->params['emailModel'];
    $attachment = array(
        'path'     => '/var/www/public/assets/downloads/filename.pdf',
        'name'     => 'File Title',
        'encoding' => 'base64',
        'type'     => 'application/pdf'
    );
    $email->addAttachment($attachment['path'], $attachment['name'], $attachment['encoding'], $attachment['type']);
});

Obviously, you'll want to do some checks on the Event and pass that off to a service to determine the logic for what should actually be attached.


Get field of a Matrix in certain locale I need to get the content of a field in the Matrix of the English localization in my template. I already have the handle of that field for the current language, but I don't know how to get the English version for that field...

I found this for getting a field of a Matrix:

{% set fields = craft.sections.getSectionByHandle('news').getEntryTypes()[0].getFieldLayout().getFields() %}

But that works of course again only for the field in the current localization... which I already have.

You should be able to set the desired locale by adding .locale('en') to your code.

Like so:

{% set fields = craft.sections.getSectionByHandle('news').getEntryTypes()[0].locale('en').getFieldLayout().getFields() %}

Assuming you've got english defined as en.


Uploaded images are saving to the server's temp folder and throwing 500 errors I've got a wordpress site that is live and am building a craft site to replace it on a subdomain and am having a strange issue that I've never had with any other craft sites I've built. Sometimes when images are uploaded the craft site the upload fails and I get a 500 error which crashes everything on the server including the live wordpress site. This has happened several times and the only way I can fix it is by asking Bluehost support to clear the server's temp folder for me. They have told me that for some reason images are being saved in there and aren't getting cleared which is causing the error. It seemes to be happening randomly, some days it happens every time I try to upload, other days it happens only after a few hours. I've looked through both Craft's error logs and my server error logs and can't make anything out. I've been troubleshooting several causes:

Incorrectly defining the image directory?

Initially I was storing images in a public folder and pointing craft to it with "../assets" because index.php is in a subdomain folder. Then I put the assets folder in the subdomain folder and it seemed to be working fine, till it crashed again. So I don't think this would be causing the issue

Multiple users on the same account?

I've enlisted a handful of people to help me port over content from the wordpress site to the new craft site and I tend to get these 500 errors when we're all uploading stuff together. However there have been times when we can work for over an hour without any problems.

Some conflict with Wordpress or other old files?

I'm not super familiar with PHP, could some server-side configuration be screwing all of this up? I've also got lots of old sites on the server from past developers that I have no idea what they do. I'm planning on wiping them all after this craft site is up.

I've configured something wrong in Craft?

Maybe?

Thanks guys

Crappy shared web hosting?

That would be my guess. It seems imprudent to be developing a site on the same host as a live site, it has to share the (probably already stretched) resources available on a shared host and there isn't enough juice to run everything.

Solution? Get a $5 VPS, and see how it runs there. In my experience a properly configured $5 VPS will out-perform shared / managed hosting costing 5x the price. Most VPS can be billed by the hour/minute, so if you don't like it just cancel and you'll be charged only a few pennies.

Personally, I would recommend Linode + Serverpilot.

Both services can be cancelled without notice, so there's really no tie-in or big gamble.


/admin/install/ missing resource files (css/js 404) and is unstyled Has anyone else run into an unstyled /admin/install/ page? Inspector shows 404 on all css and js files and they are pointing to /admin/resources/*

Been searching around and it doesn't seem to be a common issue so I'm a bit stumped. (Trying to install on an ubuntu/nginx digitalocean droplet)

I'm currently staring at this screen:
![enter image description here][1]

Most likely an nginx config file issue.  There are some configs that are working for people here: What is the recommended Nginx configuration for Craft?


Carry address over with customer's order when creating user When a user is created with the same email as a customer, the orders are attached to that user account. I have a Customer Info custom field attached to the Users, and that is updated to include the order, which is great.

Is it possible for the addresses within that order to be carried over to that same Customer Info field as well? I know that if a new address is added now they're a user then that would be saved. But what about carrying over addresses from the pre-existing order?

It's not implemented, but possible.  I think it should be part of Commerce core really, and done when the user is created by default.

In the meantime, my Register On Checkout plugin does this - https://github.com/bossanova808/CommerceRegisterOnCheckout

You could adapt this more generally I guess to listen to all user registrations and see if there are addresses to move over.

The actual code that updates the addresses is here: https://github.com/bossanova808/CommerceRegisterOnCheckout/blob/master/commerceregisteroncheckout/CommerceRegisterOnCheckoutPlugin.php#L312 ... but most of the init method would be relevant I guess.


Live Preview Items Without Entry URL This may be a silly question or a pipe dream, but i was wondering if there is a way to have a live preview for entries without a URL. For instance i have a complicated layered slider on the homepage of a site I am building and due to it's complexity it can not simply be a field or series of fields on the homepage entry, thus i've simply created a channel called 'slides' and I include that in my homepage template.

It'd be really great if there was someway to allow live-preview to show the slides while editing, or allow editing of them while in live-preview of the homepage.

Does this capability exist or am I out of luck?

It is (currently) not possible to set an Entry Template without selecting "Entries in this section have their own URLs" in the settings.
So to make Live Preview available on your "slides" entries, you have to register the URLs.
But if you use hidden / pseudo URLs (i.e. hideme/{slug}) that you don't link to and nobody knows of, this shouldn't be that bad of a workaround:

You can check if the page is shown with Live Preview using craft.request.isLivePreview.
Use this to redirect normal page views (search engines / accidential URL discoveries) to 404
and show your slider for Live Preview requests.
Set the Entry Template to the same file you use for your homepage or a new template file where you include the slider partial.

{# Conditionally show slider or redirect to 404 #}
{% if craft.request.isLivePreview %}
    {% include '_includes/slider' %}
{% else %}
    {% redirect 404 %}
{% endif %}

Live Preview doesn't only work for the Entry variable any more (→ Craft 2.3.2616 release notes). So you can make Live Preview to
update on changes detected on any entries referenced from the template.

EDIT: Unsaved entries are not yet included in such craft.entries calls (→ Brandon's comment to my question on g+). As a workaround you could do something like this:

_includes/slider.html:

{# Show unsaved "slider" entry #}
{% if not entry.id %}
    <li>{{ entry.title }}</li>
{% endif %}

{# Go through "slider" entries #}
{% for slide in craft.entries.section('slides') %}
    {{ slide.title }}
{% endfor %}

A dedicated field to set the template (or even multiple of them) used for Live Preview would make a nice feature request though! → done


404 errors on cpresources images i'm facing 404 errors for images related files in the control panel
like users photo, Login Page Logo, site Icon... etc...

for user photo for example i can edit the image, and i see it normally, but it is not visible on the my account page when craft try to reach
http://domaine.org/craft/cpresources/102e2477/thumb-100x100.jpg?v=1524146432

cpresources rights are 755

any help welcome :)

This has been fixed for the next release. Only affects environments where the web server is not sending missing resource requests (like /cpresources/XXXXXX/logo.svg) to index.php.


Locales sub directories on Nginx I'm trying to get a basic locals sub directory system working on Nginx:

/entry - en local.
/fr/entry - french translation.
/it/entry ect..

Having read this knowledge base article and some other forum posts I'm still having difficulties with 404 errors when following them or duplicate '/fr/fr'/entry issues.

Do I need to use duplicate index.php files with locals declared in them if I'm adding url paths in the section admin pages? What about site baseUrls in the config file?

The documentation seems very conflicting in these cases and having tried nearly every possible configuration option my site still won't serve up different locals.

I've had the most luck with this nginx config, together with specifying the local in the section urls in the cms for each section.

server {
    listen 80;
    server_name site.com;
    root /sites/site/public;
    index index.php;
    client_max_body_size 30M;
    location /en/ {
            root /sites/site/public;
            if (!-e $request_filename) {
                    rewrite ^/(.*)$ /index.php?q=$1 last;
            }
    }
    location /ru/ {
            root /sites/site/public/ru;
            if (!-e $request_filename) {
                    rewrite ^/(.*)$ /ru/index.php?q=$1 last;
            }
    }
    location /zh/ {
            root /sites/site/public/zh;
            if (!-e $request_filename) {
                    rewrite ^/(.*)$ /zh/index.php?q=$1 last;
            }
    }
    location / {
            root /sites/site/public;
            if (!-e $request_filename) {
                    rewrite ^/(.*)$ /index.php?q=$1 last;
            }
    }
    location ~ \.php$ {
            try_files $uri =404;
            fastcgi_split_path_info ^(.+\.php)(.*)$;
            fastcgi_pass unix:/var/run/php5-fpm.sock;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include fastcgi_params;
            fastcgi_ignore_client_abort on;
            fastcgi_param  SERVER_NAME $http_host;
    }

    location ~ /\.ht {
            deny  all;
    }
}

(each index.php has its own set local var within it like so for fr):

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

// Tell Craft to serve the local site
define('CRAFT_LOCALE', 'fr');

// Do not edit below this line

My General config is

<?php

/**
 * General Configuration
 */

return array(
    'siteUrl' => array(
        'en' => 'http://www.site.com/',
        'ar' => 'http://www.site.com/ar/',
        'es' => 'http://www.site.com/es/',
        'fr' => 'http://www.site.com/fr/',
        'hu' => 'http://www.site.com/hu/',
        'it' => 'http://www.site.com/it/',
        'ru' => 'http://www.site.com/ru/',
        'zh' => 'http://www.site.com/zh/',
    ),
    'maxUploadFileSize' => 2147483647,

    );

This results in the server displaying the correct links to my localised articles in the menu and the en language serves up entries correctly, however other languages are found at /local/local/entitypath not local/entitypath.

Adding site_urls to my config seems to break things more, causing locals to not be served up at all.

When you are following the each-locale-gets-its-own-index.php-file pattern as outlined in the official KB article, “How do I show localized content on the front end?”, then you do not need to include the locale ID in your sections’ Entry URL Format settings.

For example if you have a News section, and you want Arabic entries to get URLs that look like:

http://www.site.com/ar/news/my-entry-slug

Then the Arabic Entry URL Format should just be this:

news/{slug}

not this:

ar/news/{slug}

Everything leading up to “news/{slug}”, including “ar/”, is handled by your Arabic site URL, as defined in your config/general.php file’s siteUrl setting:

'siteUrl' => array(
    'en' => 'http://www.site.com/',
    'ar' => 'http://www.site.com/ar/',
    // ...
),


Connecting to REST API using Basic Auth The title pretty much says it all.

I'm trying to connect to a RESTful API within Craft templates to pull various showtimes, prices, availability, etc. of a theater. I have my URL endpoints and username & password but have no idea where they need to go in the templates. The API uses Basic Authentication. Everything I'm reading is PHP specific and I'm not quite sure how that translates to Craft/Twig.

I like the Rest plugin by Dukt (https://dukt.net/rest) but it uses OAuth.

Any help/direction would be appreciated.

I have built something similar so hopefully this will help get you rolling.

You are going to need to (or at least I would) create a plugin that you can call in your twig template. Pay special attention about creating a variable and services.

Let's say your plugin is called theater.
Let's also pretend you have a url "mysite.com/showtimes"

In your showtimes template, you would make a call to your theater plugin to get showtimes.

showtimes.twig

{# Get all upcoming showtimes from the api. #}
{% set showtimes = craft.theater.showtimes %}

I won't get into the specifics of building an entire plugin, but here are the main players you'll need.

First you'll need a file called TheaterVariable.php that has this:

TheaterVariable.php

<?php
namespace Craft;

class TheaterVariable
{
    /**
     * Get all upcoming showtimes from the api.
     *
     * @return mixed
     */
    public function showtimes()
    {
        $showtimes = craft()->theater->getShowTimes();

        return $results['data'];
    }
...

}

Now you'll need a file called TheaterService.php to do the real work of getting your showtimes.

TheaterService.php

<?php
namespace Craft;

class TheaterService extends BaseApplicationComponent
{
    /**
     * Get all upcoming showtimes from the api.
     *
     * @return \Guzzle\Http\EntityBodyInterface|string
     */
    public function getShowTimes()
    {
        try {
            error_log((craft()->config->get('devMode')) ? 'Getting all upcoming showtimes.' . '' : '');

            $client = new \Guzzle\Http\Client('http://your-api-domain.com/);
            $uri = 'api/api-endpoint';

            $request = $client->get($uri, array(
                'content-type' => 'application/json'
            ));

            $request->addHeader('Accept', 'application/json');
            $request->addHeader('Authorization', 'YOUR CREDS');

            $response = $request->send();

            return $response->json();
        } catch
        (\Exception $e) {
            if (craft()->config->get('devMode')) {
                error_log('Error: Could not get upcoming showtimes.');
                error_log($e->getResponse()->getBody());
            }
        }

    ...

    }
}

Finally, back to your showtimes template:

showtimes.twig

{% if showtimes|length %}
    {% for showtime in showtimes %}
        ...
    {% endfor %}
{% else %}
    {# Could not find any upcoming showtimes for some reason. #}
{% endif %}

I am using oAuth to handle my authorization, so that part might be a bit different for you. But in the big picture this should be pretty close.

Hope this helps!


Send to a friend that sends an email to a defined email of the users choosing using the contactForm plugin, I want to make a contact form, that sends to an email address of the users choosing, not the email set up in the admin.
Does anyone know the simplest way of doing this?

<input type="input" name="toEmail" value="">

https://github.com/craftcms/contact-form/tree/v1#dynamically-adding-email-recipients-requires-craft-25


Get entries by custom Users field value There is a set of entries:

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

Each entry has a custom field customUserField.  customUserField this is a field Users. How do you fetch entries where customUserField === currentUser?

Something like this should do it:

{% set entries = craft.entries.section('news').relatedTo({
    targetElement: currentUser,
    field: 'customUserField'
}).find() %}

More on the relatedTo method here: https://craftcms.com/docs/relations


Get entries where relation matches or is empty I have a channel section (tickets) where each entry has a members field. The members field can either be empty (making the entry 'public') or specific members can be added (making it 'private', to only the selected users).

I want to get a list of all the entries within the section where the members field is either empty or the currentMember has been added to the list, e.g. a member should see both public entries and private entries they have been added to.

I'm using the following to get all private entries for the currentMember, but I can't figure out how to make it include the public ones as well.

{% set tickets = craft.entries.section('tickets').relatedTo({
    targetElement: currentMember,
    field: 'members'
}) %}

For anyone that comes across this. Craft CMS has added this as a feature for next release.
https://github.com/craftcms/cms/issues/7256#issuecomment-744644568


Can I simply update from 2.6.2779 -> 2.6.2958, shared hosting Do I need to go through and install all the previous updates before installing 2.6.2958 (current 2.6.2779) OR can I simply use the instructions on this page https://craftcms.com/docs/updating and install version 2.6.2958.

Any recommendations would be appreciated since I have never used Craft before and/or done any installations/updates.

Thanks in advance.

Just make a backup of files and database first then click update (or upload a new /craft/app folder if you've got automatic updates turned off) - there are no breaking changes in Craft 2.6


How to create custom option/action for backend entry lists Please excuse me for the title.. I have no idea how to describe my problem better - if someone knows a better description for this question feel free to edit it.

I made a screenshot to clarify what I want to know.. Is it somehow possible to hook a custom option there?

I made an excel export for our customer and I would like to add an "export to excel" button there that sends an ajax request to my controller. Could you please explain me in detail how to do this?

Thank you very much

Edit
So thanks to your answers I created this test (just to see if I can add something)

<?php

namespace Craft;

class SRExcelExport_ExportElementAction extends BaseElementAction
{
    /**
     * Get element action name.
     *
     * @return string
     */
    public function getName()
    {
        return Craft::t('Export Files');
    }

    public function isDestructive()
    {
        return true;
    }

    public function performAction(ElementCriteriaModel $criteria)
    {
        // Remove all the ingredients from the selected elements
        $elements = $criteria->find();

        foreach ($elements as $element)
        {
            //do something
        }

        // Success!
        $this->setMessage(Craft::t('success'));
        return true;
    }

    public function getTriggerHtml()
    {
        $js = 'new Craft.ElementActionTrigger({' .
            'handle: '.JsonHelper::encode($this->getClassHandle()).', ' .
            'batch: true, ' .
            'validateSelection: function($selectedElements){ return true; }, ' .
            'activate: function($selectedElements){ alert("Made you click"); }' .
            '});';

        craft()->templates->includeJs($js);
    }
}

With the Plugin Handle SRExcelExport with the folder structure
srexcelexport
--elementactions
-----SRExcelExport_ExportElementAction.php

But nothing happens, the file is ignored, even a die() in the constructor does nothing. Do I need to do something to "call" the class myself or is there just a stupid error I made? I bet its just an obvious minor error I can't see right now

Indeed there is! You're looking for Element Actions...

  When you select elements on their index pages, the regular toolbar options get replaced with new ones that will trigger various actions, like batch-deleting all of the selected elements.

  That functionality is provided by Element Action classes.


Shortlist return URL working with the Shortlist plugin for Craft.

I'm trying to set the return URL after someone adds an item to their shortlist.

i assume thats what this parameter is for...

add item

however that takes the user to a 404 page with the url of

mydomain.com/index.php/actions/shortlist/item/my-page-i-want-to-go-to

any ideas?

As mentioned in the comments on the Question, the solution here is to enclose your desired path with a url() function like so:

add item

The url() function will take your current SiteURL and append the provided path. You can view the offical documentation about url() here.