# Question
Title: How do I add a content-type header to my template?
I am trying to build out an api template inside our CMS to expose a particular channel as json. I'm going to call that channel "public." Here's the template that I have put together thus far:

```
[
{exp:channel:entries channel="public" dynamic="no"
    limit="{segment_3}"
    offset="{segment_4}"
    orderby="{segment_5}"
}

    { "title" : "{title}", "source" : "{public_html}" }{if count < total_results},{/if}
{/exp:channel:entries}
]

```

There are two channel fields defined `public_html` and `public_css` that represent the stored contents of the content item. As is, it is delivering my data as `text/html` and I am needing to switch it to `application/json` to instruct the browser.

So, I tried adding

`<?php header("Content-Type: application/json"); ?>`

to the top of my template (moved it around and saw no changes), but it is still delivering text/html (verified through fiddler) In the long run, I can handle text/html in my service layer, but I would really prefer this to be done right.

How do I add the `Content-Type: application/json` HTTP Header to the template that I provided?

# Answer
You can use the HTTP Header plugin for this:

```
{exp:http_header content_type="application/json"}

```
> 2 votes

---
Tags: ee2, templates, php, headers
---


# Question
Title: Freeform: Number of fields: which is better
I am building a form with Freeform Pro that has 80 fields and am wondering the best way to go. The form is contains 4 parts, so my question is:

Should I create 1 form with 80 fields or 4 forms with 20 fields each?

I have been looking into database normalization and am wondering if this concept mostly pertains mainly to really, really large databases with way more than 100 columns. Also, this form probably won't get more than 20100 submissions per year.

Thanks

# Answer
With as few as 80 columns I wouldn't split things into 4 forms. Freeform sets everything as a TEXT type field when it builds a form table because then the content is stored separately from the row itself and it allows for more columns.

https://dev.mysql.com/doc/refman/5.0/en/column-count-limit.html

Field counts on forms have been a historically higher complaint to us than performance of TEXT type DB columns, so we made our decision for that reason.

20100 Form submissions isn't a lot in the scheme of things. You will have some performance issues if you are going to be filtering a lot with Freeform:Entries on the front end. It wont be a big hit, but to get the absolute best performance in that situation, pick the fields that will be filtered on the most and if they are small (like an email address or a selection field choice, not a textarea style input) then convert those to varchar fields and put table indexes on them.
> 1 votes

---
Tags: solspace-freeform
---


title: Order by Price Expresso Store

text:
# Question
Title: Order by Price Expresso Store
Just wondering how I can get to order products in Expresso Store by Price (High to Low and Low to High) using a drop down.

I've got sort working by using Dynamic Parameters but can't work out how to do this with Price?

# Answer
Silly me with a little more thought I just need to orderby "price" and then use sort "asc or desc"

Using Mo Variables to select the correct option from my drop down.

```
<form method="post" action="{path='shop/category/{segment_3}{if current_query_string}?{current_query_string}{/if}'}">
                <input type="hidden" name="csrf_token" value="{csrf_token}" />
                    <select name="sort">
                      <option {if post:sort == "desc"} selected="selected"{/if} name="sort" value="desc">Descending</option>
                      <option {if post:sort == "asc"} selected="selected"{/if} name="sort" value="asc">Ascending</option>
                    </select>
                    <select name="orderby">
                        <option {if post:orderby == "price"} selected="selected"{/if} name="orderby" value="price">Price</option>
                        <option {if post:orderby == "title"} selected="selected"{/if} name="orderby" value="title">Name</option>
                   </select>
               </div>
        <div class="small-2 columns">
        <input role="button" aria-label="Submit" name="submit" type="submit" class="button postfix submit" value="Go" />
</form>

```
> 0 votes

---
Tags: expresso-store, expresso
---


# Question
Title: How to add taxes and cardholder name to Charge?
Im trying to setup Subscription using Charge. But in test mode i havent yet found a way how I can include taxes and cardholders name to actual form and receipt.

I tried to look at addon dokumentation but only what i found was the tag for cardholders name. I did try to use text input and run one test, but again, in Stripe dashboard, name was missing.

About taxes i didnt find anything but that is a must to include.

Any advice would be more than welcome, thank you.

# Answer
Stripe as a payment processor doesn't really care about shipping or tax related information because they try to make it easy to charge your customers.

> Our current goal is to make it easy for you to accept any payment from your customers. We focus on providing a simple interface through which you can create charges.
>
> ```
> With that in mind, we don’t currently calculate any sales tax, VAT, tips, shipping, or other costs for your one-time charges.
>
> ```
>
> Instead, we will let you specify the final amount you’d like your customer to be charged, so you can include the total price in the `amount` field.

Having said that the best approach is to use Stripe Metadata feature to pass taxes, shipping cost and anything else that you need to Stripe. Once you pass the metadata you can then use that data in custom reports and any and all metadata is included with Stripe Exports.

The docs are a little light for Charge's Meta tags but Joel has taken the time to create a very robust example template that you can look through.

In your template you will need to calculate the taxes and whatever else you might need with some javascript or template logic then submit that along with your order to Stripe.
> 0 votes

---
Tags: payment-gateway, charge
---


# Question
Title: Passing a value to a low variable 'snippet'
When using Low Variables as one would use embeds to include a block of code, is it possible to pass a variable into that code?

For instance,

```
{lv_mysnippet foo="bar"}

```

So that I can used the value of foo within the low variable?

# Answer
Using preload-replace vars is possible, but the vars need to have early parsing enabled for it to work.

If you're using the Textarea var type, you can also use Tag syntax (rather than the Variable syntax) and use the `preparse:my_var="value"` parameters, eg:

```
{exp:low_variables:single var="my_textarea_var" preparse:myvar="foo"}

```
> 1 votes

# Answer
I've realised that I can simply use {preload\_replace}

```
{preload_replace myvar="foo"}

{lv_mysnippet}

```

This lets me use the value of myvar within {lv\_mysnippet}
> 0 votes

---
Tags: low-variables
---


title: Updating EE versions and plugins

text:
# Question
Title: Updating EE versions and plugins
Just wondering how others out there track updates for their EE sites and plugins.

I come from the WordPress world where I had tools like InifniteWP to see all my sites, if updates were available, etc. I could then update as needed. Typically pulling down to my dev server, testing the updates, and then pushing those to the live production site.

However now I am taking over a front-end dev team where we have 100+ EE sites. They've always had a set it and forget it mentality and we are starting to change that. Are their tools where I can monitor all my EE installs (not being on multi-site)? What are best practices for when to update plugins and how can I easily be notified when they are available? I'd like to start a maintenance schedule and a running list of what sites are using what plugins, so we can schedule times when we plan to test and push any necessary updates. thanks.

# Answer
You're after Lamplighter and the add-on that accompanies it.
> 3 votes

---
Tags: update
---


# Question
Title: Wygwam Images Alternative Text mandatory field
Has anyone found a way of making the alternative text field in the Wygwam images dialogue box mandatory.I have a large number of users and its something they always forget to do when adding images. Thanks

# Answer
Open this file: `THEMES_FOLDER/third_party/wygwam/lib/ckeditor/plugins/image/dialogs/image.js`

Look for `id:"txtAlt",` and replace it with `id:"txtAlt",validate:CKEDITOR.dialog.validate.notEmpty("ALT text required"),`

That should work...
> 0 votes

---
Tags: wygwam
---


# Question
Title: Relationship Field Dropdown Values more than {title} in Backend
I have a relationship Field. I would like to show the category in front of the title within the Dropdown-List. Any plugin? Other Solution? Or do I have to alter the core of EE relationship field?

I'd like to see this in the dropdown list:

```
Category A -> {title_1}
Category A -> {title_2}
Category A -> {title_3}
Category B -> {title_4}
Category B -> {title_5}

```

Any Hints?

# Answer
> 0 votes
No add-on I know of will do this, and even alternate relationship fieldtypes like Playa don't allow you to customize the item titles on the publish screen.

Unfortunately, hacking core would be a) a bad idea, and b) require extra queries to get the category data for each item as well.

# Answer
> 0 votes
The only way I know to do anything here is to use an addon like https://devot-ee.com/add-ons/mx-title-control to actually change the title of the entries, so then they will display with the desired info in the relationship fieldtypes.

You may need to then create a 'Page Title' field for use in displaying on the site.

---
Tags: categories, relationships, drop-down
---


title: DevDemon Forms Mailchimp

text:
# Question
Title: DevDemon Forms Mailchimp
I'm using DevDemon Forms module and want to map entries to MailChimp. I inserted my API key into the Settings panel and have added a Subscribe to Mailing field type in form. But there are no available options within mailing services to choose from -- where I would expect to see my Mailchimp account lists.

Any advice?

Thanks,

Colin

# Answer
I just did the same procedure and it will populate the list you have in Mailchimp. I had only one list and it worked fine. I'm guessing here that the API Key is linked with the name of that only list. I'm not sure what happens with two lists...
> 0 votes

---
Tags: devdemon, devdemon-forms, mailchimp
---


# Question
Title: Conditionals from within Piped String of values
I have a string of piped category ID's which represent all the categories which are selected for any given page.

Within my page, I now need to check the input of the chosen categories.

