How to copy Matrix from one entry to another in Craft 3 I've got $entryA with a Matrix field.

I want to programatically create a new $entryB and copy the Matrix field from $entryA to $entryB.  How do I go about this?

The blocks in a Matrix field are all elements, with their owner ID set to the corresponding entry. This is how you could copy them (untested):

use craft\elements\MatrixBlock;

foreach ($entryA->matrixFieldHandle->all() as $matrixBlockA) {
    $matrixBlockB = new MatrixBlock();
    $matrixBlockB->fieldId = $matrixBlockA->fieldId;
    $matrixBlockB->typeId = $matrixBlockA->typeId;
    $matrixBlockB->ownerId = $entryB->id;
    $matrixBlockB->siteId = $entryB->siteId;
    $matrixBlockB->enabled = $matrixBlockA->enabled;
    $matrixBlockB->sortOrder = $matrixBlockA->sortOrder;
    $matrixBlockB->setFieldValues($matrixBlockA->getFieldValues());

    Craft::$app->getElements()->saveElement($matrixBlockB);
}

Things can get tricky if you have multiple sites and the entries do or do not get propagated (etc), but this is how it works in a nutshell.

For the above code to work, you have to first save Entry B, to get an entry ID for it. So, create Entry B, fill 'normal' fields, save Entry B, create Matrix B, save Matrix B.


How do I apply taxes to subscriptions with Stripe plugin? I need to apply taxes to subscriptions. How do I do that? The idea is that prices are first shown without taxes. Then – on the payment page – I need some kind of "bill" that shows all the relevant infos and charges the correct price (subscription plus taxes):

Monthly Subscription    5€
VAT                  0,95€
--------------------------
SUM                  5,95€

Is that even possible with commerce-stripe at the moment?

Cheers,
Mark

I realise this is a bit of an old question, but I was faced with the same problem recently so I thought I'd document my solution here for anyone in the future that comes along needing to apply tax to a subscription in Craft Commerce.
There are two problems here:

Subscriptions aren't purchasables in Commerce at the moment, so they can't be added to a cart and have tax rates applied to them in the same way that you would with 'normal' products.
Subscription pricing is determined by Stripe rather than internally in Commerce, and the same is true of tax rates. There's no way of syncing or importing tax rates defined in Stripe into Commerce.

As far as I know, there is no out-of-the-box method in Commerce to apply tax to subscriptions automatically. It requires either manually adjusting subscription invoices within Stripe, or programatically adding a tax rate to a subscription before it's sent to Stripe. I chose the latter method.
Showing a bill before payment
I solved this by creating a single 'Subscription' product within Commerce, and then creating a number of variants on this product to represent the various subscriptions that I had defined in Stripe, including setting the prices to match those that are defined in Stripe. I added a custom field called subscriptionPlanHandle to the variant config to hold the handle of the subscription plan (handles for subscriptions are found in Commerce > System Settings > Subscription Plans), to allow me to fetch the correct subscription plan when creating the payment page.
Next, I set up a tax rate in Commerce, in my case VAT. I then set this tax rate to be applied to my subscription products - this can be done in Commerce > System Settings > Product Types and then edit the product type to set its Available Tax Categories (under the Tax & Shipping tab) to the relevant tax rate.
I then used the standard 'cart' approach to my purchase journey, showing my subscription products on a product page and allowing one to be added to the cart. A summary of the pricing was shown by looping through the contents of the cart and showing line item pricing followed by the tax adjustment and then a total:
{% set cart = craft.commerce.carts.cart %}

{% for item in cart.lineItems %}
    {% set itemsSubtotal = itemsSubtotal + item.subtotal %}

{{ item.description }}

{{ item.subtotal|commerceCurrency(cart.currency, stripZeros=true) }}

{% endfor %}

{% set totalPrice = itemsSubtotal %}

{% if cart.adjustments|length %}

Total

    {% for adjustment in cart.orderAdjustments %}
        {% set totalPrice = totalPrice + adjustment.amount %}

Excl. {{ adjustment.name }}: {{ itemsSubtotal|commerceCurrency(cart.currency, stripZeros=true) }}

Incl. {{ adjustment.name }}: {{ totalPrice|commerceCurrency(cart.currency, stripZeros=true) }}

    {% endfor %}
{% else %}

{{ totalPrice|commerceCurrency(cart.currency) }}

{% endif %}

Now, since subscriptions aren't purchasables in Commerce (yet), you can't just go through the normal checkout since the subscriptions won't be sent to Stripe. On the payment page/section, you have to do some juggling about to get the subscription plan UID from the product(s) in the cart and then create the appropriate payment form. Here's how I solved it:
<form method="post" accept-charset="UTF-8" novalidate>

    {{ csrfInput() }}
    {{ actionInput('commerce/subscriptions/subscribe') }}

    {% for item in cart.lineItems %}
        {% set variant = craft.variants().id(item.purchasableId).one() %}
        {% set plan = craft.commerce.getPlans().getPlanByHandle(variant.subscriptionPlanHandle) %}

        {{ plan.getGateway().getPaymentFormHtml({})|raw }}

        <input type="hidden" name="planUid" value="{{ plan.uid|hash }}">
    {% endfor %}

    <button type="submit">Pay</button>

</form>

This fetches the variant using the the item.purchasableId property, and then fetches the matching subscription plan using the custom subscriptionPlanHandle field mentioned above. A hidden field is then added to the form with the value of the plan's UID. The form can then be submitted to the subscription controller to set up the subscription.
Applying tax to a subscription
My solution requires either a custom module or plugin, so that you can listen to the EVENT_BEFORE_SUBSCRIBE event triggered by the Stripe gateway and modify the individual subscription item to add a tax code.
The steps to get this work are as follows:

In your Stripe account, you need to define a tax rate. You can do this by going to Billing > Tax rates in your Stripe dashboard, clicking 'New' and creating a new tax rate. In my case, I needed to apply VAT so I created a tax with a rate of 20%, named it 'VAT' and saved it. Next, you need to grab the ID of your new tax rate. Copy this to your clipboard - you'll need it in the next step.
Back in Commerce, find the appropriate tax rate in Commerce > Tax > Tax Rates. Paste the Stripe tax ID into the 'Code' field in Commerce. In my case, I turned on the 'Don’t apply this tax when the address has a valid VAT ID' option, as a simple way to identify that this rate was a VAT rate.
In your custom module or plugin, add an event handler in the main plugin file. This can either be directly in the init method or you could have a separate method to apply all of your event handlers that you invoke from the init method.

Here's the event handler code:
Event::on(
    StripeGateway::class,
    StripeGateway::EVENT_BEFORE_SUBSCRIBE,
    function(SubscriptionRequestEvent $event) {
        $taxRates = Commerce::getInstance()->getTaxRates()->getAllTaxRates();

        foreach ($taxRates as $taxRate) {
            if ($taxRate->isVat) {
                $event->parameters['items'][0]['tax_rates'] = [$taxRate->code];
            }
        }
    }
);

This event is triggered before a subscription is sent to Stripe, and allows you to modify the parameters that are sent to Stripe - like, say, to add in a tax rate!
The code inside the event handler gets all of the tax rates, then loops through each one until it finds one whose isVat property is set. It then adds a new tax_rates property to the first item in the items array (which should only have one property beforehand - the planId), and sets its value to an array containing the value of the code property from the tax rate.
Using the code property to hold the ID of the Stripe tax rate allows this data to be content-managed in Commerce, so that you can swap between test data and live data easily without requiring a code change. I'm not sure if there's another use for the code property within Commerce, but this worked for me.
This method is reasonably robust if you only need to apply a single tax rate like VAT, but if you need to charge lots of different tax rates it would need some modification to ensure the right tax rate is applied.
Note: these code examples don't deal with determining whether the VAT rate should be applied; you'll need to make sure that the VAT is only applied in the appropriate countries depending on the country set in the customer's shipping address.
Tidying up afterwards
This process should hopefully leave you with an active subscription in Stripe with the correct tax rate applied, but also an unfinished order since the subscription controller doesn't use the cart at all. I chose to handle this by listening to the EVENT_AFTER_CREATE_SUBSCRIPTION event and deleting the cart directly once the subscription was created.


Migrated Server, Now Getting Logged Out Constantly I just moved my site from one MediaTemple (gs) instance to another. I copied and recreated the database on the new server, moved over all the files, and updated the internal references that pointed to the old site. I even cleared out the 'craft/storage/runtime/' folder.

Whenever I am logged in, I almost instantly get logged out. Typically, this is after 30-60 seconds.

Whether or not I enter in the correct password, the same message comes back up. However, I can go back to the main admin page, and I'm still logged in.

Any ideas what's going on? It seems to be a caching and session issue of some sort, but there is no caching setup on our server, and I cleared my browser cache completely.

Most likely wherever Apache/PHP is configured to save session files doesn't exist or isn't writable.

If you've got the overridePhpSessionLocation config setting set to true, then that will be in craft/storage/runtime/sessions folder.


New Relic and Craft? I'd like to get Craft working with New Relic so I can play with my two favorite apps.  My web host (EngineHosting) got the New Relic daemons et al going; has anyone tackled getting the Craft side going so that it reports in?

Let me know, please? I may be doing some learning in order to do this integration down the line; but if someone has tackled it, I could dive right on in a bit more quickly.

Not quite sure what happened here; Brandon over at EngineHosting re-ran the installation and now I see my info in RPM.

So for future New Relic users that want to integrate with Craft on EngineHosting - at its most basic, ask EH to get New Relic installed for you.

Exciting!  Thanks @joshangell for the help.  Sometimes knowing it should just work is the key. :)

__

Editing as requested.  EngineHosting fully manages my site/server.  I don't have root via SSH so asked them to get the New Relic PHP agent installated (the agent installation requires root).  EH did install NR for me, but the first installation did not work and I do not know why.  When EngineHosting re-ran the installation, the PHP agent worked and Craft (and other PHP apps, mostly the 'index.php' file for each) started reporting to APM.

That's not helpful for people on cPanel or Plesk hosts, admittedly, nor is it helpful for people with root access doing their own installations.  But if you can get the New Relic PHP agent installed where Craft is, then it will report to APM.  Looking forward to getting more specific metrics from Craft to New Relic down the line, but that is not likely to come from me :)

With that very basic installation I get information like this:

I hope that helps.


How to filter entries in multiple category groups by selecting multiple categories This question is very similar to the question posted here I have asked in the comments but my requirements are slightly different. I am trying to filter search results by categories in more than one category group and use both an exclusive search (category AND category) and a non exclusive search (category OR category).

My use case is this: the parks category wants to filter using the OR filter so Park A OR Park B and so does the price filter so Price A OR Price B but when they are combined Park A AND Price B only show parks in the Price A category.

After a lot of back and forth and reading various posts on this I thought I would submit my answer. There maybe better ways of doing what I ended up doing but hopefully this will provide a start for someone wanting to do the same.