For example, I have `{segment_category_ids_piped}` (I'm using Low Seg2Cat) - this returns `"3|5|6|14"`.

In my category loop, I now need to check the checkbox if the category exists. The code I have at the moment is :

`<li><input type="checkbox" {if segment_category_ids_piped *= cat_id}checked="checked"{/if}><a href="#" title="{cat_name}">{cat_name}<span>({entry_count})</span></a></li>`

The problem is that it's treated as a literal string, so if I loop through my categories, it's showing cat\_id 1 and 4 as being selected, because they are represented in the string for 14.

I'm presuming that a regular expression would be needed here, but I'm at a bit of a loss as to the syntax (RegExp has never been a strong point of mine!).

Thanks

# Answer
Try this:

```
{if segment_category_ids_piped ~ '/\b'.cat_id.'\b/'}

```

Note: this works for pipe-separated **IDs** (numbers). If you're looking for pipe-separated strings or text, you'd be better off using this:

```
{if piped_text ~ '/(^|\|)'.text.'(\||$)/'}

```
> 4 votes

---
Tags: categories, conditionals, low-seg2cat
---


# Question
Title: Dreaded Email notifications and Cartthrob
I seem to be having some issues with email notifications within Cartthrob at present. Now i know these have cropped up in the past, so I'm just trying to get my head around the best case scenario for this and the pitfalls to watch out for. Obviously the email notifications are pretty important for a client, and its a pain when they can be at times pretty hit and miss.

So I'm working on a clients site that we have switched to Stripe over PayPal which seems to be fine at present. The order confirmations are coming back ok, and the orders are been created in the Order channel.

But there are no notifications been sent out at all. This is currently on a development server for testing and I've gone ahead and tested that i can trigger the emails using:

```
<?php
if (mail('you@yourdomain.com', 'Quick email test', 'Is this on?'))
{
    echo 'Mail sent successfully.';
}
else
{
    echo 'Mail was not sent.';
}

```

And thats sending both using an email local to the development server and also the clients email. So i know thats working ok.

---

Ive also looked at the settings in the Cartthrob CP and made sure those notifications are correct.

Ive even simplified the templates been used right down to say literally Thanks for Ordering, Here is a new order etc. respectively. No extra tags or information.

---

I've also checked in the exp\_cartthob\_email\_log and its saying that email\_event has been completed. But nothing is arriving. SO totally baffled.

Anyone have any ideas?

# Answer
Well thanks to John Baxter i have the solution to all my issues with email notifications, but as I've said to John I'm both super pleased its solved but frustrated at the reason. So thought good to post..

Basically the option of Log Email.. if this is set to either NO, or Log but don't send then it doesn't send the notifications!.. now to me this means either log or don't log, or send the log.. not send the notifications at all? but I'm posting for others, and either way I'm appreciative for John and the heads up. Hope this helps others, or maybe its just me.
> 1 votes

---
Tags: cartthrob, stripe
---


title: Cleaning up orphaned relationships

text:
# Question
Title: Cleaning up orphaned relationships
I have a few relationship rows that is causing some errors in the EE install. Turns out these relationships have either the parent id or the child id referencing a entry that no longer exists.

Is it safe to just delete these rows in the relationship table?

# Answer
Yes, that should be safe. Make a database backup first just in case. And for best results test on a local development copy of the site rather than in production.
> 0 votes

---
Tags: relationships
---


# Question
Title: Sagepay Protocol 3.00 - upgrading cartthrob gateway
I've been trying (without success) to upgrade the Cartthrob\_sage\_s.php gateway on Cartthrob for SagePay Europe Offsite, in order to utilise the 3.00 protocol (upgrading from 2.23. I'm running latest editions of EE (2.9.2) and Cartthrob (2.61).

On just editing the VPSprotocol field to 3.00 in the 3 locations in file, the gateway progresses to processing of payment, then returns a VPSsignature error (which I expected, since other fields are listed as mandatory in the gneeric upgrade guidelines from Sage).

On attempting to add BankAuthCode, DeclineCode and ExpiryDate to my response as part of the generated MD5, I still get a mismatch between that and the VPS signature generated by Sage (VPS signature error as above). I've established I must be missing something, but I'm not sure what - I double checked and removing the new fields and restoring protocol to 2.23 makes the gateway function again.

I've attached file contents for clarity (apologies for length):

```
<?php class Cartthrob_sage_s extends Cartthrob_payment_gateway {
public $title = 'sage_server_title';
public $affiliate = 'sage_affiliate';
public $overview = 'sage_overview';
public $language_file = TRUE;
public $settings = array(
    array(
        'name' => 'sage_payment_page_style',
        'short_name' => 'profile',
        'type' => 'radio',
        'default' => 'NORMAL',
        'options' => array(
            'NORMAL' => 'sage_normal',
            'LOW' => 'sage_minimal_formatting'
            ),
    ),
    array(
        'name' =>  'mode',
        'short_name' => 'mode',
        'type' => 'radio',
        'default' => 'test',
        'options' => array(
            'simulator' => 'simulator',
            'test' => 'test',
            'live' => 'live'
            ),
    ),
    array(
        'name' => 'sage_vendor_name',
        'short_name' => 'vendor_name',
        'type' => 'text',
    ),
);

public $required_fields = array(
    'first_name',
    'last_name',
    'address',
    'city',
    'zip',
    'country_code'
);

public $fields = array(
    'first_name'           ,
    'last_name'            ,
    'address'              ,
    'address2'             ,
    'city'                 ,
    'state'                ,
    'zip'                  ,
    'country_code'         ,
    'shipping_first_name'  ,
    'shipping_last_name'   ,
    'shipping_address'     ,
    'shipping_address2'    ,
    'shipping_city'        ,
    'shipping_state'       ,
    'shipping_zip'         ,
    'shipping_country_code',
    'phone'                ,
    'email_address'        ,
    );

public $hidden = array('description','currency_code');

/**
 * process_payment
 *
 * @param string $credit_card_number
 * @return mixed | array | bool An array of error / success messages  is returned, or FALSE if all fails.
 * @author Chris Newton
 * @access public
 * @since 1.0.0
 */
public function charge($credit_card_number)
{

    if ($this->plugin_settings('mode') == "test")
    {
        $this->_host = "https://test.sagepay.com/gateway/service/vspserver-register.vsp";
        $this->tokenrebillhost = "https://test.sagepay.com/gateway/service/vspdirect-register.vsp";
        $this->tokenhost = "https://test.sagepay.com/gateway/service/token.vsp";

    }
    elseif ($this->plugin_settings('mode') == "simulator")
    {
        $this->_host = "https://test.sagepay.com/Simulator/VSPServerGateway.asp?Service=VendorRegisterTx";
    }
    else
    {
        $this->tokenrebillhost = "https://live.sagepay.com/gateway/service/vspdirect-register.vsp";
        $this->tokenhost = "https://live.sagepay.com/gateway/service/token.vsp";

        $this->_host = "https://live.sagepay.com/gateway/service/vspserver-register.vsp";
    }

    $auth['authorized']     =   FALSE;
    $auth['declined']       =   FALSE;
    $auth['failed']         =   TRUE;
    $auth['error_message']  =   NULL;
    $auth['transaction_id'] =   NULL;

    /*
    // find out if this needs SSL
    if (!function_exists('openssl_open'))
    {
        $auth['error_message']  = $this->lang('gateway_requires_ssl');
        return $auth;
    }
    */

    $basket="";

    if ($this->order('items'))
    {
        $basket = (count($this->order('items'))+2).":";

        foreach ($this->order('items') as $row_id => $item)
        {
            $basket .= str_replace(":","",$item['title']) .":";
            $basket .= $item['quantity'] .":";
            $basket .= number_format($item['price'],2,'.','').":";
            $basket .= ":";
            $basket .= number_format($item['price'],2,'.','').":";
            $basket .= number_format(($item['price']*$item['quantity']),2,'.','').":";

        }
        $basket .= 'Shipping:----:----:----:----:';
        $basket .= number_format($this->order('shipping'), 2, '.', '').":";
        $basket .= 'VAT/Tax:----:----:----:----:';
        $basket .= number_format($this->order('tax'), 2, '.', '');
    }

    if (strlen($basket) > 7499)
    {
        // the basket can't be over 7500, and has to be formatted a specific way. We'll remove it if it's too long.
        $basket = "";
    }

    $country_code = $this->order('country_code') ? $this->alpha2_country_code($this->order('country_code')) : "GB";
    $shipping_country_code = $this->order('shipping_country_code') ? $this->alpha2_country_code($this->order('shipping_country_code')) : $country_code;

    $post_array = array(
        'VPSProtocol'       => "3.00",
        'TxType'                => "PAYMENT",
        'Website'           => "eqvvs.co.uk",
        'Vendor'                => $this->plugin_settings('vendor_name'),
        'VendorTXCode'      => $this->order('entry_id')."_".time(), // needs a unique ID for this transaction.
        'Amount'                => number_format($this->total(),2,'.',''),
        'Currency'          => ($this->order('currency_code') ? $this->order('currency_code') : "GBP"),
        'Description'       => substr(($this->order('description') ? $this->order('description') : "Purchase from ".$this->order('site_name')), 0, 40),
        'NotificationURL'   => $this->response_script(ucfirst(get_class($this))),
        'CustomerEMail'     => $this->order('email_address'),
        'BillingFirstnames' => substr($this->order('first_name'), 0, 20),
        'BillingSurname'        => substr($this->order('last_name'),0,20),
        'BillingAddress1'   => substr($this->order('address'), 0, 100),
        'BillingAddress2'   => substr($this->order('address2'), 0, 100),
        'BillingCity'       => substr($this->order('city'), 0, 40),
        'BillingPostCode'   => substr($this->order('zip'), 0, 10),
        'BillingCountry'        => $country_code,
        'BillingState'      => "",
        'BillingPhone'      => preg_replace('/[^0-9-]/', '', $this->order('phone')),
        'DeliveryFirstnames'    => substr(($this->order('shipping_first_name') ? $this->order('shipping_first_name') : $this->order('first_name')), 0, 20),
        'DeliverySurname'   => substr(($this->order('shipping_last_name') ? $this->order('shipping_last_name') : $this->order('last_name')),0,20),
        'DeliveryAddress1'  => substr(($this->order('shipping_address') ? $this->order('shipping_address') : $this->order('address')), 0, 100),
        'DeliveryAddress2'  => substr(($this->order('shipping_address2') ? $this->order('shipping_address2') : $this->order('address2')), 0, 100),
        'DeliveryCity'      => substr(($this->order('shipping_city') ? $this->order('shipping_city') : $this->order('city')), 0, 40),
        'DeliveryPostCode'  => substr(($this->order('shipping_zip') ? $this->order('shipping_zip') : $this->order('zip')), 0, 10),
        'DeliveryCountry'   => $shipping_country_code,
        'DeliveryState'     => "",
        'DeliveryPhone'     => preg_replace('/[^0-9-]/', '', $this->order('phone')),
        'Basket'                => $basket
    );

    if (strlen($post_array['NotificationURL']) > 250)
    {
        $resp = array(
             'authorized'       =>  FALSE,
             'error_message'    =>  $this->lang('sage_s_notification_url_too_long'),
             'failed'           =>  TRUE,
             'declined'         =>  FALSE,
             'transaction_id'   =>  NULL,
            );
        return $resp;
    }

    // We don't want to pass the state data to eWay unless it has 2 characters and is a us state. They don't accept any non-us state values
    if ("US" != $post_array['DeliveryCountry'])
    {
        $post_array['DeliveryState']  = "";
    }
    else
    {
        $post_array['DeliveryState'] = strtoupper($this->order('shipping_state') ? $this->order('shipping_state') : $this->order('state'));
    }
    if ("US" != $post_array['BillingCountry'])
    {
        $post_array['BillingState']  = "";
    }
    else
    {
        $post_array['BillingState'] = strtoupper($this->order('state'));
    }

    $post_array['Profile']  = $this->plugin_settings('profile');

    $data =     $this->data_array_to_string($post_array);

    $connect =  $this->curl_transaction($this->_host,$data);

    if (!$connect)
    {
        $auth['failed']         = TRUE;
        $auth['authorized']     = FALSE;
        $auth['declined']       = FALSE;
        $auth['error_message']  = $this->lang('curl_gateway_failure');
        return $auth;
    }

    $transaction =  $this->split_url_string($connect, "\r\n");
    $next_url = explode("NextURL=", $connect);

    if (!empty($next_url[1]))
    {
        $next_url = str_replace("\r\n","",$next_url[1]);
    }

    if (!is_array($transaction))
    {
        $auth['failed']         = TRUE;
        $auth['authorized']     = FALSE;
        $auth['declined']       = FALSE;
        $auth['error_message']  = $this->lang('sage_failed');

        return $auth;
    }

    if ("OK" != strtoupper($transaction['Status']))
    {
        switch(strtoupper($transaction['Status']))
        {
            case "MALFORMED":
                $auth['error_message'] = $this->lang('sage_malformed');
                $auth['error_message'] .= $transaction['StatusDetail'];
                break;
            case "INVALID":
                $auth['error_message'] = $this->lang('sage_invalid');
                $auth['error_message'] .= $transaction['StatusDetail'];
                break;
            case "ERROR":
                $auth['error_message'] = $this->lang('sage_error');
                break;
            default:
                $auth['error_message'] = $this->lang('sage_default');
        }

        $auth['failed']         = TRUE;
        $auth['authorized']     = FALSE;
        $auth['declined']       = FALSE;
        $auth['transaction_id'] = NULL;
        return $auth;
    }

    $this->update_order(array('sage_key' => $transaction['SecurityKey']));
    $this->gateway_exit_offsite(NULL, $next_url); exit;
}
public function charge_token($token, $customer_id)
{
    $resp = array(
         'authorized'       =>  FALSE,
         'error_message'    =>  NULL,
         'failed'           =>  TRUE,
         'declined'         =>  FALSE,
         'transaction_id'   =>  NULL,
        );

    switch ($this->order('card_type'))
    {
        case "mc":
            $card_type="MC";
            break;
        case 'visa':
            $card_type="VISA";
            break;
        case 'amex':
            $card_type="AMEX";
            break;
        case 'maestro':
            $card_type="MAESTRO";
            break;
        case 'solo':
            $card_type="SOLO";
            break;
        case 'delta':
            $card_type="DELTA";
            break;
        default: $card_type="VISA";
    }
    $basket="";

    if ($this->order('items'))
    {
        $basket = (count($this->order('items'))+2).":";

        foreach ($this->order('items') as $row_id => $item)
        {

            $basket .= $item['title'] .":";
            $basket .= $item['quantity'] .":";
            $basket .= number_format($item['price'],2,'.','').":";
            $basket .= ":";
            $basket .= number_format($item['price'],2,'.','').":";
            $basket .= number_format(($item['price']*$item['quantity']),2,'.','').":";

        }
        $basket .= 'Shipping:----:----:----:----:';
        $basket .= number_format($this->order('shipping'), 2, '.', '').":";
        $basket .= 'VAT/Tax:----:----:----:----:';
        $basket .= number_format($this->order('tax'), 2, '.', '');
    }

    $post_array = array(
        'VPSProtocol'               => "3.00",
        'TxType'                    => 'PAYMENT',
        'Vendor'                    => $this->plugin_settings('vendor_name'),
        'VendorTxCode'              => $this->order('entry_id')."_".time(),
        'Amount'                    => number_format($this->order('total'),2,'.',''),
        'Currency'                  => ( $this->order('currency_code')?  $this->order('currency_code') : "GBP"),
        'Description'               =>  ($this->order('description') ? $this->order('description') : "Purchase from ".$this->order('site_name')),
        'Token'                     => $token,
        'StoreToken'                => 1,
        'BillingSurname'            => $this->order('last_name'),
        'BillingFirstnames'         => $this->order('first_name'),
        'BillingAddress1'           => $this->order('address'),
        'BillingAddress2'           => $this->order('address2'),
        'BillingCity'               => $this->order('city'),
        'BillingPostCode'           => $this->order('zip'),
        'BillingCountry'            => $this->alpha2_country_code($this->order('country_code')),
        'BillingPhone'              => preg_replace('/[^0-9-]/', '', $this->order('phone')),
        'DeliverySurname'           => ($this->order('shipping_last_name') ? $this->order('shipping_last_name') : $this->order('last_name')),
        'DeliveryFirstnames'        => ($this->order('shipping_first_name') ? $this->order('shipping_first_name') : $this->order('first_name')),
        'DeliveryAddress1'          => ($this->order('shipping_address') ? $this->order('shipping_address') : $this->order('address')),
        'DeliveryAddress2'          => ($this->order('shipping_address2') ? $this->order('shipping_address2') : $this->order('address2')),
        'DeliveryCity'              => ($this->order('shipping_city') ? $this->order('shipping_city') : $this->order('city')),
        'DeliveryPostCode'          => ($this->order('shipping_zip') ? $this->order('shipping_zip') : $this->order('zip')),
        'DeliveryCountry'           => ($this->order('shipping_country_code') ? $this->alpha2_country_code($this->order('shipping_country_code')) : $this->alpha2_country_code($this->order('country_code'))),
        'CustomerEMail'             => $this->order('email_address'),
        'Basket'                    => $basket,
        'Apply3DSecure'             => 0,
    );
    // We don't want to pass the state data to Sage unless it has 2 characters and is a us state. They don't accept any non-us state values
    if ("US" != $post_array['DeliveryCountry'])
    {
        $post_array['DeliveryState']  = "";
    }
    else
    {
        $post_array['DeliveryState'] = strtoupper($this->order('shipping_state'));
    }
    if ("US" != $post_array['BillingCountry'])
    {
        $post_array['BillingState']  = "";
    }
    else
    {
        $post_array['BillingState'] = strtoupper($this->order('state'));
    }

    $data =     $this->data_array_to_string($post_array);
    $connect =  $this->curl_transaction($this->tokenrebillhost,$data);

    if (!$connect)
    {
        $resp['failed']         = TRUE;
        $resp['authorized']     = FALSE;
        $resp['declined']       = FALSE;
        $resp['error_message']  = $this->lang('curl_gateway_failure');

        return $resp;
    }

    $transaction = $this->sage_string_split($connect);

    if (!empty($transaction['Status']))
    {
        if ("OK" == strtoupper($transaction['Status']))
        {
            $resp = array(
                 'authorized'       =>  TRUE,
                 'error_message'    =>  NULL,
                 'failed'           =>  FALSE,
                 'declined'         =>  FALSE,
                 'transaction_id'   =>  trim($transaction['VPSTxId'], "{}")
                );
        }
        else
        {
            switch(strtoupper($transaction['Status']))
            {
                case "MALFORMED":
                $error_message = $this->lang('sage_malformed');
                $error_message .= $transaction['StatusDetail'];
                break;
                case "INVALID":
                $error_message = $this->lang('sage_invalid');
                $error_message .= $transaction['StatusDetail'];
                break;
                case "ABORT":
                $error_message = $this->lang('transaction_cancelled');
                break;
                case "NOTAUTHED":
                $error_message = $this->lang('sage_notauthed');
                break;
                case "REJECTED":
                $error_message = $this->lang('sage_rejected');
                break;
                case "PPREDIRECT":
                $error_message = $this->lang('sage_ppredirect');
                break;
                case "AUTHENTICATED":
                $error_message = $this->lang('sage_authenticated');
                break;
                case "REGISTERED":
                $error_message = $this->lang('sage_registered');
                break;
                case "ERROR":
                $error_message = $this->lang('sage_error');
                break;
                case "ATTEMPTED":
                $error_message =  $this->lang('sage_error')."; ATTEMPTED"; //$this->lang('sage_ATTEMPTED');
                break;
                case "NOTAVAILABLE":
                $error_message = $this->lang('sage_error')."; NOTAVAILABLE";  //$this->lang('sage_NOTAVAILABLE');
                break;
                case "INCOMPLETE":
                $error_message = $this->lang('sage_error')."; INCOMPLETE"; //$this->lang('sage_INCOMPLETE');
                break;
                default:
                $error_message = $this->lang('sage_default');
            }

            $resp = array(
                 'authorized'       =>  FALSE,
                 'error_message'    =>  $error_message,
                 'failed'           =>  TRUE,
                 'declined'         =>  FALSE,
                 'transaction_id'   =>  NULL
                );
        }
    }
    return $resp;
}

public function create_token($credit_card_number)
{
    $post_array = array(
        'VPSProtocol'               => "3.00",
        'TxType'                    => 'TOKEN',
        'Vendor'                    => $this->plugin_settings('vendor_name'),
        'Currency'                  => ( $this->order('currency_code')?  $this->order('currency_code') : "GBP"),
        'NotificationURL'           => $this->response_script(ucfirst(get_class($this)), array('create_token')),
        'Profile'                     => $this->plugin_settings('profile'),
    );

    $data =     $this->data_array_to_string($post_array);

    $connect =  $this->curl_transaction($this->tokenhost,$data);

    if (!$connect)
    {
        $auth['failed']         = TRUE;
        $auth['authorized']     = FALSE;
        $auth['declined']       = FALSE;
        $auth['error_message']  = $this->lang('curl_gateway_failure');
        return $auth;
    }

    $transaction =  $this->split_url_string($connect, "\r\n");
    $next_url = explode("NextURL=", $connect);

    if (!empty($next_url[1]))
    {
        $next_url = str_replace("\r\n","",$next_url[1]);
    }

    if (!is_array($transaction))
    {
        $auth['failed']         = TRUE;
        $auth['authorized']     = FALSE;
        $auth['declined']       = FALSE;
        $auth['error_message']  = $this->lang('sage_failed');

        return $auth;
    }

    if ("OK" != strtoupper($transaction['Status']))
    {
        switch(strtoupper($transaction['Status']))
        {
            case "MALFORMED":
                $auth['error_message'] = $this->lang('sage_malformed');
                $auth['error_message'] .= $transaction['StatusDetail'];
                break;
            case "INVALID":
                $auth['error_message'] = $this->lang('sage_invalid');
                $auth['error_message'] .= $transaction['StatusDetail'];
                break;
            case "ERROR":
                $auth['error_message'] = $this->lang('sage_error');
                break;
            default:
                $auth['error_message'] = $this->lang('sage_default');
        }

        $auth['failed']         = TRUE;
        $auth['authorized']     = FALSE;
        $auth['declined']       = FALSE;
        $auth['transaction_id'] = NULL;
        return $auth;
    }

    $this->update_order(array('sage_key' => $transaction['SecurityKey']));
    $this->gateway_exit_offsite(NULL, $next_url); exit;
}

/**
 * payment_notification
 *
 * @return void
 * @author Chris Newton
 * @since 1.0
 **/
function extload($post)
{
    $auth['authorized']     =   FALSE;
    $auth['declined']       =   FALSE;
    $auth['failed']         =   TRUE;
    $auth['error_message']  =   NULL;
    $auth['transaction_id'] =   NULL;

    if (!empty($post['VendorTxCode']))
    {
        list($order_id) = explode("_", $post['VendorTxCode']);

        $this->relaunch_cart(NULL, $order_id);
    }
    else
    {
        die($this->lang('sage_default'));
    }

    if (strpos( $this->order('return'), 'http') === 0)
    {
        $return_url =  $this->order('return');
    }
    else
    {
        $return_url = $this->create_url($this->order('return'));
    }

    if ("OK" == strtoupper($post['Status']))
    {
        $tmp = array(
            'VPSTxId'           =>  $post['VPSTxId'],
            'VendorTxCode'      =>  $post['VendorTxCode'],
            'Status'            =>  $post['Status'],
            'TxAuthNo'          =>  $post['TxAuthNo'],
            'BankAuthCode'      =>  $post['BankAuthCode'],
            'DeclineCode'       =>  $post['DeclineCode'],
            'ExpiryDate'            =>  $post['ExpiryDate'],
            'FraudResponse'     =>  $post['FraudResponse'],
            'VendorName'        =>  strtolower($this->plugin_settings('vendor_name')),
            'AVSCV2'            =>  $post['AVSCV2'],
            'SecurityKey'       =>  $this->order('sage_key'),
            'AddressResult'     =>  $post['AddressResult'],
            'PostCodeResult'    =>  $post['PostCodeResult'],
            'CV2Result'         =>  $post['CV2Result'],
            'GiftAid'           =>  $post['GiftAid'],
            '3DSecureStatus'    =>  $post['3DSecureStatus'],
            'CAVV'              =>  (!empty($post['CAVV'])?$post['CAVV']: ""),
            'AddressStatus'     =>  (!empty($post['AddressStatus'])?$post['AddressStatus']: ""),
            'PayerStatus'       =>  (!empty($post['PayerStatus'])?$post['PayerStatus']: ""),
            'CardType'          =>  $post['CardType'],
            'Last4Digits'       =>  $post['Last4Digits']
            );

        if (empty($tmp['AddressStatus']))
        {
            unset ($tmp['AddressStatus']);
            unset ($tmp['PayerStatus']);
        }

        $md5 = implode("",$tmp);

        $md5hash = strtoupper(md5($md5));
        if (!empty($post['ct_action']) && $post['ct_action'] == "create_token")
        {
            $tmp = array(
                'VPSTxId'           =>  $post['VPSTxId'],
                'VendorTxCode'      =>  $post['VendorTxCode'],
                'Status'            =>  $post['Status'],
                'VendorName'        =>  "eqvvs",
                'SecurityKey'       =>  $this->order('sage_key'),
                'Token'             =>  $post['Token']
                );

            $md5 = implode("",$tmp);

            $md5hash = strtoupper(md5($md5));
        }

        if ($md5hash != strtoupper($post['VPSSignature']))
        {
            $auth['authorized']     =   FALSE;
            $auth['declined']       =   FALSE;
            $auth['failed']         =   TRUE;
            $auth['error_message']  =   $this->lang('sage_signature_not_valid');
            $auth['transaction_id'] =   NULL;

            $this->checkout_complete_offsite($auth, $order_id, 'stop_processing');
            // SAGE requires that we output this stuff.
            @ob_clean();
            header("Content-type: text/plain");
            echo "Status=INVALID\r\n";
            echo "RedirectURL=".$return_url."\r\n";
            @ob_flush();
            exit;
        }
        $auth['authorized']     =   TRUE;
        $auth['declined']       =   FALSE;
        $auth['failed']         =   FALSE;
        $auth['error_message']  =   NULL;
        $auth['transaction_id'] =   trim($post['VPSTxId'], "{}");
        // "Auth:".$post['TxAuthNo']."_Tx:".$post['VPSTxId']."_Vnd:".$post['VendorTxCode']."_Sec:".$_SESSION['cartthrob']['sage_key'];

        if (!empty($post['ct_action']) && $post['ct_action'] == "create_token")
        {
            $token = new Cartthrob_token();
            $token->set_token( $post['Token'] );
            exit;
        }
        $this->checkout_complete_offsite($auth, $order_id, 'stop_processing');
        // SAGE requires that we output this stuff.
        @ob_clean();
        header("Content-type: text/plain");
        echo "Status=OK\r\n";
        echo "RedirectURL=".$return_url."\r\n";
        @ob_flush();
        exit;
    }
    else
    {
        $status = NULL;
        $redirect_url = NULL;
        switch(strtoupper($post['Status']))
        {
            case "NOTAUTHED":
                $auth['error_message'] = $this->lang('sage_notauthed');
                $status = "Status=OK\r\n";
                break;
            case "ABORT":
                $auth['error_message'] =  $this->lang('transaction_cancelled');
                $status = "Status=OK\r\n";
                $redirect_url = "RedirectURL=".$return_url."\r\n";

                $this->set_status_canceled($auth, $this->order('entry_id'),  FALSE);
                $this->save_cart();

                // but need to handle canceled as well.
                $auth['canceled'] = TRUE;
                break;
            case "REJECTED":
                $auth['error_message'] =  $this->lang('sage_rejected');
                $auth['declined']       =   TRUE;
                $status =  "Status=INVALID\r\n";
                break;
            case "AUTHENTICATED":
                $auth['error_message'] = $this->lang('sage_authenticated');
                $status =  "Status=OK\r\n";
                break;
            case "REGISTERED":
                $auth['error_message'] =  $this->lang('sage_registered');
                $status = "Status=OK\r\n";
                break;
            case "ERROR":
                $auth['error_message'] = $this->lang('sage_error');
                $status = "Status=INVALID\r\n";
                break;
            default:
                $auth['error_message'] =  $this->lang('sage_default');
        $auth['authorized']     =   FALSE;
        $auth['transaction_id'] =   NULL;
        }

        if (!empty($post['ct_action']) && $post['ct_action'] == "create_token")
        {
            $token = new Cartthrob_token();
            $token->set_error_message( $auth['error_message']  );
            exit;
        }

        $this->checkout_complete_offsite($auth, $order_id, 'stop_processing');
        @ob_clean();
        header("Content-type: text/plain");
        if ($status)
        {
            echo $status;
        }
        else
        {
            echo "Status=INVALID\r\n";
        }
        if ($redirect_url)
        {
            echo $redirect_url;
        }
        else
        {
            echo "RedirectURL=".$return_url."\r\n";
        }
        // SAGE requires that we output this stuff.
        @ob_flush();
        exit;
    }
} }

```

# Answer
Having spoken to the very helpful Chris @ Cartthrob during a dedicated support session, thought I'd come back to answer this - the soon to be latest edition of Cartthrob will handle Sagepay 3.00 vps - I can confirm all worked great from my point of view, as the update was conducted during the support session, and I was immediately able to both continue to process checkout, and take advantage of the new data fields via MySagePay.

I should also point out that I had updated to the latest version of cartthrob prior to that, but did not have the updated version of extload.php in my /themes/ folder - I believe this was error my end with a git commit failing to ignore reverting this file, but it would certainly be the first point of reference I'd check for anyone else out there struggling - I may perhaps have cracked the gateway issue myself had I not inadvertently reverted that file.

For reference, the vps has to be updated to 3.00 in all 3 areas on the sage gateway (I'm referring specifically to the offsite server version `Cartthrob_sage_s.php`) and the new mandatory fields (bankauth et al) added to the last set of fields within the gateway.

```
        $tmp = array(
            'VPSTxId'           =>  urldecode($post['VPSTxId']),
            'VendorTxCode'      =>  urldecode($post['VendorTxCode']),
            'Status'            =>  urldecode($post['Status']),
            'TxAuthNo'          =>  urldecode($post['TxAuthNo']),
            'VendorName'        =>  strtolower($this->plugin_settings('vendor_name')),
            'AVSCV2'            =>  urldecode($post['AVSCV2']),
            'SecurityKey'       =>  $this->order('sage_key'),
            'AddressResult'     =>  urldecode($post['AddressResult']),
            'PostCodeResult'    =>  urldecode($post['PostCodeResult']),
            'CV2Result'         =>  urldecode($post['CV2Result']),
            'GiftAid'           =>  urldecode($post['GiftAid']),
            '3DSecureStatus'    =>  urldecode($post['3DSecureStatus']),
            'CAVV'              =>  (!empty($post['CAVV'])? urldecode($post['CAVV']): ""),
            'AddressStatus'     =>  (!empty($post['AddressStatus'])? urldecode($post['AddressStatus']): ""),
            'PayerStatus'       =>  (!empty($post['PayerStatus'])? urldecode($post['PayerStatus']): ""),
            'CardType'          =>  urldecode($post['CardType']),
            'Last4Digits'       =>  urldecode($post['Last4Digits']),
            'DeclineCode'       => urldecode($post['DeclineCode']),
            'ExpiryDate'        => urldecode($post['ExpiryDate']),
            'FraudResponse'     => urldecode($post['fraudResponse']),
            'BankAuthCode'      => urldecode($post['BankAuthCode'])
            );

```
> 1 votes

---
Tags: ee2, cartthrob, error, payment-gateway, sagepay
---


# Question
Title: Cartthrob no longer sending email notifications after EE/CT upgrade
I've recently upgraded EE from version 2.7.3 to the latest 2.9.2, and CartThrob similarly from 2.3.6 to the latest 2.6.1.

All functionality seemed to be fine, aside from my SagePay checkout, which initially fired a 5006 error. I narrowed this down to an issue with extload.php (commonplace!) which I amended by utilising my old extload.php.

There are no obvious errors logged, but I noted pretty instantly that the email notifications (for admin and customer) are no longer being sent; the database does not even log attempts to send the emails. I've confirmed that the backend still has the same email details present, and even tried adding a new, standalone rule that used a non-domain email, in case of any block from that point of view.

On investigation, I've also noticed that after Sage redirects back to site (order complete), the basket retains the items from the order - it previously did not. This even skips the first layer of out of stock warning, allowing items in the basket that are OOS until the point of checkout (where it does then catch them).

Any advice would be greatly appreciated - I've read on similar errors, but not a concrete solution as such. Thanks!

# Answer
> 0 votes
I got to the bottom of this problem - upon updating to the latest cartthrob, I think due to an accidental reversion of extload.php to its previous version (via a GITIGNORE incorrectly referencing the file), I was running an outdated extload.

Having updated apparently seamlessly, this of course wasn't something I'd looked for, and had actually tried manually uploading the old extload.php to see if this would temporarily patch the error. On updating extload again to the present and correct version, email functionality returned and basket correctly empties again on checkout success response.

---
Tags: cartthrob, email, notification, shopping-cart, sagepay
---


# Question
Title: Migrated EE site shows correct page in URL but index page in browser window... ideas why?
I realise this is a an incredibly vague question, but asking just in case someone recognises symptoms and can suggest a possible cause that I can go investigate...

\[if you haven't worked out I'm new to EE...\]

I'm trying to migrate a site from one server to another server.

I've migrated the server using the instructions in EE documentation, and believe I've done those steps as required.

The site works perfectly on the current server.

On the new server the site will only show the home page, regardless what URL you enter (i.e. site\_URL plus any trailing text gives home page).

The URL entered is preserved in the displayed browser URL.

I turned on template debugging, and this is what I see when I try go to any page that is not the index page - you'll see it seems to ignore the URI: (it is blank for some reason) and then loads /index...

```
(0.000013 / 4.53MB) - Begin Template Processing -
(0.000144 / 4.53MB) URI:
(0.000155 / 4.53MB) Path.php Template: /
(0.000165 / 4.53MB) Retrieving Template
(0.000175 / 4.53MB) Parsing Template URI
(0.000197 / 4.53MB) Retrieving Template from Database: /index

```

Anyone with any ideas?

Couple of clarifications based on questions asked.

First, the new server is simply another instance on the same hosting platform that we use for the current site instance - the idea is to build a test server that we can use to test module updates / do development on that is in the same hosting environment as the live site.

The hosting is done by a firm called TSOHost in the UK and is the "Cloud Hosting" package (https://www.tsohost.com/web-hosting).

Second, is the complete .htaccess file from the current server (on which EE is working no problem, and has been copied over to the new server instance):

```
AddType x-httpd-php53 .php

Header set X-UA-Compatible "IE=edge"

<IfModule mod_rewrite.c>
RewriteEngine On

# Removes index.php from ExpressionEngine URLs
RewriteCond $1 !\.(gif|jpe?g|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
</IfModule>
ErrorDocument 403 http://2gc.eu/pages/sorry-that-link-cant-be-used
# Added automatically by Gridhost panel Wednesday 27th of March 2013 06:45:28 PM
Options -Indexes

```

# Answer
Did you copy over the .htaccess file from the old server? It may have been invisible to you and thus not been copied.
> 0 votes

# Answer
The hosting company may determine small changes in your .htaccess file. Some require

```
RewriteBase /

```

for example, or something similar. So that might give us a clue if you can post that.
> 0 votes

---
Tags: server-migration
---


title: Template file not synchronizing to cms?

text:
# Question
Title: Template file not synchronizing to cms?
I have been given an expressionengine site to work on. This is my first time using expressionengine.

I am trying to make some changes to a template file. I have uploaded the file to the webserver. I then go in to desgin \> templates \> synchronize templates.

The template file that I edited shows a different "File edit date" to the date that I just edited the file.

I ran the synchronizaton on this file anyway to see if it would work and it didn't do anything.

How can I synchronize changes to template files back to the live site/cms?

# Answer
Check a few things in EE. Go to DESIGN \> TEMPLATES \> GLOBAL PREFERENCES and check out the last two settings.

* Save Templates as Files -\> Yes (if it won't change, check your config files)
* Server path to site's templates -\> make sure path is correct and folder is chmod 777
> 3 votes

# Answer
Sometimes people develop templates as files, then when they launch on the production server they sync those to the DB and then turn off saving to file (for performance reasons I believe) - so then it wouldn't pick up the changed template I guess.
> 2 votes

# Answer
You might check the cache option;

Find the template, go to preferences and see if "enable caching" is set to "no". When you're done editing simply switch back to "yes" .
> 2 votes

# Answer
On a webserver make sure the files are set to the correct file permissions, which should be rw-rw-rw- 666
> 1 votes

# Answer
Can I just say EE template sync is lacking. The sync manager doesn't tell you which direction the sync will go in. You should be able to manually toggle direction however you want on a case by case basis. Why can I check some boxes and not others, why are some dates red and some green? There should also be a setting that if file is newer, auto sync to db or if db is newer, auto sync to file. And do that on an ongoing basis if configured. That's what I'd expect. The way they have it leaves a lot to the unknown.
> 0 votes

---
Tags: templates, sync
---


title: Modules/Add-ons loading on all pages

text:
# Question
Title: Modules/Add-ons loading on all pages
I'm finding a few add-ons/modules that are loading on every page/template even if they are not being called in that template.

For example, the Solspace Favorites module seems to constantly be coming up on every page of the site even though it is only being called with tags and used in only 2 pages/templates.

The issue is that it's also causing increases in memory usage (not crazy amounts but still). Is this normal and is there any way to avoid this?

Thanks! Dan

# Answer
At least for Favorites, the add-on uses a hook, `channel_entries_tagdata`, which is a hook present in the EE Channel:Entries module. Any add-on that uses this hook will be called when the EE Channel:Entries module is used. This includes when `{exp:channel:entries}` is used, but can include other tags where the Channel:Entries library is being used, eg. `{exp:favorites:entries}`.

Hooks usually extend a feature in EE. In the case of `channel_entries_tagdata`, the hook can be used to modify the Channel:Entries tag data, for example to add additional variables that can be parsed by `{exp:channel:entries}`. If you had Matrix or Playa installed, for example, you might also see calls to these modules since they also use this hook, likely to add the ability to parse Matrix/Playa variables (*don't take my word for it*).

Simply calling a hook does not add a lot of overhead: a function called by the hook might exit immediately, with no queries or heavy processing happening. Favorites does this: it checks if there's anything related to Favorites with the tag, and if not, exits the function. A look at the Output Profiler should not show Favorites-specific queries if Favorites is not mentioned in your code.

Unfortunately there is no way modify this behaviour, since this is how hooks work in EE: EE triggers a hook, looks for all add-ons that use the hook, and runs each add-on function that uses the hook. It's the add-on developer's responsibility to exit early (or use cached data instead of queries/loading librairies) if nothing needs to be done when the function is called. EE's Template Debugger, however, will still log the hook call, even if nothing happens when the hook function is called.

You could disable the extension for an add-on, but then you would lose its functionality when it's needed.
> 2 votes

---
Tags: solspace, performance, memory
---


# Question
Title: Local copy of working site > admin work > pages all get 404
We're taking over hosting a clients site, and I've downloaded a copy of the site and the database, and set up both in mamp.

I've adjusted the db config, and the '/admin/' area all works - however, if I go to 'index.php' i'm just getting a 404 page ('Status: 404 Page Not Found').

I've adjusted the paths in Global Template Preferences, and General Configuration, but to no avail.

Any ideas of where I should start looking to find the issue? I'm new to EE...

cheers

# Answer
> -1 votes
I not sure why, but i stumbled across 'Enable Strict URLs' in the global template settings, tried setting to 'no' and all the page appears...

---
Tags: 404, localhost
---


# Question
Title: Unable to modify data with ‘entry_submission_ready’ extension hook
I’ve read a few posts on this, and for the life of me I can’t get this working. I want to intercept a Channel Form submission, and modify the submitted data.

I’m using the ‘entry\_submission\_ready’ extension hook, which fires fine. I can access the $data array, but I cannot modify an element so that it is saved when the entry is saved.

I’m accessing the $data arary by reference ( &$data ), but that doesn’t make any difference.

Where an I going wrong?

```
<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

/**
 * ExpressionEngine - by EllisLab
 *
 * @package     ExpressionEngine
 * @author      ExpressionEngine Dev Team
 * @copyright   Copyright (c) 2003 - 2011, EllisLab, Inc.
 * @license     http://expressionengine.com/user_guide/license.html
 * @link        http://expressionengine.com
 * @since       Version 2.0
 * @filesource
 */

// ------------------------------------------------------------------------

/**
 * Contact Notify Extension
 *
 * @package     ExpressionEngine
 * @subpackage  Addons
 * @category    Extension
 * @author      James Seavers
 * @link        http://www.symphonyonline.co.uk
 */

class Contact_notify_ext {

    public $settings        = array();
    public $description     = 'Notifies when an entry is created in contact request channel after changing some data';
    public $docs_url        = '';
    public $name            = 'Contact Notify';
    public $settings_exist  = 'n';
    public $version         = '1.0';

    private $EE;

    private $recipient = 'me@gmail.com';

    /**
     * Constructor
     *
     * @param   mixed   Settings array or empty string if none exist.
     */
    public function __construct($settings = '')
    {
        $this->EE =& get_instance();
        $this->settings = $settings;
    }// ----------------------------------------------------------------------

    /**
     * Activate Extension
     *
     * This function enters the extension into the exp_extensions table
     *
     * @see http://codeigniter.com/user_guide/database/index.html for
     * more information on the db class.
     *
     * @return void
     */
    public function activate_extension()
    {
        // Setup custom settings in this array.
        $this->settings = array();

        $data = array(
            'class'     => __CLASS__,
            'method'    => 'change_data',
            'hook'      => 'entry_submission_ready',
            'settings'  => serialize($this->settings),
            'version'   => $this->version,
            'enabled'   => 'y'
        );

        $this->EE->db->insert('extensions', $data);

    }

    // ----------------------------------------------------------------------

    /**
     * change_data
     *
     * @param
     * @return
     */
    public function change_data($meta, &$data, $autosave=false)
    {
        $data['field_id_60'] = 'test';
    }

}

```

Thanks in advance, James

# Answer
Passing by reference doesn't work when calling extension hooks in EE.

If you want to alter the field data inside any of the API Channel Entries hooks, you need to change it directly in the API object, like so:

```
ee()->api_channel_entries->data['field_id_60'] = 'test';

```
> 2 votes

---
Tags: extension
---


title: Member Portals for Employees

text:
# Question
Title: Member Portals for Employees
I have a client who is requesting a member portal. The concept is to have two parts to this portal. Part one is from the Employer side. Employer logs-in to access Employees resumes and information and can search by keyword or industry. Part Two is from the employee side. The employee logs-in and can update their information, add keywords, upload a photo and resume and have access to restricted content.

I'm not too familiar with member management in EE so my questions are this: 1. Are there any plugins that could make this project run smoother such as User? 2. Is it possible to have a way that an employer can view the details of an employee, and download that data to a file? Would that require a plugin? 3. Is there an advance search that I would need for this type of project?

thanks jeff

**Here is an update** I now have the docs to begin and I want to make sure these are the right plugins to use on this project. I am think of using Zoo Visitor, Safe Cracker, Super Search and Grid Field. The idea behind the project is that there are two types of members, employers who want access to employees and employees who want access to employers. Both need to be able to update info and search for each other and both login to the site.

# Answer
think you're very lucky :) check this new post by Sean Smith on how he built a resume builder Channel Form and Grid/Matrix fields
> 2 votes

# Answer
Have built a few things like this in EE. Look at Zoo Visitor for the member registration and something like Low Search for the search side.

There are more than a few ways to go about it. Have a look on Devot-EE for more addons that could help your build.
> 1 votes

# Answer
We're just about to a launch a full job portal site for a client that includes Employer access with ability to add/edit jobs, job applicants with ability to upload resume, save jobs to favorites and apply directly to jobs.

We used Zoo Visitor for our member management which was beyond easy and then utilized Reefine for the search filters. Freeforms was used for all the forms to communicate and LinkVault for secure handling of all resumes so that they aren't easily accessible via web (all files stored above root).

Hope that helps...let me know if you have other questions :)
> 1 votes

# Answer
Another add-on to consider for profiles management is Profile:Edit. And of course, Freemember.
> 0 votes

---
Tags: categories, members, plugin, member-management, export
---


# Question
Title: Convert a row's site_pages cell (inside exp_sites) into a key-value array
For the purpose of using PHP to automate the creation of custom URLs that will be placed in the Pages Module, I'm first retrieving and decoding the whole block of encoded, serialized data in the exp\_sites table and the site\_pages column.

All is well when fetching the string from the site\_pages column and assigning it to a variable like $decode\_this\_string.

All is again well when I get the list of URLs with PHP like so:

```
$site_pages = unserialize(base64_decode($decode_this_string));
$the_uris = $site_pages[1]["uris"];

```

When I var\_dump $the\_uris, I get output that looks like this, where I see string length, the page\_uri, and the associated entry ID for each.

```
array(236) { [23]=> string(13) "/tools/index/" [36]=> string(8) "/voting/" [48]=> string(13) "/links/index/" [100]=> string(19) "/supporters/thanks/" [119]=> string(15) "/cancel/return/" [222]=> string(10) "/pressroom" ...

```

That's normal. But what I'd like to do is plunk this into a two-dimensional array where I can manipulate the Pages entries as rows (and can then sort them, search through them, add to them, delete them).

However, I'm confused how to break the rows down further. I can loop through them this way:

```
<ul>
<?php foreach ($the_uris as $uri): ?>
    echo '<li>' . $uri . '</li>';
<?php endforeach; ?>
</ul>

```

...but this way, all I can seem to output is the page\_uri, not the entry associated with the page\_uri. This is the output from the code above.

```
/tools/index
/voting/
/links/index

```

etc. In other words, I don't know how to break the row $uri into its related key and value (or "pair" of entry\_id and page\_uri, if that's a better way of describing it).

Is there a way to do this, so I can grab the entry\_id along with the page\_uri?

# Answer
I figured out the answer just a few minutes after posting.

```
<?php foreach ($the_uris as $key => $val) { ?>
    <tr>
        <td><?php echo "[" . $key . "] => " . $val; ?></td>
    </tr>
<?php } ?>

```

This is great. Now I can just find the page URI through a simple array with an entry ID key, like:

```
<?php echo 'entry id 36 = ' . $the_uris[36]; ?>

```

which outputs:

```
/voting/

```
> 0 votes

---
Tags: ee2, php, database, mysql, pages
---


title: Incorrect Entry Date

text:
# Question
Title: Incorrect Entry Date
Using the basic channel entries tag, entries made in Feb of 2015 are all showing the same entry date even though they are set to different dates.

```
<ul class="blog-list">
    {exp:channel:entries
        channel="blog"
        orderby="date"
        sort="desc"
        dynamic="no"
        show_future_entries="yes"
        disable="categories|category_fields|member_data|pagination"
    }

        <li>

                <h4>{entry_date format="%F %n, %Y"}</h4>
                <p>{title}</p>

    </li>
    {/exp:channel:entries}
</ul>

```

I am running EE 2.8.1.

Thanks for any help.

# Answer
Your date format is incorrect.

Please check https://ellislab.com/expressionengine/user-guide/templates/date\_variable\_formatting.html.

Your format there provides (%F, long month) Feburary (%n, month without leading zeros) 2 (%Y, four digit year) 2015. So yes, February is always the 2nd month, and the year isn't going to change during that month.

I think you want

```
<h4>{entry_date format="%F %d, %Y"}</h4>

```

on that line.
> 3 votes

---
Tags: entry-date
---


# Question
Title: Assets and Low Variables not compatible?
When I add an assets field to a Low Variable, it reports that it's added it correctly, however I then get a fatal error whenever I try to load the LV dashboard:

`Unable to load the requested file: field/field.php`

If I manually delete the row in the table, LV returns to normal operating status and all is fine.

Similarly, if I add an Assets field to a grid Low Variable, I don't get the above fatal error, however I get the following PHP errors:

```
A PHP Error was encountered
Severity: Notice
Message: Array to string conversion
Filename: libraries/Core.php
Line Number: 409

A PHP Error was encountered
Severity: Warning
Message: Cannot modify header information - headers already sent by (output started at /home/--REDACTED--/system/codeigniter/system/core/Exceptions.php:170)
Filename: core/EE_Security.php
Line Number: 88

A PHP Error was encountered
Severity: Warning
Message: Cannot modify header information - headers already sent by (output started at /home/--REDACTED--/system/codeigniter/system/core/Exceptions.php:170)
Filename: core/EE_Security.php
Line Number: 89

```

Has anyone else seen these problems and is there a hotfix available to resolve it?

I'm running `ExpressionEngine 2.9.2` and `Assets 2.5`

Assets in a channel entry works fine, so the bug seems to be with the compatibility with Low Variables.

---

UPDATE: The second error reported now appears to be happening on ALL assets modal windows within channels *and* with Low Variables.

# Answer
Appears the problem was a conflict with another custom add-on that was installed. I've disabled it for the time being and I'll review the source code to fix at a later date.
> 1 votes

---
Tags: assets, pixelandtonic, low-variables, low
---


# Question
Title: Using just the name of a Freeform recipient in a notification template
I'm using the recipients="yes" option in my form, and I have a number of recipients specified in the form parameters using the pipe-separated format (eg. recipient1="somename|somevalue@example.com"). Is there a way to include just the part before the pipe ("somename") in a notification template? I can add the custom field {recipient\_email} but that places both parts into the template, including the email address. I just want the first bit. Possible?

EDIT: I'm similarly struggling to find a way to pass the name value of the selected email address to the return (Thank You) page. For example, if the user chooses the second of three email address from the form's select menu and that recipient is specified as recipient2="Joe Smith|jsmith@example.com" then I want to be able to have a line of the form's Return page that says "You sent this information to Joe Smith". So far I haven't found a way, even using Stash to save a variable to the database.

Anyone have a solution to this?

# Answer
From the documentation it looks like to get just the email you can use:

```
{freeform:recipient_value1}

```

And to get just the name you can use:

```
{freeform:recipient_name1}

```
> 1 votes

---
Tags: solspace-freeform
---


# Question
Title: Issue using category_id in IF statement when entry has multiple categories
this code has worked great for a long time. I pull entries and use an IF statement around which category they are in:

```
{exp:channel:entries channel="resources" dynamic="on" limit="1"}

    {if "{categories}{category_id}{/categories}” == “44” OR “{categories}{category_id}{/categories}” == “191” }
    ....
    {/if}

    {if "{categories}{category_id}{/categories}” == “45”}
      ....
    {/if}

```

All was good until I got an entry with more than one category (84 & 191). The output is `{category_id} = “84191”` which doesn't get caught in my conditional.

I don’t want to use the “contains” conditional b/c then an entry with category 84 & 4 would be “844” and would match me looking for category=44. How do I solve this??

Thanks!

# Answer
> 1 votes
To prevent your issue with 84 & 4 occurring, you could use code like this, where you surround the category IDs with something to make them separate:

```
{exp:channel:entries channel="resources" dynamic="on" limit="1"}

    {if "{categories}({category_id}){/categories}" *= "(44)" OR "{categories}({category_id}){/categories}" == "191" }
    ....
    {/if}

    {if "{categories}({category_id}){/categories}" *= "(45)"}
    ....
    {/if}

```

Depending on your use case, it might be better written as

```
{exp:channel:entries channel="resources" dynamic="on" limit="1"}
    {categories}
        {if "{category_id}" == "44" OR "{category_id}" == "191" }
        ....
        {/if}

        {if "{category_id}" == "45"}
        ....
        {/if}
    {/categories}

```

Though then you'd get output twice if your entry was in both categories 44 and 191.

---
Tags: categories
---


# Question
Title: DB error when a new user registers after server migration
Just moved the site from a lamp to IIS. We are using Solspace's User module for registration but we are getting the following DB

```
A Database Error Occurred
Error Number: 1366

Incorrect integer value: '' for column 'last_activity' at row 1

INSERT INTO `exp_members` (
`group_id`,
`username`,
`password`,
`salt`,
`ip_address`,
`unique_id`,
`join_date`,
`email`,
`screen_name`,
`time_format`,
`url`,
`location`,
`occupation`,
`interests`,
`language`,
`last_activity`,
`bday_d`,
`bday_m`,
`bday_y`,
`aol_im`,
`yahoo_im`,
`msn_im`,
`icq`,
`bio`,
`profile_views`,
`timezone`,
`signature`

)VALUES (

'6',
'ashby', '63fd27cab8beb2c3fbf8aca6d49f71a333ab71c3a741d8fd3bd6627698696b1fa4dc63ece5143a06a8701081f0a64b3fea9da59a181b770c5876a4454e9610cb', 'CzO6TFy\'#l=<`G@BSjl?AEa*W[Y0N3bcr4).O:;@j^:+Bds&4wM:)*\\w,m!ziRC~sp\".o-m1.qZTR?TeK,JhmCut;j',
'190.140.68.177',
'a6444108bf453435e0b71f60ea11e4b640403178',
1425070565,
'email@gmail.com',
'ashby',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'')

Filename: C:\inetpub\wwwroot\system\codeigniter\system\database\DB_driver.php

Line Number: 330

```

# Answer
You are likely not using the latest version of User: a separate conversation mentioned that you were using `3.4.5`, and the latest as of this writing is `3.5.2`. Please update User to the latest version.
> 0 votes

---
Tags: members, solspace-user, registration
---


# Question
Title: how can I transfer entries between MSM sites if the site's already been created?
We created a separate site in MSM a while back and never copied over channels, fields or categories. But now we want to do this without deleting and recreating the site. How do I do this?

# Answer
> 0 votes
It turns out there's not really an easy way. What I did was in the second MSM site:

1. Duplicate channels
2. Duplicate field groups, fields etc.
3. Duplicate categories
4. Duplicate file upload prefs.

With 1-3 above we used the EXACT same url title. Then we wrote this script to copy all the entries over, retaining their category assignments.

I hope this helps someone.

https://gist.github.com/jaseclamp/2dcda64e8912f7361d94

---
Tags: multi-site-manager
---


# Question
Title: Channel Entries - addon to charge members per entry?
Does EE have an addon, either native or third party, that can charge members to post entries? Some entries will be a one time payment while others need to be recurring. I need the entry to expire at a certain date, or if a future payment fails, etc. Email notifications to keep members aware of payments, etc. would be useful.

I know this sounds very specific, but I'm hoping something already exist than having to build something.

# Answer
Disclaimer : I'm the developer of Charge so am biased on this.

**Yes** \- this is all quite simple with Charge. You'd simply use the standard front-end entry form as usual and set the entry status to a pending state, then use the built in entry actions in Charge to update the status to live after a successful payment.

This can all be used with recurring payments, and if you need to later down grade or alter the status of the entry you can use the provided hooks to trigger any extra logic you might want.

To be fair - this same setup is likely possible using other third party addons but I can't speak for the exact setup on those.
> 1 votes

# Answer
You could use a store add-on as a workaround.

I'm using Expresso Store. You could add a custom text field to a product and use it to store the id of an channel form entry.

This might also be possible using other add-on, such as Simple Commerce or CartThrob.
> 0 votes

# Answer
I've reached similar functionality some time ago using Membrr. DevDemon Subscriptions might also work for this.
> 0 votes

---
Tags: channel-entries, add-on, add-on-development, entries, addons
---


# Question
Title: Ideas why status is set to closed when entry edited via channel:form?
In this post answer was that membergroup has to have access to all statuses merged to channel: Custom Member's Channel Entries Defaulting To "Closed" Status

I have same issue that when editing entry via channel:form, status goes to closed. So only way to avoid this type of situation is to make custom status group and to allow access to all statuses, so entry should stay open/what-ever status but not closed?

What is the logic behind this? I want to deny access to closed and open, but having access to foo and bar, this is mission impossible because entry goes closed every time someone edit the entry when having the channel attached to default status group.

Feeling nuts to create new status groups just because of this, if the case is really that member has to have access to all statues or otherwise entry goes closed.

Is there a work-around for this, so that channel could have the choice to deny access to open and closed without a worry about entry getting closed everytime it is edited?

# Answer
Are you including status input in your form? If not, try adding

> \<input type="hidden" name="status" value="{status}" /\>
> 1 votes

---
Tags: channel-entries, status
---


title: Save template output to disk?

text:
# Question
Title: Save template output to disk?
I have a client in a situation where they need to provide physical CSV files on-disk for various and sundry reasons. The CSV would need to be populated with data fetched from the DB.

Now, I can totally prepare a custom template that would result in a CSV-formatted response via HTTP, but how do I save that response to disk? (EDIT: Is there perhaps some way to use a caching method of some sort to write the output to disk?)

In case it helps clarify things, the situation is a client who uses a fulfillment center for hosting and managing their non-EE shop. They now want to move to Expresso Store for the shop, but still use the fulfillment center to manage things. The fulfillment center wants to continue working with their own system of order management, but they can set up their system to fetch via FTP nightly updates in the form of CSV files to update their system with the latest orders from the Expresso Store.

# Answer
I'd recommend turning on "Enable HTTP Authentication?" for your template, so that you must use a username/password to access it, and then setting up a Cron job on your server to save to disk on a nightly basis:

```
00 00 * * * curl http://username:password@yoursite.com/your/template > /var/www/csv/`date +\%Y\%m\%d\%H\%M\%S`.csv

```
> 5 votes

# Answer
Not sure exactly what your needs are but would NSM Reports solve your problems?
> 1 votes

---
Tags: export, csv
---


# Question
Title: Charge wont show Card Holders name on success page, ideas why?
I simplified the form what Im using with Charge atm. to point out with what I have issues.

I have this form:

```
{exp:charge:form
                form_class="form-horizontal"
                form_id="charge-form"
                return="client/thankyou"
                return_error="client/errors"
                plan_amount="69"
                plan_currency="eur"
                plan_length="12"
                on_success="premium_membership"}

                       <label for="card_name" class="col-sm-2 control-label">Name on the Card</label>

                        <div class="col-sm-4">
                          <input type="text" class="form-control" id="card_name" value"" data-stripe="name" />
                        </div>

{/exp:charge:form}

```

and this is on the "receipt" page:

```
{exp:charge:info hash="{segment_3}"}

 <strong>Name on the Card:</strong> {card_name}

{/exp:charge:info}

```

But it does not show the name put to the field. Stripe does take and save that data to proper place on their end, but on my site, its blank.

I've looked at the charge documentation that clearly says card\_name is available, even its optional. http://squarebit.co.uk/software/expressionengine/charge/docs/tags#tag-info

When doing business to business payments, I need the name of the client to be included to receipt to make it legal for added to accounting on the client end.

However, if I use just customer\_name, I do not get the right data saved to Stripe end. And I cant use data-stripe for customer\_name because it is not the same as the name of whos paying.

What I have might done wrong, or does the card\_name has to be inside of specific tags or so?

All other fields like card number, and card used is coming out as normal, and the amount paid.

Please, i've heard that there is thousands of ppl who uses Charge, so this has to be something that has easy solution?

Using EE 2.9.2 running on PHP 5.6.2

Thank you.

# Answer
> 0 votes
I just got email from addon developer that card\_name appears to have some sort of bug on the version of Charge im using. So if someone else might have had same issue, I just want to let you know.

---
Tags: add-on, forms, charge
---


title: https:// with expression engine

text:
# Question
Title: https:// with expression engine
What do i need to consider when using a ssl ceritifcate on my website. I have an sll set up on my server but at the moment i have the .hta file redirecting everyone to http://.

This is because if i visit the site over https:// there is a few things wrong.

Low Search doesnt work, Free Form doesnt work, Free members - basically asks if your sure you want to login as some things might not be secure. Control panel has no styles or javascript.

However the general website loads and operates fine.

Do i need to change some files to reflect https:// for everything to work properly?

Thanks for any help.

# Answer
> 3 votes
> Low Search doesnt work, Free Form doesnt work, Free members - basically asks if your sure you want to login as some things might not be secure.

These add-ons usually use what you have configured in your "Admin \> General Configuration \> URL to the root directory of your site". You can also set/override the General Configuration settings using the /system/expressionengine/config/config.php file.

If using your config.php file to make the changes, you could use these basic settings to possibly fix some or all of the issues you're experiencing:

```
// check if https or http
$base_url = (!empty($_SERVER['HTTPS'])) ? 'https://' . $_SERVER['HTTP_HOST'] : 'http://' . $_SERVER['HTTP_HOST'];

// set as constant
define('BASE_URL', $base_url . '/');
define('BASE_PATH'. $_SERVER['DOCUMENT_ROOT']);

$config['site_url']                = BASE_URL;
$config['cp_url']                  = BASE_URL.'admin.php';

$config['theme_folder_path']       = BASE_PATH.'themes';
$config['theme_folder_url']        = BASE_URL.'themes/';

```

> Control panel has no styles or javascript.

This would be due to the /themes/ folder path setting being invalid/incorrect. You can update it using the General Configuration or config.php file I mentioned above.

> Do i need to change some files to reflect https:// for everything to work properly?

If you've configured your paths to be relative or based on the current URI, you shouldn't need to setup any special https redirect rules. However, I do recommend either forcing www or non-www for SEO and to prevent cross-domain errors. This would be done using your htaccess file:

https://stackoverflow.com/questions/4916222/htaccess-how-to-force-www-in-a-generic-way

---
Tags: solspace-freeform, low-search, expresso, low
---


title: Apply Snazzy maps to MX Google Maps

text:
# Question
Title: Apply Snazzy maps to MX Google Maps
I want to apply a snazzymap to MX Google Maps.

# Answer
If you're using Max's MX Google Map \[1.5.3\] for publish form maps and wish to apply a snazzymap you can do so by adding the snazzymap styles on line 496 of system/third\_party/mx\_google\_map/ft.mx\_google\_map.php.

Download the snazzymap you want to apply. View the source. Copy from:

```
// How you would like to style the map.
// This is where you would paste any style found on Snazzy Maps.
    styles: ... ]}]

```

And then paste it just after:

```
jQuery(document).ready(function() {
    jQuery("#'.$randid.'_map").mxgoogleMaps({
    latitude: '.$data["latitude"].',
    longitude: '.$data["longitude"].',
    zoom:  '.$zoom.',
    markers: ['.$markers.'],

```

So it looks something like this:

```
   [...]
   markers: ['.$markers.'],

   // Snazzy maps hackery
   styles: [{"featureType":"landscape","stylers":[{"saturation":-100},{"lightness":65},{"visibility":"on"}]},{"featureType":"poi","stylers":[{"saturation":-100},{"lightness":51},{"visibility":"simplified"}]},{"featureType":"road.highway","stylers":[{"saturation":-100},{"visibility":"simplified"}]},{"featureType":"road.arterial","stylers":[{"saturation":-100},{"lightness":30},{"visibility":"on"}]},{"featureType":"road.local","stylers":[{"saturation":-100},{"lightness":40},{"visibility":"on"}]},{"featureType":"transit","stylers":[{"saturation":-100},{"visibility":"simplified"}]},{"featureType":"administrative.province","stylers":[{"visibility":"off"}]},{"featureType":"water","elementType":"labels","stylers":[{"visibility":"on"},{"lightness":-25},{"saturation":-100}]},{"featureType":"water","elementType":"geometry","stylers":[{"hue":"#ffff00"},{"lightness":-25},{"saturation":-97}]}],
   // End Snazzy maps hackery

   field_id : "'.$randid.'"
   [...]

```

Remember to add a comma after the closing square bracket `]}],`.
> 2 votes

---
Tags: mx-google-map
---


title: Low Search + Matrix field data

text:
# Question
Title: Low Search + Matrix field data
I'm trying to create a dropdown of matrix field data using the search form. It's outputting the matrix data, but I can't seem to figure out how to remove duplicate content. Say I'm using the data "john doe" on multiple entries -- it's showing for every entry, not just once. Is there any way to fix this? Thanks in advance.

```
{exp:low_search:form query="{segment_3}"}
    <label>Arranger:</label>
    <select name="search:tags:arranger">
        {exp:channel:entries channel="products" dynamic="no"}
            {tags}<option value="{arranger}">{arranger}</option>{/tags}
        {/exp:channel:entries}
    </select>
    <button type="submit">Search</button>
{/exp:low_search:form}

```

# Answer
You'll need to use the Query module for this. Something like

```
{exp:query sql="SELECT DISTINCT col_id_X AS val FROM exp_matrix_data WHERE field_id = Y ORDER BY val"}
  <option>{val}</option>
{/exp:query}

```

...where you need to replace `X` with the correct column ID and `Y` with the correct field ID.

**EDIT** Alternatively, you can try this query:

```
{exp:query sql="SELECT col_id_X AS val FROM exp_matrix_data WHERE field_id = Y AND col_id_X != '' GROUP BY col_id_X ORDER BY val"}
  <option>{val}</option>
{/exp:query}

```
> 1 votes

---
Tags: low-search
---


# Question
Title: Stash - tag pairs to set multiple variables at once - no results / no_results
This one kept me busy for a while and I although could find similar questions none of the solutions worked.

Using template partials, gather the page content then send though (via embed) to a master wrapper template. This site has 'pages' where the URL should identify a unique entry, but EE tries it's best to show something, adding `require_entry` in the Channel tag should trigger `no_results` if an entry can't be found.

`{no_results}` works as expected when trying the `channel:entries` tag (below) outside of stash. Looking at stash docs, `unprefix` is specifically for this scenario. The below code **does** work.

```
{exp:stash:set
    name        = "st_page_content"
    parse_tags  = "yes"
    unprefix    = "my_prefix"
}
    {exp:channel:entries
            channel         = "channel_short_name"
            limit           = "1"
            require_entry   = "yes"
        }

    <p>{title}</p>

    {if my_prefix:no_results}<p>no results</p>{/if}

    {/exp:channel:entries}
{/exp:stash:set}

```

But it **doesn't** work when stashing multiple variables between 1 stash tag pair. Eg. `no_results` is **not** stored in `st_page_content`:

```
{exp:stash:set
    name        = "st_page_content"
    parse_tags  = "yes"
    unprefix    = "my_prefix"
}

    {stash:st_entry_id}{entry_id}{/stash:st_entry_id}

    {stash:st_page_content}

        {exp:channel:entries
                channel         = "channel_short_name"
                limit           = "1"
                require_entry   = "yes"
            }

        <p>{title}</p>

        {if my_prefix:no_results}<p>no results</p>{/if}

        {/exp:channel:entries}

    {/stash:st_page_content}

{/exp:stash:set}

```

EE 2.9.2
Stash 2.6.1 (Dev)

# Answer
> 0 votes
I feel the example code in the question should work but it doesn't. Here's a solution. I understand why it does work, but it *seems* wrong.

```
{exp:stash:set
    name        = "st_page_content"
    parse_tags  = "yes"
    unprefix    = "my_prefix"
}

    {stash:st_entry_id}{entry_id}{/stash:st_entry_id}

    {stash:st_page_content}

        {exp:channel:entries
                channel         = "channel_short_name"
                limit           = "1"
                require_entry   = "yes"
            }

        <p>{title}</p>

        {if my_prefix:no_results}<p>no results</p>{/if}

        {/exp:channel:entries}

    {/stash:st_page_content}

    {if stash_prefix:no_results}
        {stash:st_page_content}{redirect="404"}{/stash:st_page_content}
    {/if}

{/exp:stash:set}

```

If EE can't find an entry, anything **not** inside `no_results` is discarded. So all that's left inside the `stash:set` is:

```
{if stash_prefix:no_results}
    {stash:st_page_content}{redirect="404"}{/stash:st_page_content}
{/if}

```

And now `st_page_content` will store just the no\_results content. It seems wrong to be setting the same variable twice but due to EEs parse order there's only ever one instance of `st_page_content`.

---

### Update 15/03/11

After getting feedback from Mark, there's another solution, that's really not that different! https://twitter.com/croxton/status/573949167824953344

> that's one way to do it. But you should be able to use {exp:stash:not\_found} inside the first conditional to return your 404.

https://github.com/croxton/Stash/wiki/%7Bexp:stash:not\_found%7D#advanced-example

I've tried this and it does **not** work:

```
{exp:stash:set
    name        = "st_page_content"
    parse_tags  = "yes"
    unprefix    = "my_prefix"
}

    {stash:st_entry_id}{entry_id}{/stash:st_entry_id}

    {stash:st_page_content}

        {exp:channel:entries
                channel         = "channel_short_name"
                limit           = "1"
                require_entry   = "yes"
            }

        <p>{title}</p>

        {if my_prefix:no_results}<p>no results</p>{/if}

        {/exp:channel:entries}

        {if stash_prefix:no_results}
            {exp:stash:not_found}
        {/if}

    {/stash:st_page_content}

{/exp:stash:set}

```

Putting the `{exp:stash:not_found}` in the first tag pair (`{stash:st_entry_id}`) doesn't work either.

But similar to my original solution wrapping `{exp:stash:not_found}` with the variable tag pair does work. This is exactly the same solution as using `{redirect="404"}` but maybe EEs redirect tag will cause problems in other circumstances.

Alternative solution:

```
{exp:stash:set
    name        = "st_page_content"
    parse_tags  = "yes"
    unprefix    = "my_prefix"
}

    {stash:st_entry_id}{entry_id}{/stash:st_entry_id}

    {stash:st_page_content}

        {exp:channel:entries
                channel         = "channel_short_name"
                limit           = "1"
                require_entry   = "yes"
            }

        <p>{title}</p>

        {if my_prefix:no_results}<p>no results</p>{/if}

        {/exp:channel:entries}

    {/stash:st_page_content}

    {if stash_prefix:no_results}
        {stash:st_page_content}{exp:stash:not_found}{/stash:st_page_content}
    {/if}

{/exp:stash:set}

```

---
Tags: stash
---


title: Cannot open any child page on site

text:
# Question
Title: Cannot open any child page on site
I cannot open any child page generated by EE in 2 of my 3 sites which use Multiple Site Manager. Only my 'home site,' which contains all the EE system files, can open child pages. I have them listed below for reference:

Site 1, can open child pages: http://beta.autouplinktech.com (home site) Site 2, cannot open child pages: http://dev.autouplinkusa.com Site 3, cannot open child pages: http://dev.customerlifecycle.com

# Answer
This might be a problem with your .htaccess rule for removing index.php.

If I access this company page with index.php it works just fine: http://dev.autouplinkusa.com/index.php/company

Do you have .htaccess file in place for all three sites?

See: https://stackoverflow.com/questions/13227820/htaccess-on-expressionengine-msm-site
> 0 votes

---
Tags: templates, multi-site-manager, children, child
---


# Question
Title: a less expensive way of grouping entries by category
I'm trying to figure out if there's a more performant way of getting entries grouped by category.

As you can see, I'm using NSM Categories module. Right now, this costing me 263 queries and 5 seconds of load. If I remove my if statements (only there because we have different markup for the first entry of a category and also spit out an opening ul element), performance increases dramatically using 63 queries in 2 seconds.

Can anyone suggest any improvements? With something so intensive, we'll be using CE Cache anyway but would like to improve even more before we get to that stage.

```
{exp:nsm_categories:archive
            enable="entries"
            category_channel_entry_limit="6"
            category="3|6|5|1|7|2"
        }
            <div class="category category--{category_url_title}">
                <h3 class="category__title"><a class="category__link" href="/channel/{category_url_title}">{category_name}</a></h3>

                {category_channel_entries}
                {if {category_channel_entry_count} == '1'}
                <div class="category__firstentry relative" style=
                "background-image: url(''); background-size: cover;">
                <div class="category__overlay absolute"></div><a class="title relative" href="">{title}</a>
                    <p class="author relative">by {exp:playa:children var_prefix="children" entry_id="{entry_id}" backspace="5"}{children:title}</a> and {/exp:playa:children}</p>
                </div>
                {/if}

                {if {category_channel_entry_count} == '2'}
                <ul class="category__entries">
                {/if}
                {if {category_channel_entry_count} > '1'}
                <li class="entry__single">
                    <a href="/article/{url_title}">{title}</a>
                </li>
                {/if}

                {/category_channel_entries}
            </div>
            {/exp:nsm_categories:archive}

```

# Answer
> 3 votes
So my experimentation here brought me to Stash.

Much more succinct now and gives me everything I need in just 66 queries before caching :)

```
{exp:channel:entries dynamic="no" channel="articles"}
     {categories}
      {exp:stash:append_list name="news_{category_id}"}
       {stash:item_title}{title} - {entry_date {gv_date_short}}{/stash:item_title}
      {/exp:stash:append_list}
     {/categories}
{/exp:channel:entries}

{exp:channel:category_archive channel="articles" show="not 4|22|24" style="linear"}
  {categories}
    <h2>{category_name} - {category_id}</h2>
    {exp:stash:get_list limit="6" name="news_{category_id}"}
    {if count == '1'}
    <h3>{item_title}</h3>
    {/if}
    {if count == '2'}
      <ul class="list">
    {/if}
    {if count > '1'}
    <li>{item_title}</li>
    {/if}
    {if count == total_results}
      </ul>
    {/if}
    {/exp:stash:get_list}
    {/categories}
{/exp:channel:category_archive}

```

# Answer
> 1 votes
Interesting approach. I would typically have used Stash to

* set a list of all my entries (capturing categories for each of them)
* set a list of all the categories I want

And then used nested `{exp:stash:get_list}` with `match_against` to get entries ordered by categories. Same principle as this gist by Mark Croxton

Don't know if that would lower your number of queries, though.

# Answer
> 0 votes
When using if conditionals you're going to have the overhead of parsing the template code within every condition and then getting rid of the ones that don't apply, for *every* iteration of your loop.

Using Switchee should greatly reduce this overhead as it's going to get rid of the non-matching conditions and only parse the one that matches.

I've seen some good performance improvements just by moving to using Switchee rather than using regular conditionals.

---
Tags: channel-entries, categories, stash, performance, caching
---


# Question
Title: New to Expression and have problems updating navagation bar
Site was out sourced and getting no response from developer.

I need to add a new link to one of the navigation bars. There are 2 top navigation bars on my site.

Main home page code:

```
{html-open}
{html-head-open}
{exp:low_variables:single var="meta"}
{exp:low_variables:single var="favicon"}
{exp:low_variables:single var="css"}
{exp:low_variables:single var="js"}
{embed="partial/html-head-close" is_home="true"}
{exp:stash:get name="content"}
{exp:low_variables:single var="html-close"}

```

---

code from Secondary navbar

```
<div class="navbar-secondary">
    <div class="container">
        {exp:structure:nav start_from="/" max_depth="1" css_class="list-inline list-unstyled" current_class="active" include="15|20|21"}
    </div>
</div>

```

---

I tried to add a 6 (page I need) to the Include and no go. If I remove the any of the include numbers and view rendered template they drop off and I can add them back, but new item won't work. any pointers in the right direction would be great.

Thank you

John

# Answer
You need to post a page that has been assigned to use Structure. Check Structure » Settings and use one of those channels.
> 1 votes

---
Tags: templates, structure, navigation, links
---


# Question
Title: How to Implement File Upload Progress Bar with BlueImp JQuery File Upload and Channel Form?
I have trouble combining Channel Form and BlueImp JQuery File Upload (https://github.com/blueimp/jQuery-File-Upload/).

I always getting "Your channel entry must have a title." although I have set the value of Title in HTML.

Basically I have these:

HTML:

```
{exp:channel:form channel="artworks" include_assets="no" include_jquery="no" json="yes" return="register/step3/{segment_3}"  class="artwork-form"}
  <input type="file" class="fileupload" data-directory="6" data-content-type="all" value="" name="artwork_image">
  <input type="text" class="form-control artwork_title" placeholder="Title" name="title" value="Title">
{/exp:channel:form}

```

JS:

```
$('.fileupload').fileupload({
            dataType: 'json',
            formData: $(this).closest('form.artwork-form').serialize(),
            add: function(e, data){
               var form = $(this).closest('form.artwork-form');

                $.each(data.files, function (index, file) {
                    form.find('.artwork_title').val(file.name);
                });

                data.submit();
            },
            submit: function(e, data) {
                var form = $(this).closest('form.artwork-form');
                data.formData = form.serialize();
                console.log(data.formData);

            },
    });

```

Here's what I see in firebug: Params:

```
ACT 7
RET http://localhost/register/step3test/263
URI register/step3test/263
XID
author_id   3
channel_id  13
entry_id    263
meta    VjpdYFRjVDNWPVEsACcFblFkBD5ZIVd+U3YD.... (cutted)
return  register/step3/263
return_url  register/step3/263

```

POST:

```
----------------------------22998389620162591192122547020 Content-Disposition: form-data; name="artwork_image"; filename="debate-ad.jpg" Content-Type: image/jpeg ÿØÿá�Exif��II

```

Response:

```
{"success":0,"errors":{"title":"Your channel entry must have a title.","url_title":"Unable to create valid URL Title for your entry"},"field_errors":[],"entry_id":false,"url_title":false,"channel_id":false}

```

Is there anything I missed?

Thanks a lot for your help!

# Answer
> 0 votes
you cannot send the file directly to the form's action method like what you are doing there. The reason for this is that the jQuery fileuploader will only send the file, and chunked as well, so EE will not get title etc.

Basically you need to create an addon with its own action method where you handle the upload and then return some kind of ID which you can use to identify the file later. This you store in a hidden post variable. Then you need to hook onto e.g. "channel\_form\_submit\_entry\_start" and process the file and store it in the format you need (e.g. File or Assets) on submit.

So, it's an elaborate process ;-)

# Answer
> 0 votes
Maybe take a look at Binder? It does the front end upload, not sure about progress bar mind you http://squarebit.co.uk/software/expressionengine/binder

---
Tags: file-uploads, channel-form, jquery
---


# Question
Title: Call EE publish from another module and prepopulate some fields
I have a custom module that members update team and player information. I would like to use a channel for publishing match reports rather than code it into the module.

Is it possible to call the content\_publish from another module and populate two fields depending on

logged in user or part of the link or add information to the url

# Answer
It looks like you are looking for Channel Entries API which you can call in your module to publish an entry whenever module's action is triggered.
> 0 votes

---
Tags: channel-entries, channel, custom-fields, module
---