First here are a few posts and questions that helped:

Find entries with multiple categories with an and/or twist
How can I create an ElementCriteriaModel with 'and' and 'or'
Combined searches and filters using Craft

My Solution

First I created a search form that had the checkboxes for the search, each checkbox name when posted would form the get variable for the filter. A check is done to see if there are categories, if there are then I loop through and add them. There is also a check done to see if you are on the filter results page, if you are then set the relevant checkboxes to checked on the form.

The Search Form Code

<form action="{{ url('homes-for-sale/filter') }}" method="get">

  {# check if there are any park categories if there are then show them as checkboxes #}

  {% if parkCategories|length %}

    {% for category in parkCategories %}
      {% set loopIndex = 'park' ~ loop.index %}

        {# if you are on the filter results page then set the results to checked #}

        {% if template is defined and template == 'filter' %}
          <input type="checkbox" name="{{ loopIndex }}" value="{{ category.slug }}"{% if category.slug == park1 or category.slug == park2 or category.slug == park3 or category.slug == park4 or category.slug == park5 %} checked{% endif %}>
        {% else %}
          <input type="checkbox" name="{{ loopIndex }}" value="{{ category.slug }}">
        {% endif %}
        {{ category.navTitle }}

    {% endfor %}
  {% endif %}

  {# check if there are any price categories if there are then show them as checkboxes #}

  {% if priceCategories|length %}
    {% for category in priceCategories %}
      {% set loopIndex = 'price' ~ loop.index %}

        {# if you are on the filter results page then set the results to checked #}

        {% if template is defined and template == 'filter' %}
          <input type="checkbox" name="{{ loopIndex }}" value="{{ category.slug }}"{% if category.slug == price1 or category.slug == price2 or category.slug == price3 or category.slug == price4 or category.slug == price5 or category.slug == price6 %} checked{% endif %}>
        {% else %}
          <input type="checkbox" name="{{ loopIndex }}" value="{{ category.slug }}">
        {% endif %}
        {{ category.title }}

    {% endfor %}
  {% endif %}

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

</form>

The Filter Results Page

On the results page you need to check which filter variables have been set via the get request and then display the appropriate related entries.

{# set park search parameters #}
{% set park1 = craft.request.getParam('park1') %}
{% set park2 = craft.request.getParam('park2') %}
{% set park3 = craft.request.getParam('park3') %}
{% set park4 = craft.request.getParam('park4') %}
{% set park5 = craft.request.getParam('park5') %}

{# set price search parameters #}
{% set price1 = craft.request.getParam('price1') %}
{% set price2 = craft.request.getParam('price2') %}
{% set price3 = craft.request.getParam('price3') %}
{% set price4 = craft.request.getParam('price4') %}
{% set price5 = craft.request.getParam('price5') %}
{% set price6 = craft.request.getParam('price6') %}

{# set park category model if it is in the search query #}
{% set parkCategory1 = park1|length ? craft.categories.slug(park1).first().id %}
{% set parkCategory2 = park2|length ? craft.categories.slug(park2).first().id %}
{% set parkCategory3 = park3|length ? craft.categories.slug(park3).first().id %}
{% set parkCategory4 = park4|length ? craft.categories.slug(park4).first().id %}
{% set parkCategory5 = park5|length ? craft.categories.slug(park5).first().id %}

{# create an array of park categories #}
{% set parks = [
  parkCategory1,
  parkCategory2,
  parkCategory3,
  parkCategory4,
  parkCategory5,
] %}

{# create a park array and trim blank strings #}
{% set trimParks = [] %}

{% for park in parks %}
  {% if park|length %}
    {% set trimParks = trimParks|merge({ (loop.index0): park}) %}
  {% endif %}
{% endfor %}

{# set price category model if it is in the search query #}
{% set priceCategory1 = price1|length ? craft.categories.slug(price1).first().id %}
{% set priceCategory2 = price2|length ? craft.categories.slug(price2).first().id %}
{% set priceCategory3 = price3|length ? craft.categories.slug(price3).first().id %}
{% set priceCategory4 = price4|length ? craft.categories.slug(price4).first().id %}
{% set priceCategory5 = price5|length ? craft.categories.slug(price5).first().id %}
{% set priceCategory6 = price6|length ? craft.categories.slug(price6).first().id %}

{# create an array of price categories #}
{% set prices = [
  priceCategory1,
  priceCategory2,
  priceCategory3,
  priceCategory4,
  priceCategory5,
  priceCategory6,
] %}

{# create a price array and trim blank strings #}
{% set trimPrices = [] %}

{% for price in prices %}
  {% if price|length %}
    {% set trimPrices = trimPrices|merge({ (loop.index0): price}) %}
  {% endif %}
{% endfor %}

{% if trimParks|length and trimPrices|length %}
  {% set entries = craft.entries.section('homesForSale').relatedTo('and',
    {targetElement:parks},
    {targetElement:prices}
  ) %}
{% endif %}

{% if trimParks|length and not trimPrices|length %}
  {% set entries = craft.entries.section('homesForSale').relatedTo('or',
    {targetElement:parks}
  ) %}
{% endif %}

{% if trimPrices|length and not trimParks|length %}
  {% set entries = craft.entries.section('homesForSale').relatedTo('or',
    {targetElement:prices}
  ) %}
{% endif %}

Filter Results

{% if entries|length %}

{{ entries|length }} results:

        {% for entry in entries %}
          {% set park = entry.park.first() %}
          {% set price = entry.parkPriceCategory.first() %}

{{ entry.title }} :: {{ park }} :: {{ price }}

        {% endfor %}

{% else %}

Your search didn't return any results.

{% endif %}


Any cloud providers hosting and securing Craft as a service Are there any PaaS providers out there delivering Craft as a platform continuously updated and secured?

I'm not aware of any PaaS service that also keeps Craft up-to-date for you automatically.

There are some like Fortrabbit, that are PaaS and are very familiar with Craft installs, but you'd still be on the hook for updating Craft.

There are some more traditional, managed, non-PaaS hosts like ArcusTech that are also very familiar with Craft installs, and they keep the OS configured and secured for you are responsible for installing and updating Craft as well.

There is some more discussions about hosting options for Craft here:
Recommended hosting company for a Craft site?


Templates, Routes, and URL segments In EE, if there was a template /foo/bar.html, one could access the contents of that template by going to either example.com/foo/bar or example.com/foo/bar/more/segments/here. The additional URL segments didn't prevent EE from loading the most-accurately-matching template.

Moving over to Craft, bar is now an entry's slug. The section for that entry is properly set up with the "Entry URI Format" and "Template" pointing to foo/{slug} and foo/_entry.html, respectively. Is there a way to get the same "most-accurate" template-matching behavior in Craft? Perhaps with routes? I would want the {{ entry }} variable to be automatically available for either URL.

Yes and no.
Yes it is possible to include as many additional segments to selected routes and it's even possible to achieve what you want but it might become resource heavy and you would need to handle the entire routing on your own.

Channels

If it's for a channel with a set URI format like foo/{slug} you can implement a route like

Event::on(
    UrlManager::class,
    UrlManager::EVENT_REGISTER_SITE_URL_RULES,
    function(RegisterUrlRulesEvent $event) {
        $event->rules[] = [
            'pattern'  => 'foo/<uri:\S+>/<additionals:\S+>',
            'route'    => 'your-module/your-controller/route',
            'defaults' => [
                'additionals' => ''
            ]
        ];
    }
}

So all your urls like foo/{slug} as well as foo/{slug}/bar/whatever  will be routed to your controller YourController::actionRoute with the parameters

public function actionRoute(string $uri, string $additionals = null)
{
    $element = Craft::$app->getElements()->getElementByUri($uri);
    $template = (new Query())->select('template')
        ->from('sections_sites')
        ->where(['=', 'siteId', $element->site->id])
        ->andWhere(['=', 'sectionId', $element->sectionId])
        ->scalar();

    return $this->renderTemplate($template, ['entry' => $element]);
}

Note keep in mind this will only work if the uri format is rather simple like foo/{slug} it won't really work for things like foo/{author}/{category.id}/{slug}/{title} you'll need the rule mentioned in "structures" for it

Singles

If it's for singles you can do it dynamically

try {
    $uris = (new Query())
        ->select('uriFormat')
        ->from('sections_sites')-
        ->where(['=', 'siteId', Craft::$app->getSites()->getCurrentSite()->id])
        ->andWhere(['=', 'sectionId', [array of your section ids])
        ->column();
} catch (Exception $exception) {
    $uris = [];
}

if (empty($uris) === false) {
    $event->rules[] = [
        'pattern'  => '<uri:(' . implode('|', $uris) . ')>' . '/<additional:\S+>',
        'route'    => 'module/controller/action',
        'defaults' => [
            'additional' => ''
        ]
    ];
}

Structures

For structures it's not that easy... You would need to recursively remove one segment and try to search for a matching route if there is one, use it, otherwise remove the next one.

Attention pseudocode

$path = get your full path
while($element === null){
    $path = $path - lastSegment;
    $element = Craft::$app->getElements()->getElementByUri($path);
}
// attach the route `path` as you can see above

However I would not suggest the code above since it will search for a matching element for each segment for every request. I would highly recommend to include many conditions around it like Craft::$app->getRequest()->isSiteRequest() === true and $request->isAjaxRequest() === false and so on to reduce the amount of queries as much as possible


Sending email from GMail protocol I'm using AM Forms on a site that I've built. The site is now in production.

Via the AM Forms notifications settings, the email I've entered for Email recipients and Sender email address notification email is an email which is hosted with G Suite.

Am I correct in thinking that these notifications are being sent via Craft's email settings (currently PHP Mail)?

G Suite is running DKIM, SPF and DMARC, so the PHP Mail protocol is not the best method for receiving these notifications. If I change Craft's email protocol to GMail, how safe are the credentials I enter and are they encrypted?

Am I correct in thinking that these notifications are being sent via Craft's email settings (currently PHP Mail)?

Probably.  There are plenty of other reasons to not use PHP Mail on a production environment, though.

  If I change Craft's email protocol to GMail, how safe are the credentials I enter and are they encrypted?

If you select the "GMail" as an email delivery method in Craft, Craft sets the SMTP hostname to smtp.gmail.com, forces SMTP authentication over SSL over port 465 and passes in the given username/password.

No encryption is done because SSL is used, so the credentials are as safe as SSL is.


Best way to organise sections and templates I'm hoping this isn't too broad or long! I have two questions. I'm trying to streamline the organisation of my site.

Firstly: Currently, for every section of my website (e.g. website.com/housing , website.com/skiing, website.com/guitar) i have created separate structures for each one, with an index page in it with content entries being children of that index. The index template loops through children and displays links to each page.

Housing structure
  - index
    - entry
    - entry

I have seen some people saying they are putting all entries of the site in a single structure with hierarchy, e.g. one structure that has:

- Single Structure
  - housing
    - entry
    - entry
    - entry
  - guitar
    - entry
    - entry
  - skiing
    - entry
    - entry etc.

Is this a good idea? Is there any drawkbacks to the way i've done it? or is it a case of 'whatever works best for you'. It does make my Entries area of the CMS full of lots of structures, but it is clear which to access to edit which pages.

Second question: template organisation. In light of my separate structure approach, my templates folder has a folder in it for each structure type with an _entry that routes to the correct template based on entry type e.g.

templates folder
  > housing
    - _entry.html
    - index.html
    - content-page.html
  > guitar
    - _entry.html
    - index.html
    - content-page.html

_entry.html in each folder has something like this:

{% include "housing/" ~ entry.type %}

The index page on nearly all my structures is exactly the same, and the content page is often pretty similar (although varies slightly), so it feels like i should really point each structure to a single folder to load templates (e.g._pages/), where i'd realistically have maybe 6 or 7 templates total, as opposed to 10+ folders in /templates/ (one for guitar, one for skiing etc.).

I've abstracted all of the repeated logic in each structure template folder to a macro file to make it easy to manage updates to templates but is a single folder a better approach? Would i be best off still keeping a separate folder for /news/ in the templates folder? Or is it again 'what works best for you'.

I'd love to hear how others are doing things so i can improve my future craft builds.

I would use separate Structure for each content type, instead of having them all in a single structure.

Separate structures would allow cleaner 'relationships' between entries.

Your template structure looks good. (could you explain how 'content-page.html' differs from '_entry.html'?)

In addition: I typically add a 'static' Section for each content type so that I can display some introduction text or imagery for a page which displays a collection of entries. e.g.

Sections might be:

Single = "Housing Page"
Structure = "Housing"

Templates:

/housing/index.html would display the content from the Single AND Titles+links to each Housing entry page at:

/housing/_entry.html


getUrl() not working I have the following code in the “main.twig” template:

<head>
    {% block head %}
        <meta property="og:image" content="{% block pageImage %}{% endblock %}" />
    {% endblock %}
</head>

Then, I’m trying to populate the image URL into the < meta > tag from a Matrix field:

{% extends "templates/main" %}
{% for block in entry.articleBody %}
    {% if block.type == "articleImage" %}
        {% set image = block.articleImage.first().getUrl() %}
        {% block pageImage %}{{ image }}{% endblock %}
    {% endif %}
{% endfor %}
{% block head %}{{ parent() }}{% endblock %}

However, no URL is outputted. Does anyone know why?

Thanks!

Twig generally doesn't like nested/un-nested blocks like this. A better way to deal with this would be to just set a variable; and since twig renders templates from the inside-out, any variables that you define in child-templates should be available to the parent.

So in 'main.twig':

<head>
    <meta property="og:image" content="{% if seoImage is defined %}{{ seoImage }}{% endif %}" />
</head>

And in your child-template:

{% extends "templates/main" %}

{# note: needs to be defined outside the 'for' loop to become available #}
{% set seoImage="" %}
{% for block in entry.articleBody %}
    {% if block.type == "articleImage" %}
        {% set seoImage = block.articleImage.first().getUrl() %}
    {% endif %}
{% endfor %}

You can still use blocks of course in addition to this technique, but generally best to keep them in the same nesting order.

On a side-note: I don't think you need the 'templates/' part of the extends statement (unless you have a 'templates' folder inside 'templates'). Normally you would just use {% extends "_main" %}. The underscore in the name also prevents the template from being loaded directly.


Live Preview failing in Safari and Firefox only New Craft user here and I am working on wrapping up my first Craft site and am running into a Live Preview error.

When Live Preview is activated in either Firefox or Safari, I just get a blank white page and am getting this error thrown in the console:

  XMLHttpRequest cannot load http://mysite.com/section/slug. Cross-origin redirection denied by Cross-Origin Resource Sharing policy.

I'm not really sure what that is other than it sounds like I need to give something access that doesn't have it.   And I'm not sure why this error doesn't get thrown in for Chrome or IE.

Any help would be appreciated!

CORS (or Cross-Origin Resource Sharing) issues usually occur when you are attempting to load a resource such as a font, a stylesheet, or a script from a remote location that does not give your domain explicit permission to access it. Thinking the resource is unsafe, your browser will block it.

Are these pages attempting to load any resources from remote locations such as a CDN or web storage like an S3 bucket? If so, you may need to edit your CORS policy for those services to mark your resources as "safe" for your domain.


How can I create a new asset source? Now I have a "gallery image" field which allows users to upload multiple images, and some "single-upload image field" in matrix block.

For "single-upload image field", I want to force users to choose images only from the "gallery image" field.

To do that, I want to create a custom asset source called "gallery image". So with this source selected, I can limit the source of "single-upload image field".

Any idea to achieve this? Thanks!

Of course, just create a new asset source (settings > volumes > new volume)
then in your image field select 'Restrict uploads to a single folder' in your field and then select the asset source you just created.


"Error: Unknown package has no name defined" when updating Craft 3 I'm getting "Error: Unknown package has no name defined" when updating a site from 3.0.41.1 to 3.5.15.1
I had read a reinstall of composer had fixed this for someone else, but hasn't for me. This also happens on the same site (running locally) from a Windows and Mac OS machine - on the Mac I have been able to install some Craft updates, but I get the same error when updating plugins.
Plugins installed are: CKEditor, Contact Form, Redirect Manager, Twitter, Contact Form Extensions, Contact Form Honeypot.
I'm not able to remove any of the plugins via admin to see if they are breaking the update.
I've tried deleting the /vendor file and reinstalling the plugins with composer install - they all install fine without errors.

Okay, so this seems to be the incompatibility issue between craftcms/plugin-installer < 1.5.6 and Composer 2: https://github.com/craftcms/plugin-installer/issues/5
The solution is to update in multiple steps:

Do a normal composer update, which will fail for a couple of plugins, but will update craftcms/plugin-installer to 1.5.6.
Delete the vendor folder.
Do a composer install, as the composer.lock file has already been updated in the first step, and craftcms/plugin-installer is locked to 1.5.6 now, so the plugins should install fine.
Deploy to production: because the lock file is backward-compatible, whenever the "internal" Composer of the server will be upgraded to the 2.0-branch, it will be handled, as the composer.lock file is already 2.0-compatible.


Using multiple elementTypes in Element API I am currently trying to create an autocomplete search with the element-api. I need results from two different elementTypes:

Product::class
Entry::class

How do I get results out of both elementTypes with only one endpoint?

Thats my working Product::class element-api.php config file:

return [
    'endpoints' => [
        'search.json' => function() {
        // settings
        $phrase = Craft::$app->request->getParam('query');

        $criteria = [
            'search' => 'title:'.$phrase,
        ];

            return [
                'elementType' => Product::class,
                'criteria' => $criteria,
                'paginate' => false,
                'transformer' => function(Product $product) {
                return [
                    'title' => $product->title,
                    'url' => $product->url,
                ];
            },
          ];

        },
    ]
];

The results query could not be the same, you have to separate them.
use craft\commerce\elements\Product;
use craft\elements\Entry;

return [
    'endpoints' => [
        'search/product.json' => function () {
            // settings
            $phrase   = Craft::$app->request->getParam('query');
            $criteria = [
                'search' => 'title:' . $phrase,
            ];

            return [
                'elementType' => Product::class,
                'criteria'    => $criteria,
                'paginate'    => false,
                'transformer' => function (Product $product) {
                    return [
                        'title' => $product->title,
                        'url'   => $product->url,
                    ];
                },
            ];
        },
        'search/news.json' => function () {
            // settings
            $phrase   = Craft::$app->request->getParam('query');
            $criteria = [
                'search' => 'title:' . $phrase,
            ];

            return [
                'elementType' => Entry::class,
                'criteria'    => $criteria,
                'paginate'    => false,
                'transformer' => function (Entry $entry) {
                    return [
                        'title' => $entry->title,
                        'url'   => $entry->url,
                    ];
                },
            ];
        },
    ]
];

UPDATED: 18/12/2020
Anyway, I've found a new way that allows you o use the multiple entries in an endpoint.
<?php

use craft\commerce\elements\Product;
use craft\elements\Entry;

return [
    'endpoints' => [
        'search.json' => function () {
            // settings
            $phrase         = \Craft::$app->request->getParam('query');
            $articles       = Entry::find()->search($phrase)->limit(10)->all();
            $articleObjects = [];

            if ($articles) {
                $articleTemplateName = ''; // your article template path
                foreach ($articles as $article) {
                    $articleObjects[] = \Craft::$app->getView()->renderTemplate($articleTemplateName, ['post' => $article]);
                }
            }

            return [
                'elementType' => Product::class,
                'criteria'    => [
                    'search' => 'title:' . $phrase,
                ],
                'paginate'    => false,
                'transformer' => function (Product $product) {
                    return [
                        'title' => $product->title,
                        'url'   => $product->url,
                    ];
                },
                'meta'        => [
                    'news' => $articleObjects
                ]
            ];
        },
    ]
];


Sprout Forms + Email - internal server error Sprout Forms 2.5.1
Sprout Email 3.0.3

I am getting the error "Internal Server Error - Illegal string offset 'template'"

I have updated the template file to use email variable instead of entry for the html and text content respectively.

Stack trace:

******************************************************************************************************
    2017/11/06 20:38:21 [error] [php] Illegal string offset 'template' (/home/forge/www.sitename.co.uk/craft/plugins/sproutemail/services/SproutEmailService.php:212)
    Stack trace:
    #0 /home/forge/www.sitename.co.uk/craft/plugins/sproutemail/services/SproutEmailService.php(69): Craft\SproutEmailService->error()
    #1 /home/forge/www.sitename.co.uk/craft/plugins/sproutemail/services/SproutEmailService.php(468): Craft\SproutEmailService->renderObjectTemplateSafely()
    #2 /home/forge/www.sitename.co.uk/craft/plugins/sproutemail/integrations/sproutemail/mailers/SproutEmail_DefaultMailer.php(99): Craft\SproutEmailService->renderEmailTemplates()
    #3 /home/forge/www.sitename.co.uk/craft/plugins/sproutemail/services/SproutEmail_NotificationEmailsService.php(487): Craft\SproutEmail_DefaultMailer->sendNotificationEmail()
    #4 /home/forge/www.sitename.co.uk/craft/plugins/sproutemail/services/SproutEmail_NotificationEmailsService.php(383): Craft\SproutEmail_NotificationEmailsService->relayNotificationThroughAssignedMailer()
    #5 /home/forge/www.sitename.co.uk/craft/plugins/sproutemail/services/SproutEmail_NotificationEmailsService.php(359): Craft\SproutEmail_NotificationEmailsService->handleDynamicEvent()
    #6 unknown(0): Craft\SproutEmail_NotificationEmailsService->Craft\{closure}()
    #7 /home/forge/www.sitename.co.uk/craft/plugins/sproutemail/services/SproutEmail_NotificationEmailsService.php(298): call_user_func_array()
    #8 /home/forge/www.sitename.co.uk/craft/app/framework/base/CComponent.php(567): Craft\SproutEmail_NotificationEmailsService->Craft\{closure}()
    #9 /home/forge/www.sitename.co.uk/craft/plugins/sproutforms/services/SproutFormsService.php(79): Craft\SproutFormsService->raiseEvent()
    #10 /home/forge/www.sitename.co.uk/craft/plugins/sproutforms/services/SproutForms_EntriesService.php(246): Craft\SproutFormsService->onSaveEntry()
    #11 /home/forge/www.sitename.co.uk/craft/plugins/sproutforms/services/SproutForms_EntriesService.php(195): Craft\SproutForms_EntriesService->callOnSaveEntryEvent()
    #12 /home/forge/www.sitename.co.uk/craft/plugins/sproutforms/controllers/SproutForms_EntriesController.php(162): Craft\SproutForms_EntriesService->saveEntry()
    #13 /home/forge/www.sitename.co.uk/craft/app/framework/web/actions/CInlineAction.php(49): Craft\SproutForms_EntriesController->actionSaveEntry()
    #14 /home/forge/www.sitename.co.uk/craft/app/framework/web/CController.php(308): CInlineAction->runWithParams()
    #15 /home/forge/www.sitename.co.uk/craft/app/framework/web/CController.php(286): Craft\SproutForms_EntriesController->runAction()
    #16 /home/forge/www.sitename.co.uk/craft/app/framework/web/CController.php(265): Craft\SproutForms_EntriesController->runActionWithFilters()
    #17 /home/forge/www.sitename.co.uk/craft/app/framework/web/CWebApplication.php(282): Craft\SproutForms_EntriesController->run()
    #18 /home/forge/www.sitename.co.uk/craft/app/etc/web/WebApp.php(823): Craft\WebApp->runController()
    #19 /home/forge/www.sitename.co.uk/craft/app/etc/web/WebApp.php(287): Craft\WebApp->_processActionRequest()
    #20 /home/forge/www.sitename.co.uk/craft/app/framework/base/CApplication.php(185): Craft\WebApp->processRequest()
    #21 /home/forge/www.sitename.co.uk/craft/app/index.php(62): Craft\WebApp->run()
    #22 /home/forge/www.sitename.co.uk/public/index.php(19): require_once()
    REQUEST_URI=/contact-us

Although the Sprout Email docs state it is preferable to use shorthand syntax for variables in notifications, I found this to not be the case for the Notification subject line.

So using {companyName} in the subject would cause the issue shown above.

{{object.companyName}} fixes this.


Using Craft inside Lumen / Laravel I’m trying to bootstrap Craft as a service inside of another framework (lumen). I’m requiring the bootstrap file which seems to get me up and running except that plugins and assets aren’t included in the EntryModel results.

I’m requiring Craft like this:

$craft = require_once base_path().'/../craft/app/bootstrap.php';

$this->app->singleton('Craft', function() use ($craft)
{

    return $craft;

});

and then getting my EntryModel like this:

$criteria = app()->make('Craft')->elements->getCriteria(ElementType::Entry);

$criteria->section = 'emails';

$criteria->slug = 'tuition-agreement-link';

$email = $criteria->first();

Text content returns perfectly, but asset fields return null. The one thing I can see that craft/app/index.php does differently than me is calling $app->run() (since I'm not actually trying to run the full blown app with request routing). Anyone know if there is an additional step I can take to bootstrap assets and plugins without running the full blown app? Am I trying to do the impossible?

Craig, I really don't know much directly about this, but it occurred to me to look at the ConsoleApp, which is used in one normal way to run Craft headless (from yiic on command line). It's in app/etc/console/ConsoleApp.php.

A little hunting around with PhpStorm, excellent for this sort of thing as others, turns up that ConsoleApp is loading plugins, and I think it will be loading things like Assets through the loadEditionComponents call -- edition checks out to mean Craft Edition, as Personal, Client, Pro, etc. by your license -- so that S3 might be available for Assets, and so forth.

Just what you would need to do, haven't time to go further on. You might find just calling ConsoleApp->run() would do, or may have to make a modified version of ConsoleApp, but seems it might make a good scaffold in that case.

Good fortune on this; interested to know what you work out.


Accessing named parameter in custom route from within a controller I have a custom module in which I am setting a front end route that routes through to a controller. Like so:

 Event::on(
    UrlManager::class,
    UrlManager::EVENT_REGISTER_SITE_URL_RULES,
    function (RegisterUrlRulesEvent $event) {
        $event->rules['my-account/orders/<order>/pause'] = 'custom-module-name/order/pause-order';
    }
);

This works fine but how can I access that <order> named parameter within my controller? Is the only way to use craft::$app->request->getSegment(3);?

Hat tip to Andrew Welch for the answer.

With the route my-account/orders/<order>/pause it's possible to simply add the parameter to my controller method definition and it gets populated from the named parameter in the route.

  public function actionPauseOrder($order = null)
    {

       // do stuff
    }

The value of the named parameter order can then be accessed in the function as one would expect.

Super simple!


How to update Craft from 2.4 to 2.6? I know is kind of stupid question, but I need some 'comforting' words :)
We are going to update a very old version of Craft. We have Craft Client 2.4.2684 and going to update to the last Craft 2.6 version 2794 - 29/06/2016.

It is a very big update and usually such jumps are never going well :) What about Craft? Do the updates work good or like WP :) do they need lot of fixing of the server afterwards?

If I copy all the files present in root to my HD and a copy of the database before the upgrade, will I be able to go back without problems?

The good news is, 2.4 isn't that old. The bad news is, 2.5 was one of the most significant updates Craft has ever seen. For that reason, you'll want to exercise a little more caution than you typically would need to.

To begin with, backup your database! I can't emphasize this enough... you want to make sure that you have captured a "moment in time" for your site to roll back to, in the unlikely event that it's necessary.

After that, you'll want to perform a manual update. The vast majority of times (99%), an auto-update is a clean and easy way to update your Craft site. In fact, it's one of the things that makes Craft so amazing to begin with! However, upgrading from 2.4 -> 2.5 involves a lot of file changes, so this is one of those rare instances where you'd be wise to upgrade manually.

Lastly, you'll want to update all of your plugins after you update Craft itself. The arrival of 2.5 brought a few breaking changes for some plugins, and several awesome new features for plugins to take advantage of. Besides, it's always best to be running the latest versions of your plugins anyway. :)

In short, set aside 1-2 hours. If you're cautious and follow these tips, you'll almost certainly have a smooth transition. And if something goes horribly wrong, just roll back to your backup, and reach out to the community on the Craft Slack channel.

Good luck!


adding a block of matrix field from a front end entry form I am trying to add a form to the frontend in which a registered user will be able to create and publish new block in a matrix field. I have read the documentation about it but am still failing miserably in achieving it...
The entry is part of a structure section with sectionId movementCoursesEntries. The matrix fieldId is videos. The blockId is video_box and it has two plain text fields videoTitle and videoUrl.
I have used this code but what I am getting is that the after submitting the form, all the old matrix blocks are being deleted and the new one is not being created. Any advice is highly appreciated!
<form method="post" accept-charset="UTF-8">
    {{ csrfInput() }}
    {{ actionInput('entries/save-entry') }}
    {{ redirectInput('/members-zone/{slug}') }}
    {{ hiddenInput('movementCoursesEntries', '2') }}
    {{ hiddenInput('enabled', '1') }}
    {{ hiddenInput('entryId', entry.id) }}

    {% if entry is defined %}
        {# Retain existing blocks + sort order #}
        {% for video_box in clone(entry.videos).anyStatus().ids() %}
            {{ hiddenInput('fields[videoTitle][sortOrder][]', video_box) }}
            {{ hiddenInput('fields[videoUrl][sortOrder][]', video_box) }}
        {% endfor %}
    {% endif %}

    {# Add a new text block #}
    {{ hiddenInput('fields[videoTitle][sortOrder][]', 'new:1') }}
    {{ hiddenInput('fields[videoUrl][sortOrder][]', 'new:1') }}

    {# Prefix the block's input names with `fields[<FieldHandle>][blocks][new:1]` #}
    {% namespace "fields[blocks][blocks][new:1]" %}
        {{ hiddenInput('type', 'text') }}
        <input name="fields[videoTitle]">
        <input name="fields[videoUrl]">
    {% endnamespace %}

  <input type="submit" value="Publish">
</form>

With the help of CreateSean comment I have managed to fix the problems in the form.
Here it is for future reference for everyone:
<form method="post" accept-charset="UTF-8" enctype="multipart/form-data" class="edit-store">
    {{ csrfInput() }}
    {{ actionInput('entries/save-entry') }}
    {{ redirectInput('members-zone/{slug}') }}
    {{ hiddenInput('movementCoursesEntries', '2') }}
    {{ hiddenInput('enabled', '1') }}
    <input type="hidden" name="entryId" value="{{ entry.id }}">

    {# various includes here #}
    <input type="hidden" name="fields[blocks]" />

    {% for block in entry.videos %}
        {% if block.type == 'video_box' %}
            <div class="matrixblock ">
                <input type="hidden" name="fields[videos][{{ block.id }}][type]" value="video_box">
                <input type="hidden" name="fields[videos][{{ block.id }}][enabled]" value="1">
                <input type="hidden" name="fields[videos][{{ block.id }}][fields][videoTitle]" value="{{ block.videoTitle }}">
                <input type="hidden" name="fields[videos][{{ block.id }}][fields][videoUrl]" value="{{ block.videoUrl }}">
            </div>
        {% endif %}
    {% endfor %}
    {# hidden field with block type that is being updated #}
    <input type="hidden" name="fields[videos][new_0][type]" value="video_box">
    {# is this block enabled #}
    <input type="hidden" name="fields[videos][new_0][enabled]" value="1">
    <input type="text" name="fields[videos][new_0][fields][videoTitle]" value="" placeholder="Video Title">
    <input type="text" name="fields[videos][new_0][fields][videoUrl]" value=""  placeholder="Videl URL">

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


.htpasswd in template file I would like to set a .htpasswd on a folder within my templates directory. Here is what I did:

..create the .htpasswd file and place in directory above my public folder
..create a .htaccess file that points to the .htpassword file, and place it in the folder I want to protect, which is in my templates directory.

When I enter a url to access the page, it displays the page fine, but does not trigger the .htpasswd. If I move the folder to my root directory, everything works fine.

Why does this not work as a Craft template?

It's not doing it due to order of operations. Your browser hits the site, checks htaccess (in the webroot /html/), and then asks craft for whatever page. Craft goes hunting around, and returns your page from templates. And it's Craft (not you the user) accessing the templates, so it's always 'approved.'

Here's a potential solution. Take a look at this page - https://noahread.net/blog/create-password-protected-pages-in-craft

It's how to create a single password-protected page. Uses a for a password. And that password is hidden in a craft variable, so no one can see it. If it returns successfully, you get content.

All that said, craft pro might be cheaper than the time spent building said form.


Control panel field name & instructions translations I've installed a Craft Pro site with 3 locales: Dutch, French & English, but the people who are going to input data will speak those languages too, so I need to translate the instructions field in the control panel (and, if possible, the field names too since most of the time that makes it clear enough).
Is this possible, and if it is: how?
Thanks!

If your main language site is dutch for example, you can do that using your own php files locale and naming them according the other locales languages, en.php, fr.php and put those files in craft/translations/ (a folder you must create yourself). Then you can translate in the array all your string (field name and instructions).

Have a check at the documentation:

Translating Static Text


Only fetch categories that are related to a minimum of entries Is there a way to only fetch categories that have been assigned to a minimum of entries, i.e. 4?

Currently I fetch categories like this:

{% set productIds = craft.entries.section('products').ids() %}
{% set categories = craft.categories.relatedTo({ sourceElement: productIds }) %}

I know I can now do the following to only display content for categories which have been assigned to at least  four entries:

{% set entries = craft.entries.section('products').relatedTo(category) %}
{% if entries|length > 4 %}
  ...
{% endif %}

But is there a way to apply this logic to the craft.categories query?

What you can always do in situations, where the default parameters are not enough,
is to "collect" element IDs and pass them to the id param of a new criteria model.

So loop through all categories and merge the category IDs matching you condition to an array:

{% set topCategoriesIds = mainCategoriesIds|merge([category.id]) %}

When you're done, get your filtered categories from these IDs:

{% set categories = craft.categories.id(topCategoriesIds) %}


Dashboard icons missing with flexible SSL We are enabling SSL initially via cloudflare and their free flexible SSL. This works great for the site content, but on the dashboard for craft, if I login, any icons are converted into words.

https://www.cloudflare.com/ssl

I am seeing that the page is serving mixed secure content, but wonder if there is a way to make craft happy with this situation and render the font icon properly?

We will eventually implement a full SSL cert, but this will be in place for a while.

Many thanks :)

This is a bit of a stab in the dark, but have you tried forcing SSL for all CP requests?

http://buildwithcraft.com/help/force-ssl

Ultimately your .htaccess would look something like this:

<IfModule mod_rewrite.c>
 RewriteEngine On

 # Force SSL for CP requests
 RewriteCond %{HTTP_HOST} example\.com [NC]
 RewriteCond %{REQUEST_URI} ^/admin/ [NC]
 RewriteCond %{HTTPS} !=on
 RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [NC,R=301,L]
</IfModule>


Displaying Error onBeforeSaveEntry I am new to Craft but loving its ease of use so far.

I am having a problem however when setting up a plugin to display an error to the user when using the onBeforeSaveEntry hook when a user saves an entry. I am looking to determine the value of a field and then take the user back to the entry page and display an error to the user based on a certain selection. Is this something that can be done with the Craft page when saving an entry?

Is this something that can be done with the Craft page when saving an entry?

In 2.2, there isn't an easy way.  In the upcoming 2.3 release, we added a $performAction property to the event, so your can do something like:

$entry->addError('attribute', 'MyErrorMessage');
$event->performAction = false;

And Craft will not save the entry and return to the edit entry page to display any validation errors.

You should post your second question as an entirely new question.


Best solution for get json results from third party api? I need to get blog posts from hubspot api using this approach.
http://developers.hubspot.com/docs/methods/blogv2/get_blog_posts

Since craft uses twig I'm unable to use php in the templates, so I thought I could just use jQuery getJson but this causes a cross origin request blocked error.

So is creating a plugin and using php my only option to get json results from an api call?

Has anyone used hubspot api?

This works great for templates too: https://github.com/engram-design/FeedMe

Just tested it for a RSS feed, but apparently it also supports JSON.

The RSS example:

{% set params = {
    url: 'http://url.to/feed.rss',
    type: 'rss',
    element: 'item',
    cache: 60,
} %}

{% set feed = craft.feedme.feed(params) %}
{% for node in feed %}
    Title: {{ node.title }}
    Publish Date: {{ node.pubdate }}
    Content: {{ node.description }}
{% endfor %}


Setting arbitrary PHP constants in index.php I was looking for a way to set arbitrary PHP constants in the index.php that could then be accessed within templates.

This is particularly useful if you have more than one index/domain pulling content from a core Craft install as the additional domains won't have any configuration files to use, just index.php.

Hat-tip to Brad for finding this answer.

This can be achieved with something like the following in your index.php:

define('BRADS_FAVORITE_HOBBY', "Drinking");

Thanks to the power to Twig, you can then access this in your templates using:

{{ constant('BRADS_FAVORITE_HOBBY') }}


Craft Commerce: ordering products like a structure Is it possible to change the order of products in Craft Commerce (3) by drag & drop? Just like it is done with the entries of a structure?
If not, how am I supposed to change the order of products?
Of course I can create a number field and type in a number and then sort after this number. But that's super inconvinient.
Another way would be to create single-pages for each product category and then have an entries-field. Than, at least, I can use drag and drop. But still, this would just be a work-around.

Yeh there's few workarounds.
Your entries field is close to what Nathanial from P&T mentioned on the issue tracker:

If you create a global set and add a custom product field. Then select all the products. This gives you the ability to drag and drop the order of the products. You can use this in conjunction with the on save event and catch the save of new products and programmatically add them to the field mentioned above.

If you filter by category, you won't have to create a field for every category however it's definitely still a workaround.

One other option would be to sort based on some other criteria that's always around, such as date created or modified.
If you want something to float to top or bottom, just remove the post date (so Craft will make the product the current date and time) or resave the product (to change the modification date). Depending on how you sort that could be a quick way to move products to the top for example.
Make sure you chime in on that issue on the tracker to give it more attention.


Templating Matrix Block It's my first website using Craft.
I'm trying to figure out how to loop Matrix. I have created a field called bannerMatrix with a block type called banner that has 3 fields:

Image (assets)
Heading (plain text)
Subheading (plain text)

This is what I have so far:

{% for block in entry.bannerMatrix %}
    {% if block.type == "banner" %}

{{ block.heading }}

{{ block.subheading }}

    {% endif %}
{% endfor %}

Anything will be helpful.
Thanks!

UPDATE

@JamieWade, thanks a lot for the super fast answer!
Unfortunately, the code above still doesnt work for me :(

{% for block in entry.bannerMatrix %}

{{ block.heading }}

{{ block.subheading }}

{% endfor %}

I also tried this :

{% set image = block.image.first() %}
{% if image %}

{% endif %}

And I dont get anything as well :(

I wonder if my structure is correct. So I attached a screenshot.

@Alec, yes there is content in the entry(I attached a screenshot). Now I'm even more curious, what's missing here. I also added the path to subfolder in the Field Setting.

From your last update it looks like you simply need to get the entry that contains that matrix block, the error Variable "entry" doesn't exist simply means nothing is assigned to entry in your templates. There are a couple of ways you can solve this:

Option 1 - Tell Craft which template to load for this entry

If you go into your section settings, there will be a field called Entry template which if, for example, you put about in this craft would look for either about.html or about/index.html in your craft/templates folder and would automatically assign a variable entry to your template when you visit the /about url.

There is also an option This is for the homepage in the settings which, if checked, will assign the entry to index.html in your templates (but i don't think this will show if there is already a section checked elsewhere)

You can see more about this in the craft docs: http://buildwithcraft.com/docs/templating-overview

Option 2 - Fetch the entry in your template using twig tags

There are numerous ways to do this, but given you are using a single you should just be able to use this:

{% set entry = craft.entries.section('homePageBanner').first() %}

You might need to adjust the homePageBanner part if that isn't the handle of your section, but this will then give you an entry variable to work with in your template and hopefully you'll find you will get the matrix content back :)

If you need some more details on how craft.entries works then the docs are a great place to find out more: http://buildwithcraft.com/docs/templating/craft.entries


Display first image from matrix field of a related entry to current tags I want to display on entry view page, related entries to current tags.
So far, I came to displaying basic entry's object, but I don't know How to get in matrix field and pull the first image.

Images are stored in matrixFieldHandle -> blockTypeHandle -> imageFieldHandle.

For outputting related entries to current tags I use:

{# Set ECM for related entries to current tags #}
{% set tag = entry.keywords %}
{% set relatedEntries = craft.entries.relatedTo(tag).id('not ' ~ entry.id).limit(8).find() %}

{% for entry in relatedEntries %}
    {{ entry.title }}
{% endfor %}

I think entry.matrixFieldHandle.type('blockTypeHandle') is what you're looking for. Putting it together, it'd be something like:

{% set tag = entry.keywords %}
{% set relatedEntries = craft.entries.relatedTo(tag).id('not ' ~ entry.id).limit(8) %}

{% for relatedEntry in relatedEntries %}

    {% set matrixBlock = relatedEntry.matrixFieldHandle.type('blockTypeHandle').first() %}

    {% if matrixBlock %}

        {% set asset = matrixBlock.imageFieldHandle.first() %}

        {% if asset %}

            <h1>{{ relatedEntry.title }}</h1>
            {{ asset.img }}

        {% endif %}

    {% endif %}

{% endfor %}


The file does not appear to be an image. Bug? I've installed the latest ImageMagick on my ubuntu 14 server. If I force imageDriver to use 'imagick', I can only upload Gif images. And if I force it to use GD, I can upload all images but only static gif images.

The images are not changed in any programs.

It's important for me to have both options. Any ideas what this issues can be? I use php 7.0

Upload failed for background.jpg. The error message was: “Error uploading the file: The file “/var/www/html/craftcms/craft/storage/runtime/temp/assets57cb93709cf445.74590720.jpg” does not appear to be an image.”

That error will occur if the fileinfo extension or imagick (ImageMagick) extension are not configured with a comprehensive list of file MIME types (the "magic file", as they refer to it, I think), or the images you're uploading aren't really images despite their extensions.

Regarding GIFs - you must use ImageMagick if you want to upload animated GIFs, as it's not possible for Craft to reconstruct an animated gif using the GD library.


Bulk resave entries to trigger onSaveEntry event I have a site with a hundred+ or so entries. I've added a new field to my entry template, but it won't take effect until it's been activated by a onSaveEntry event.

I've gone through maybe 15 entries or so now and resaved them manually, but it's proving to be a long and painstaking process.

Is there a way for me to batch resave all enabled entries in order to trigger this onSaveEntry event?

If you re-save the section(s) that your entries are in, it should re-trigger a save of all of the entries.

Hope that helps!


PHP Fatal error during installation I am trying to run craft inside a homestead box. The box boots and installs everything correctly, and when I navigate to http://localhost:8000/admin I see the install screen and can click through the prompts. However, after clicking through the final screen I always get "Install failed  Please check your logs for more info.".

Here are the details for my setup:

Host OS: Windows 10 1809
Vagrant version: 2.2.4
Virtualbox version: 6.0.8
Homestead version: 8.5.5 (vagrant box 8.0.0-alpha2)
Guest OS: Ubuntu 18.04.2
Guest PHP version: 7.3.5-1

phperrors.log has this to say:

[03-Jun-2019 19:56:07 UTC] PHP Fatal error:  Uncaught yii\base\ErrorException: unlink(/home/vagrant/code/storage/runtime/mutex/a78d6a4ecc5877cd5617ca990a2be38b.lock): Text file busy in /home/vagrant/code/vendor/yiisoft/yii2/mutex/FileMutex.php:161
Stack trace:
#0 /home/vagrant/code/vendor/yiisoft/yii2/mutex/FileMutex.php(161): ::unlink()
#1 /home/vagrant/code/vendor/yiisoft/yii2/mutex/Mutex.php(88): yii\mutex\FileMutex->releaseLock()
#2 /home/vagrant/code/vendor/yiisoft/yii2/mutex/Mutex.php(57): yii\mutex\FileMutex->release()
#3 {main}
  thrown in /home/vagrant/code/vendor/yiisoft/yii2/mutex/FileMutex.php on line 161

I've googled this error message but didn't find anyone with the same problem. The referenced line of code (FileMutex.php:161) offers the clue that it may be an issue with operating systems (a different file unlock/delete procedure is used on windows).

In the vagrant box, the permissions on that file are wide open and I can delete the file with no problem.

vagrant@craftycoffee:/vagrant/storage/runtime/mutex$ ls -al
total 8
drwxrwxrwx 1 vagrant vagrant 4096 Jun  3 02:39 .
drwxrwxrwx 1 vagrant vagrant 4096 Jun  3 02:35 ..
-rwxrwxrwx 1 vagrant vagrant    0 Jun  3 02:35 4f99fda3d17d57459c4105d023bcba69.lock
-rwxrwxrwx 1 vagrant vagrant    0 Jun  3 02:35 52fa75c9044f6df80d2103fad929036e.lock
-rwxrwxrwx 1 vagrant vagrant    0 Jun  3 19:56 a78d6a4ecc5877cd5617ca990a2be38b.lock
vagrant@craftycoffee:/vagrant/storage/runtime/mutex$ rm a78d6a4ecc5877cd5617ca990a2be38b.lock
vagrant@craftycoffee:/vagrant/storage/runtime/mutex$ ls
4f99fda3d17d57459c4105d023bcba69.lock  52fa75c9044f6df80d2103fad929036e.lock

My best guess is that there is some weird interaction between windows and ubuntu when vagrant mounts that folder. However, I use vagrant for several other projects (all with windows host and linux guest) and have never seen any problems like this. I'm a complete noob with homestead/craft/php so I'm not really sure where to go from here; Any guidance on troubleshooting is appreciated. If there is any more info I can provide please let me know.

EDIT: I tried using SMB to do the file mounting (I believe NFS is the default?) and it worked. However, this isn't an optimal solution because I have to put in my username and password every time I boot the box.

See this issue: https://github.com/craftcms/cms/issues/4355#issuecomment-498829513

reproduced here for completeness:

  A yii variable 'isWindows' is apparently the way to correct this issue, but I haven't been able to find any documentation describing where/how to set this.

From your Craft config/app.php file, you can use this to set the isWindows property of the FileMutex class to true.

return [
    'components' => [
        'mutex' => function() {
            $config = craft\helpers\App::mutexConfig();
            $config['isWindows'] = true;
            return Craft::createObject($config);
        },
    ],
];


Element Query matrixfields where I'm trying to query entries in a section where the (activities) entry has an item in a matrix field timeSlots -> timeSlot -> startDate.
The startDate must be >= NOW().

$query = Entry::find()->section('activities');

// something like
// $query->where('timeSlots.*.startDate >= NOW()');

$activities = $query->all();

You need to join the matrixblocks and the specific content table

$query->join('{{%matrixblocks}}, 'matrixblocks.ownerId = elements.id);
$query->join('{{%matrixcontent_your_table_name}}, 'matrixcontent_your_table_name.elementId = matrixblocks.id);
$query->andWhere([
    '>=',
    'matrixcontent_your_table_name.name-of-the-column',
    new Expression('NOW()')
]);

Edit: if you have multiple blocks with the same field handle you'll need to wrap all those in a new OrCondition

$now = new Expression('NOW()');
$query->andWhere(
    new OrCondition([
        ['>=', 'column1', $now],
        ['>=', 'column2', $now],
        ['>=', 'column3', $now],
    ])
);

Edit2: I would suggest you to only fetch ids in that query because it's likely to have more results when you join these tables


How Do I show advanced Date filters for Events? I am trying to setup an events section similar to that of Yelp's Events.  They have a listing of all the upcoming events and have filters on the side for "Today, Tomorrow" etc...

I received help from Brandon Kelly and will be posting my answer below.

Thanks to Brandon Kelly's help I now have Events being filtered by my custom date field called eventDate by doing the following:

{% set day = date(craft.request.getSegment(2)) %}
{% set nextDay = day|date_modify('+1 day') %}
{% set events = craft.entries.eventDate('and, >= '~day|date('Y-m-d')~', <'~nextDay|date('Y-m-d')) %}

I have some links in my side bar that append the appropriate Date to the URL:

Today
Tomorrow

And finally I just loop that through like so:

{% for block in events %}{% endfor %}

I hope someone else can find this as handy as I did through Brandon's help!


Can I add fields to the User > Account screen? Is there any way to add to the fields shown on the 'Account' tab on the user account screen?

I know I can add fields via the layout designer, but these appear as seperate tabs.

I'd like to add "middle name(s)" as a field next to "First Name" and "Last Name" if possible?

User content fields can only be customized within the additional tabs, configured in the field layout interface. Users are a built-in custom Element Type, and have some non-configurable fields.

This is likely a measure taken by the Craft authors to isolate and protect important fields from being lost among other custom fields.

It is possible to create front-end form that rearranges these fields, if the UX of the admin is unworkable for your users!

Edit (1/24/2018): In Craft 2.6.3005, the authors have added support for multiple tabs in the User edit screen. This doesn't change our ability to customize the first page, but allows you to add more tabs to organize the remainder of your fields. ✌


Create a custom field with my plugin data I want to create a field like categories but using my plugin data.

I need to be able to select one element in entry page to get all the elements from my plugin group base on that selection.

do i go with a custom field type or there is another way ?

The questions is a bit short on details but from what you've posted, it sounds like a custom field type is what you're looking for.


Finding the correct actions url struggling to decipher how to link a plugins controller to an action route. The docs say to use "https://pluginfactory.io/" to scaffold one, but what it generates is a different structure to what the documentation say to use.

I've got a plugin called Gated Content sitting inside: plugins/gated-content

I've got a controller named and located at:

plugins/gated-content/src/controllers/GatedContent_DataCaptureController.php

with the class name of of GatedContent_DataCaptureController

I've just got an actionIndex method which var dumps and exits.

Which would suggest (according to the docs) that the URL to access this should be:

https://craftcms.localhost/index.php?p=actions/gatedContent/dataCapture/index

But it just throws a 404.

Inside of the .craftplugin file I've also added "controllerName":"GatedContent_DataCaptureController incase, but doesn't seem to make a difference.

What is the correct pattern to use for each of these?

Thanks

EDIT:
In the first version of the answer I forgot the /admin part of all the example URLs. Added now.

TL;DR version:

To get to the point first before explaining more in-depth: You need to convert the names from camelCase (with capitalisation in the name) to kebab-case (with dashes instead). I would suggest renaming your controller to simply DataCaptureController, since it's within the Gated Content plugin anyways, and you should be able to use:

https://craftcms.localhost/admin/gated-content/data-capture/index

Full answer:

So, the structure is basically plugin-name/controller-name/method-name, all in kebab case, meaning that what is someName should be some-name, as not all servers are case sensitive (althouth URLs technically are, if I'm correct). Also, the Controller and action parts of the class/method name is implied, as you've already correctly done, but as far as I know, not adding the plugin name to the front of your controller (I have not checked this specifically).

So in your case it should be something like this:

https://craftcms.localhost/admin/index.php?p=actions/gated-content/gated-content_data-capture/index

I am honestly not quite sure how underscores are treated in kebab-case, so it could be that this is the correct form:

https://craftcms.localhost/admin/index.php?p=actions/gated-content/gated-content-data-capture/index

Also, you should be able to use the url like this:

https://craftcms.localhost/admin/gated-content/gated-content-data-capture/index

(Or, if you really prefer for some reason, with /actions in the URL:)

https://craftcms.localhost/admin/actions/gated-content/gated-content-data-capture/index


Can't install plug-ins from CP I can install plug-ins from the command line, but when I do so from within Craft, I get this:
Composer was unable to install the updates.
Error: Could not delete /var/www/craft-dev/vendor/yiisoft/yii2-shell/ShellController.php: unlink(/var/www/craft-dev/vendor/yiisoft/yii2-shell/ShellController.php): Permission denied
Composer output: Package "craftcms/vue-asset" listed for update is not installed. Ignoring.
Loading composer repositories with package information
Updating dependencies
Package operations: 8 installs, 2 updates, 4 removals

Removing yiisoft/yii2-shell (2.0.4)

Any suggestions? Permission error?

Yes, looks like you'll need to look at the folder yiisoft and subfolders for permissions. Maybe set them to read, write until you're done and then change them to read only.
Just thinking off the top of my head about what the issue could be.


Text cut off after migration in some fields I migrated a site from Craft 2 to Craft 3 and on some Redactor fields, half the text is gone. It looks completely random. In some fields, the text is gone. In some the text is about half as long as before and on others the text is fine. How is this possible?

I just noticed that when I copy the old text into the field it is cut off again on save. How is that possible?

Found the issue with the awesome Craft support.

There seems to be a server related issue where db tables change from TEXT to VARCHAR.

So the solution is to change those fields back to TEXT directly in the db.


Craft entries related on a category page So i'm trying to output blog entries related to a category.

I first created a category group ('categories')
I added several categories to the group ('innovation', 'teams', etc)
I added a category field to my blog post matrix field (post.category)
On my blog index page (example.com/blog) I have excerpts of posts and a sidebar which has the categories and their urls

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

 {% for category in categories %}

{{ category.title }}

 {% endfor %}

When I click on the link it goes to the page I expect (example.com/categories/teams) and is using the template i specified for the template group (categories.html)
In the template for the category I can list the title and name but I want to get the entries so I:

{{ category.title }}
 <--- just this works
{% set posts = craft.entries.relatedTo(category) %}
{% for post in posts %}

{{ post.title }}

{% endfor %}

But this didn't work

following http://buildwithcraft.com/help/entries-related-to-category

then I tried this, thinking specifying the field was necessary

{{ category.title }}
 <--- again, this works
{% set posts = craft.entries({
section: 'blog',
relatedTo: {
targetElement: category,
field: 'posts.categories'
}
}) %}

{% for post in posts %}

{{ post.title }}

{% endfor %}

and this doesn't work either.

Anyways, i'm not sure where I am going wrong and any help would be appreciated.

I should note that the relatedTo method accepts a CategoryModel, not the title of a category. What you ended up doing works, but here's the way to do with the relatedTo method, which is what I'd suggest for anyone finding this in the future:

{% for entry in craft.entries.relatedTo(craft.categories.slug('your-cat-slug')) %}

You now have all entries that are associated with the given category, and can loop through them with the usual {% for entry in entries %} technique.

TL;DR: You can't pass the category name. You have to give relatedTo an actual CategoryModel.


Stub out the global craft() object for PHPUnit tests As best I can tell, the 'mockBuilder' function is exactly what I want, and based on other examples, should work.

Am I missing something?
How can I stub out the global craft() object?

under test:

<?php

namespace Craft;

class JobsVariable
{

     // Grab all Jobss
     public function jobs()
      {
            return craft();
      }
 }

test file:

    <?php

    namespace Craft;

    require_once 'www/craftcms/plugins/jobs/variables/JobsVariable.php';

    class JobsVariableTest extends \PHPUnit_Framework_TestCase
    {

        public function testJobs()
        {

            $craft = $this->getMockBuilder('\\Craft')
                ->disableOriginalConstructor()
                ->setMethods(array('craft'))
                ->getMock();

            $craft->method('craft')->willReturn('xxx');

            $jobs = new \Craft\JobsVariable();
            $this->assertEquals('xxx', $jobs->jobs());

        }
    }

output:

PHP Fatal error:  Call to undefined function Craft\craft()

Whew...this seems to do the trick!
Hopefully this is an appropriate way to handle things.

I created a new Craft class file in the 'tests' dir.  There I can stub out any \Craft\craft() methods the class under test depends on.

stub class \tests\Craft

<?php

class Craft {

    public function __construct()
    {
    }

    public function jobs()
    {
        return 'xxx';
    }
    public function getJobs()
    {
        return 'xxx';
    }

    public function craft()
    {
        return $this;
    }
}

in the test class

<?php

namespace Craft;

require_once '/www/craftcms/plugins/jobs/variables/JobsVariable.php';
require_once '/www/craftcms/tests/Craft.php';

class JobsVariableTest extends \PHPUnit_Framework_TestCase
{

    public function testJobs()
    {
        $jobs = new \Craft\JobsVariable();
        $this->assertEquals('xxx', $jobs->jobs());

    }
}
function craft()
{
    return new \Craft;
}

allows me to test this function...

public function jobs()
{
    return craft()->jobs();
}


Search result on blank search query When you click in search form and press 'Enter' or 'Submit' button, it returns all entries, that exist in database.

How could I display some message rather than all entries?

You could use a conditional to check if your "search term" parameter has a value.

Search Results

{% set query = craft.request.getParam('q') %}

{% if query|length  %}

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

    {% if entries|length %}

{{ entries|length }} results:

            {% for entry in entries %}

{{ entry.title }}

            {% endfor %}

    {% else %}

Your search for “{{ query }}” didn’t return any results.

    {% endif %}

{% else %}

You forgot to enter a search term.

{% endif %}

(This code is modified from the examples in the Craft docs for "Search Form")


Sorting by date field across sections not working I've seen a number of answers prescribing how to sort across different sections...but I'm not seeing it work. Here's what I've tried:

{% set profileIds = craft.entries.section('profiles').order('profileBorn asc').ids() %}
{% set eventIds = craft.entries.section('events').order('eventDate asc').ids() %}
{% set timelineIds = profileIds|merge(eventIds) %}
{% set timeline = craft.entries.id(timelineIds) %}

Or:

{% set timeline = craft.entries.section(['profiles','events']).order('GREATEST(eventDate, profileBorn) desc') %}

Then for either, I'm doing:

{% for entry in timeline %}

In both cases, I get entries in the following order, with their {{ entry.profileBorn }} or {{ entry.eventDate }} shown here:

1832-02-01 / events entry
1830-01-01 / profiles entry
1840-01-01 / profiles entry

Any thoughts? Thanks!

UPDATE:

This looks like the SQL being generated by the first answer's suggestion, which is still outputting the event entry first.

SELECT `elements`.`id`, `elements`.`type`, `elements`.`enabled`, `elements`.`archived`, `elements`.`dateCreated`, `elements`.`dateUpdated`, `elements_i18n`.`slug`, `elements_i18n`.`uri`, `elements_i18n`.`enabled` AS `localeEnabled`, `content`.`id` AS `contentId`, `content`.`title`, `content`.`field_profileBio`, `content`.`field_body`, `content`.`field_profileBorn`, `content`.`field_copyright`, `content`.`field_datePrecision`, `content`.`field_datePrecisionBorn`, `content`.`field_datePrecisionDied`, `content`.`field_profileDied`, `content`.`field_eventDate`, `content`.`field_mediaCaption`, `content`.`field_mediaPublicationDate`, `content`.`field_mediaSource`, `content`.`field_mediaTitle`, `content`.`field_siteTitle`, `entries`.`sectionId`, `entries`.`typeId`, `entries`.`authorId`, `entries`.`postDate`, `entries`.`expiryDate`, `structureelements`.`root`, `structureelements`.`lft`, `structureelements`.`rgt`, `structureelements`.`level`
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_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.id=:elementsid1) OR (elements.id=:elementsid2) OR (elements.id=:elementsid3))) AND (elements.archived = 0)) AND ((elements.enabled = 1) AND (elements_i18n.enabled = 1) AND (entries.postDate <= '2017-07-12 12:47:25') AND ((entries.expiryDate is null) OR (entries.expiryDate > '2017-07-12 12:47:25')))) AND (elements_i18n.enabled = 1)
GROUP BY `elements`.`id`
ORDER BY GREATEST(field_eventDate, field_profileBorn) asc LIMIT 100

Your second attempt is sound. I don’t really have an idea why it doesn’t work, but I bet it has to do with the SQL that is caused by setting the section param to an array.

What I would try next is the following, kind of a merge of your ideas.

{% set profileIds = craft.entries.section('profiles').limit(null).ids() %}
{% set eventIds = craft.entries.section('events').limit(null).ids() %}

{% set idParam = profileIds|merge(eventIds) %}

{% set timeline = craft.entries({
    id: idParam,
    order: 'GREATEST(eventDate, profileBorn) desc',
}) %}


upgrading from 2.1 to 2.3 The project I was working on was put on hold a few months back. Back then I was on version 2.1.2570. Now the project is back on. After having gone through the pain of manually restoring the InnoDB tablespaces because I switched development systems in the meanwhile and didn't bother to do a proper mysqldump, I'm now facing the task of upgrading Craft from 2.1.2570 to the latest revision. It fails while updating the database. Is there any place where I can download older releases (i.e. 2.2.2579) to see if they come through?

Thanks

Sure, have a look at the Craft site for details about downloading a specifc build of Craft:

http://buildwithcraft.com/help/download-previous-versions

So if you want to download 2.2.2579, the URL will be:

http://download.buildwithcraft.com/craft/2.2/2.2.2579/Craft-2.2.2579.zip


Send email to website owner after user registration I have a client that wants to get notified whenever someone registers on their website.

How can I do this, is there some kind of plugin? If not how would I go about doing this?

I have done something very similar. You'll want to create a plugin for this.

In my case, I am validating email addresses so I was checking against the onBeforeActivateUser event. If you are not validating email addresses, @Lindsey D' answer is where you want to go.

Either way, they will look about like this:
I created a plugin called accounts.

MyPlugin.php

public function init()
{
    /**
     * Event listener for activating a user.
     *
     * @param Event $event
     */
    craft()->on('users.onBeforeActivateUser', function (Event $event) {
        $user = $event->params['user'];

        craft()->accounts->onSendNotificationEmail($user);
    });
}

MyService.php

/**
 * Sends a notification email.
 *
 * @param $user
 * @return bool
 */
public function onSendNotificationEmail($user)
{
    $recipient = $user->email; // get the email address passed in

    $email = new EmailModel();

    $message = '<!DOCTYPE html><title>My Title</title>';
    $message .= '';
    $message .= '
';
    $message .= '
LOGO/BRANDING
';
    $message .= '
';
    $message .= '
Hello,
There has been a new account created on the website.
';
    $message .= '
...your message here...
';
    $message .= '';

    $email->subject = 'New Account Created';
    $email->body = $message;

    try {
        $email->toEmail = $recipient;

        craft()->email->sendEmail($email);
    } catch (\Exception $e) {
        return false;
    }
}

I'm sure there is a cleaner way to get your email body into the CP itself and allow the admin to change the message easily, but this works quick/well.


Best way to create an entry (bio) view for a User I think Douglas has kind of answered this here, but just to ask as a separate question:

Given I have made use of Craft's User section to hold data about a company's team members, how do I now make an entry page for each member, which can link through from the list page? ('About us' single containing a loop over Users).

I originally had a channel for the team members, but switched to using Users because they will be authoring blog posts, and I figured the relation would be cleaner.

Thanks.

Not to diminish from Damon's excellent answer — I have certainly used this technique in the past when needed. However, just to provide another option, keep in mind that you don't need to create a separate section/channel for profile information (and thus a plugin to keep them in sync, etc). You can also simply link to a user profile template by creating a route, using username or id (or any other unique identifiable user field or field combination) to identify the user, and then pull data from the custom fields you added to 'users'.

You will first want to create a route in settings to your user profile template. Notice the use of the 'slug' token, which will be available to the template as simply {{ slug }}:

If the URL looks like this:
about/profiles/<slug>   <-- where '<slug>' is the slug token

Load this template:
about/user-profile.twig

In your 'about' page template (i.e. the user's index page):

{% set users = craft.users.group('myGroup').limit(null) %}

    {% for user in users %}

{{ user.firstName }} {{ user.lastName }}

    {% endfor %}

Then, in your 'about/user-profile' template:

{% set user = craft.users.username(slug).first %}
{% if user %}

{{ user.firstName }} {{ user.LastName }}

{{ user.biography }}

    etc...
{% else %}
    {% redirect '404' %}
{% endif %}


MySQL ColumnType::Time does does not populate model from setAttribute() I have a record with a time field set like this:

'startTime'         => array(AttributeType::DateTime, 'column'=>ColumnType::Time, 'required' => true),
'endTime'           => array(AttributeType::DateTime, 'column'=>ColumnType::Time),

The data is stored in the database as a string like this:

10:45:53

When I populate models from an elementCriteria query, the string value "10:45:53" does not work with creating a new DateTime object so I get false returned.

I would need to supply a full date in order to get a valid DateTime object back.

How should I deal with this? Is this i a bug in core? Why have ColumnType::Time if its not going to work correctly when pulling the value from the database?

It turns out that I don't think you should really use craft's DateTime object for time only. I suppose there is a case where you might want but if you just have a "time of day" absent a date, I ended up using AttributeType::String for them, but still use a ColumnType::Time for the database.

Then all I needed to do is override populateModel method to do a little magic to convert them from 24 hour format to 12 hour format like this:

public static function to12Hour($dbTime) {

    $dbTime = explode(":", $dbTime);

    if($dbTime[0] > 12) {
        $ampm = "PM";
        $dbTime[0] = $dbTime[0] - 12;
    } else if($dbTime[0] == 0) {
        $ampm = "AM";
        $dbTime[0] = 12;
    } else {
        $ampm = "AM";
    }

    return $dbTime[0] . ":" . $dbTime[1] . " " . $ampm;
}

public static function populateModel($values) {

    $model = parent::populateModel($values);

    if ($values['startTime']) {
        $model->setAttribute('startTime', self::to12Hour($values['startTime']));
    }

    if ($values['endTime']) {
        $model->setAttribute('endTime', self::to12Hour($values['endTime']));
    }

    return $model;
}

You just need to make sure you're storing the time in 24 hour format and to ensure that is the case, I set up my attribute types like this:

        'startTime'         => array(AttributeType::String, 'column'=>ColumnType::Time, 'required' => true, 'matchPattern' => '/^\d\d:\d\d:\d\d$/'),
        'endTime'           => array(AttributeType::String, 'column'=>ColumnType::Time, 'matchPattern' => '/^\d\d:\d\d:\d\d$/'),


How do I nest multiple templates while keeping a wrapper for some pages I'm trying to figure out how to nest 3 templates and have them inherit the blocks. How can I sometimes reference the child.html when I need a wrapper and sometimes not reference it. Maybe I'm trying to do this the wrong way? Thank you for your feedback.

parent.html

{% block contentBlock %}
{% endblock %}

child.html

<div>
{% extends "parent" %}
{% block content %}
</div>

child-child.html

{% extends "child" %}
{{ title }}

child2.html

{% extends "parent.html" %}
{% block contentBlock %}
{{ title }}

In my experience, this is the type of situation where you may want to consider having a second layout rather than opting for a more complicated inheritance scheme. If your layouts are somewhat complex and you want to keep your markup DRY I would suggest moving the more complex components of your layout into includes.

Also, when I get beyond the Layout » Template relationship, instead of defining blocks and extending the Template I opt for includes there as well. This makes my workflow efficient because I always consider the Template to be the base point, inheriting up into the Layout and inheriting down into any includes.

layout_1col.html

<!DOCTYPE html>
{% include 'head' %}

  {% include 'header' %}

    {% block 'main' %}{% endblock %}

  {% include 'footer' %}

layout_2col.html

<!DOCTYPE html>
{% include 'head' %}

  {% include 'header' %}

    {% block 'main' %}{% endblock %}

    {% block 'sidebar' %}{% endblock %}

  {% include 'footer' %}

MyTemplate.html

{% extends 'layout_1col' %}
{% block 'main' %}

My content

  {% include 'mywidget' %}
{% endblock %}

By letting your layouts rely heavily on includes you can let them vary only where needed but keeping your inheritance logic simple and easily extended.


Restrict access to Element API endpoint I'd like to Restrict access to Element API endpoint by the current user's group.

Is this possible Using Craft 2?

Yes it is you can see here how to check permissions

You can get the current user with

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

Then you can check the same conditions like in the example link. If the conditions are false you can return an empty array instead of your endpoints

if(!$currentUser->isInGroup('groupHandle')) {
    return [];
}

Please make sure to check if the current user is not null


Best approach for building a webshop with more than one URL to the same product (entry) What would be the best approach to a webshop in Craft, for solving the possibility of having products on more that on URL. Is there a best practice for one entry being accessible from more than one url? We use canonical for SEO.

Here is a quick summary of the current approach that works, but may be totally overkill :)

Products are stored in a Channel.
A product can be related to several entries in Structures > Product Categories.
The product uri is for example /shop/category/subcategory/product - meaning that one product can have more than one location (url). The SEO issue with this is handled with canonical URLs (further down). The reason we want the product in several locations is that the store is for example selling a certain boot both as a "hiking boot" and a "hunting boot", so the context is different and it won't work as well going to domain.com/products/name without the category (keyword rich) structure in the url. Also having all product entries at the same base url like that (/products/name/) takes the user out of their current context in general (breadcrumb + section specific content/design) if they clicked the product at domain.com/shop/boots/hiking/high/.
3 routes are setup to send /shop/* (1-3 levels adding /* for each) to the ecommerce/_product template.
Entry is not found when entering a product in this way, so if entry is not defined, it is set to be the one matching the last segment of the current URL (matched by slug).
Now we're good to go to show the actual product entry.
The issue of SEO (penalty for duplicate content) is handled with "canonical". I get all entries from Product Categories with a relation to the product (reversed relation), and defining the first one in that loop to be the main location (random - could be set as a relation on product level for the user to decide, but that requires "manual control" and may be hard for the client to relate to), and all other URLs showing the product in a different category that the main location will get  in the header.
In product listings we find the uri to each product again with reversed relations to all categories that has a relation to that product, and we prioritize the product category we are currently in. If the product is listed outside any of its product categories (like on a product page as a related product) it ends up with the base url from the last reversed related product category.

If you think this approach works well or if you have any other ideas.

UPDATE:

I started out with native Categories for product categories. But the client is a brand selling their own product on their site, and each product category is a page with quite a bit more content than just the products, so I have a structure with an entry type for productCategory with several tabs (not possible for a Category).

My two cents:

I wouldn't use different url's for the same product, that's considered bad seo. Instead use something like domain.com/product/slug. That way you can change product categories while keeping the links intact, and it'll be easier to get the url of entries.
If there is no specific reason for using structures, use native categories.
Instead of reverse-relations for seo-information, a simpler solution like Sprout SEO might be better.

tl;dr: keep it simple


Is it possible to extend the lifetime of the CraftSessionId cookie? I would like to extend the lifetime of the CraftSessionId cookie. Is this possible and if so, where can I change the value?

Thank you for your time.

Craft's CraftSessionId cookie is simply the PHP Session cookie renamed and by default it's terminated when the browser is closed.

Craft currently doesn't expose any way to alter that behavior, but you can always make a feature request!


Listing All tags - and linking them to list of entries with that tag I have a blog, and in the sidebar I have listed all tags in use. I would like to link each tag - when you click it I want to link to a page that lists all the blog entries which have that tag applied to them. Cant find this in the docs.. would someone mind helping? Here is my code so far:

    {% set entries = craft.entries.section('blog').limit(null) %}
         {% for tag in craft.tags %}

{{ tag.title }}

    {% endfor %}

MY RESULTS: This code is linking to for example mysite.com/blog-page/88 - and giving me a page not found. I have a template blog-page and the path is correct as the page loads if you remove the tag-id off the end.

Thanks

You don't have a setting in Craft to make Tags have their own pages automatically. So what you have to do instead, is to set up a dynamic route in Settings → Routes. Create a new route which routes these URIs: blog/tags/[slug] (drag the slug token into the URI field) to a template blog/_tags.html.

In your blog/_tags.html template you will now have a slug variable available, but you still need to query for the tag model / entry models.

{% set tag = craft.tags.slug(slug).first() %}
{% if not tag %}{% exit 404 %}{% endif %}

{% set entries = craft.entries.section('blog').relatedTo(tag).limit(null) %}

{{ tag.title }}

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

I'd also modify the tag listing to only show tags that are actually related to an entry, and use the tags' (undocumented) slug property for SEO purposes:

{% set entries = craft.entries.section('blog').limit(null) %}
{% set tags = craft.tags.relatedTo(entries).limit(null) %}

{% for tag in tags %}
    {{ tag.title }}
{% endfor %}


Override the output of class S3AssetSourceType->getBucketList from a plugin My issue is that for security I don’t have the s3:ListAllMyBuckets permission (as I can only see one bucket), but not list them. Craft needs this to function, so I need to manually force the list of one bucket.

I am trying to override the output of class S3AssetSourceType->getBucketList from a plugin (in Craft 2) to return my own list.

In Craft 3 I’d create my own AssetSource. I guess I’m going to need to amend the core (I know very bad), but I think its the only option I have at this stage (unless anyone has a bright idea). We won’t allow updates via the CMS, so I could write a unit test to check the output is as I have amended it after any core updates. Also, I’d assume that S3AssetSourceType won’t be edited much in Craft 2.

Not an ideal solution, but its the only way I can think of doing it. I have tried every other workaround I can think about (before editing the core code). I looked at mounting the filesystem using s3fs-fuse on Ubuntu, but Docker won’t allow it in our setup.

Anyway, any help would be much appreciated before I start hacking away… thanks.

OK, this doesn't completely answer my question, but I think this is the more elegant solution to the problem I was trying to solve. If you don't have the all s3:ListAllMyBuckets permission available in AWS then the following plugin code will allow you to pass in a static bucket list. This meant I didn't have to start hacking the core code.

<?php
namespace Craft;

class MyPlugin extends BasePlugin
{
    public function init()
    {
        parent::init();

        if(isset($_GET['p']) && $_GET['p'] == "admin/actions/assetSources/getS3Buckets")
        {
            // Requires an admin
            craft()->userSession->requireAdmin();

            // Making the money
            craft()->requireEdition(Craft::Pro);

            $bucketList = array();

            $bucketList[] = array(
                'bucket' => 'my-bucket-name',
                'location' => 'EU',
                'urlPrefix' => 'http://s3-eu-west-1.amazonaws.com/my-bucket-name/'
            );

            $this->returnJson($bucketList);
        }
    }

    private function returnJson($var = array(), $options = array())
    {
        // Set the 'application/json' Content-Type header
        JsonHelper::setJsonContentTypeHeader();

        $options = array_merge(array(
            'expires' => false,
        ), $options);

        // Set the Expires header
        if ($options['expires'] === false)
        {
            HeaderHelper::setNoCache();
        }
        else if ($options['expires'])
        {
            HeaderHelper::setExpires($options['expires']);
        }

        // Output it into a buffer, in case TasksService wants to close the connection prematurely
        ob_start();
        echo JsonHelper::encode($var);

        craft()->end();
    }
}