Adding a custom field to Magento's subscription module
Asked Answered
M

5

9

The newsletter subscription module in Magento has only one field (email) by default. After I add an extra field to the form (say country), how can I get the form data to show up in the Magento back-end and be sent as an email to a preset recipient? Thanks.

Multitudinous answered 1/7, 2010 at 7:25 Comment(0)
A
24

There are a few things that you need to take care of to make this work:

  1. Add a new column for your data to the appropriate database table
  2. Make sure that Magento saves your new field to the database
  3. Present the data in the admin backend
  4. Record the data when you get a new newsletter subscription

Here's how you can do all those things:

Ad. 1)

Using phpMyAdmin, MySQL command line, or whatever is your preferred DB manipulation method, add a new column "country" as, say, varchar(100) to the newsletter_subscriber table.

Ad. 2)

Magento will automatically give you access to the new field through the getCountry() and setCountry() methods on the Mage_Newsletter_Model_Subscriber object. The only thing it won't do is save your field back to the DB after it has been changed with code somewhere in the system. To get it saved you need to modify _prepareSave(Mage_Newsletter_Model_Subscriber $subscriber) function found in Mage_Newsletter_Model_Mysql4_Subscriber (app/code/core/Mage/Newsletter/Model/Mysql4/Subscriber.php). Be sure to make a local copy of the file first and not modify the core file. Here's what you need to add:

protected function _prepareSave(Mage_Newsletter_Model_Subscriber $subscriber)
{
    $data = array();
    $data['customer_id'] = $subscriber->getCustomerId();
    $data['store_id'] = $subscriber->getStoreId()?$subscriber->getStoreId():0;
    $data['subscriber_status'] = $subscriber->getStatus();
    $data['subscriber_email']  = $subscriber->getEmail();
    $data['subscriber_confirm_code'] = $subscriber->getCode();

    //ADD A NEW FIELD START

    //note that the string index for the $data array
    //must match the name of the column created in step 1
    $data['country'] = $subscriber->getCountry();

    //ADD A NEW FIELD END
    (...)
}

Ad. 3)

You will need to modify (a local copy of) the file app/code/core/Mage/Adminhtml/Block/Newsletter/Subscriber/Grid.php. The method you are looking for is called _prepareColumns(). In there you will see a series of calls to $this->addColumn(). You need to add a corresponding call for your "Country" field with the following code:

$this->addColumn('country', array(
    'header'    => Mage::helper('newsletter')->__('Country'),
    //the index must match the name of the column created in step 1
    'index'     => 'country',
    'default'   =>    '----'
));

If you want the field to appear at the end of the grid (as the last column) add it as the last call, otherwise, squeeze it between the existing calls exactly where you want it to end up in the admin.

Ad. 4)

This is a part I did not have to do in my customization of the Magento newsletter, so it will be mostly theoretical. The subscription occurs in the controller located at app/code/core/Mage/Newsletter/controllers/SubscriberController.php. Here's the code of the newAction method with my proposed changes:

public function newAction()
{
    if ($this->getRequest()->isPost() && $this->getRequest()->getPost('email')) {
        $session   = Mage::getSingleton('core/session');
        $email     = (string) $this->getRequest()->getPost('email');

        try {
            if (!Zend_Validate::is($email, 'EmailAddress')) {
                Mage::throwException($this->__('Please enter a valid email address'));
            }

            $status = Mage::getModel('newsletter/subscriber')->subscribe($email);
            if ($status == Mage_Newsletter_Model_Subscriber::STATUS_NOT_ACTIVE) {
                $session->addSuccess($this->__('Confirmation request has been sent'));
            }
            else {
                $session->addSuccess($this->__('Thank you for your subscription'));
            }
                
                //ADD COUNTRY INFO START
                
                //at this point we may safly assume that subscription record was created
                //let's retrieve this record and add the additional data to it
                $subscriber = Mage::getModel('newsletter/subscriber')->loadByEmail($email);
                
                //assuming that the input's id is "country"
                $subscriber->setCountry((string) $this->getRequest()->getPost('country'));
                
                //don't forget to save the subscriber!
                $subscriber->save();
                
                //ADD COUNTRY INFO END
        }
        catch (Mage_Core_Exception $e) {
            $session->addException($e, $this->__('There was a problem with the subscription: %s', $e->getMessage()));
        }
        catch (Exception $e) {
            $session->addException($e, $this->__('There was a problem with the subscription'));
        }
    }
    $this->_redirectReferer();
}

Going through the above steps should take care of the most part of your problem. Let me know how that last part worked out, as I did not have a chance to test it.

Once you have your additional field in the Subscriber object you can do whatever you want with it. I did not really get what you mean by

be sent as an email to a preset recipient

If you can explain that I will try to help you out with this part too.

Edit - how to send a mail when someone subscribes

Just add the following code to the controller after the part which adds country to a subscriber object.

$mail = new Zend_Mail();
$mail->setBodyHtml("New subscriber: $email <br /><br />Country: ".$this->getRequest()->getPost('country'));
$mail->setFrom("[email protected]")
->addTo("[email protected]")
->setSubject("Your Subject here");
$mail->send(); 
Austronesian answered 3/7, 2010 at 22:11 Comment(5)
thanks for a brilliant reply. 'be sent as an email.." means i'd like the subscriber info (email and country in this case) to be sent as an email to the admin (say [email protected]). so i have the info added to the database and sent as an email too. thanksMultitudinous
there is no _prepareSave function in the file that you mentioned.. I'm using 1.4.0.1... or I'm just missing something?Faux
I'm also missing the _prepareSave function. Can't actually find it anywhere within app/code/Petersham
@Austronesian I am using 1.7 and did not find the _prepareSave in the file you mentioned above. Please let me know how to do it? Thanks in advance.Odont
sorry guys, I'm not working with magento anymore, so can't comment on the changes in recent releases. Hopefully other users can pitch in...Austronesian
A
34

If you want to add some custom fields for Magento newsletter subscriber (for example subscriber_name), you should do the following:

  • Add new column for newsletter_subscriber table
  • Add text input to newsletter template
  • Create observer for newsletter_subscriber_save_before event

In the observer you can get your custom field's value from request and assign it to subscriber's object:

public function newsletterSubscriberSave(Varien_Event_Observer $observer)
{
    $subscriber = $observer->getEvent()->getSubscriber();
    $name = Mage::app()->getRequest()->getParam('subscriber_name');

    $subscriber->setSubscriberName($name);

    return $this;
}


UPDATE:

Here is the detailed article explaining how to add Country field Also, I have created a free module, it is available on the GitHub

Arvid answered 21/6, 2011 at 13:5 Comment(13)
This solution is simpler it should be rewarded IMHOEstablishment
This is definitely the solution.... what code has to go into config.xml to get this to work? I know it starts with frontend> <events> <newsletter_subscriber_save_before> <observers> but I can't work out what the next part is..Chuch
Which version of Magento is this for? I can't find any events for a subscribe action.Chuch
@AdamMoss this event is being generated by Mage_Newsletter_Model_Subscriber - you can't find it explicitly by event name.Arvid
@WebFlakeStudio Thanks. Not sure why but this function just isn't working at the moment. The subscriber table has both a first and last name, but I've also tried this and it still won't work: $subscriber->setFirstname($firstname); do you know what the code is for this on 1.5?Chuch
Just noticed that the table says 'Customer First Name' and 'Customer Last Name' - does this mean that the name attributes can only be used by customers and not general subscribers? No matter what I try I can't seem to get a subscriber to have anything other than an email address.Chuch
@AdamMoss oh, I forgot to tell, that you actually need to modify subscribers table. I updated my answer above.Arvid
@WebFlakeStudio ah that makes much more sense - working now! thanks :)Chuch
@WebFlakeStudio i'm having a few issues implementing this, could you inform me what file to put the observer in?Extensive
@Extensive here you can find information about creating observers in Magento #2048958. And here more detailed explanation magentocommerce.com/wiki/5_-modules_and_development/0-_module_development_in_magento/customizing_magento_using_event-observer_method#customize_magento_using_eventobserverArvid
What about the grid display in backend? Will this code update it as well?Surgery
No, you should make additional changes to grid.Arvid
@RomanSnitko I am using 1.7 and I am not a developer can you please tell me in which file I need to put the code you have mentioned above and how to make changes to grid?Odont
A
24

There are a few things that you need to take care of to make this work:

  1. Add a new column for your data to the appropriate database table
  2. Make sure that Magento saves your new field to the database
  3. Present the data in the admin backend
  4. Record the data when you get a new newsletter subscription

Here's how you can do all those things:

Ad. 1)

Using phpMyAdmin, MySQL command line, or whatever is your preferred DB manipulation method, add a new column "country" as, say, varchar(100) to the newsletter_subscriber table.

Ad. 2)

Magento will automatically give you access to the new field through the getCountry() and setCountry() methods on the Mage_Newsletter_Model_Subscriber object. The only thing it won't do is save your field back to the DB after it has been changed with code somewhere in the system. To get it saved you need to modify _prepareSave(Mage_Newsletter_Model_Subscriber $subscriber) function found in Mage_Newsletter_Model_Mysql4_Subscriber (app/code/core/Mage/Newsletter/Model/Mysql4/Subscriber.php). Be sure to make a local copy of the file first and not modify the core file. Here's what you need to add:

protected function _prepareSave(Mage_Newsletter_Model_Subscriber $subscriber)
{
    $data = array();
    $data['customer_id'] = $subscriber->getCustomerId();
    $data['store_id'] = $subscriber->getStoreId()?$subscriber->getStoreId():0;
    $data['subscriber_status'] = $subscriber->getStatus();
    $data['subscriber_email']  = $subscriber->getEmail();
    $data['subscriber_confirm_code'] = $subscriber->getCode();

    //ADD A NEW FIELD START

    //note that the string index for the $data array
    //must match the name of the column created in step 1
    $data['country'] = $subscriber->getCountry();

    //ADD A NEW FIELD END
    (...)
}

Ad. 3)

You will need to modify (a local copy of) the file app/code/core/Mage/Adminhtml/Block/Newsletter/Subscriber/Grid.php. The method you are looking for is called _prepareColumns(). In there you will see a series of calls to $this->addColumn(). You need to add a corresponding call for your "Country" field with the following code:

$this->addColumn('country', array(
    'header'    => Mage::helper('newsletter')->__('Country'),
    //the index must match the name of the column created in step 1
    'index'     => 'country',
    'default'   =>    '----'
));

If you want the field to appear at the end of the grid (as the last column) add it as the last call, otherwise, squeeze it between the existing calls exactly where you want it to end up in the admin.

Ad. 4)

This is a part I did not have to do in my customization of the Magento newsletter, so it will be mostly theoretical. The subscription occurs in the controller located at app/code/core/Mage/Newsletter/controllers/SubscriberController.php. Here's the code of the newAction method with my proposed changes:

public function newAction()
{
    if ($this->getRequest()->isPost() && $this->getRequest()->getPost('email')) {
        $session   = Mage::getSingleton('core/session');
        $email     = (string) $this->getRequest()->getPost('email');

        try {
            if (!Zend_Validate::is($email, 'EmailAddress')) {
                Mage::throwException($this->__('Please enter a valid email address'));
            }

            $status = Mage::getModel('newsletter/subscriber')->subscribe($email);
            if ($status == Mage_Newsletter_Model_Subscriber::STATUS_NOT_ACTIVE) {
                $session->addSuccess($this->__('Confirmation request has been sent'));
            }
            else {
                $session->addSuccess($this->__('Thank you for your subscription'));
            }
                
                //ADD COUNTRY INFO START
                
                //at this point we may safly assume that subscription record was created
                //let's retrieve this record and add the additional data to it
                $subscriber = Mage::getModel('newsletter/subscriber')->loadByEmail($email);
                
                //assuming that the input's id is "country"
                $subscriber->setCountry((string) $this->getRequest()->getPost('country'));
                
                //don't forget to save the subscriber!
                $subscriber->save();
                
                //ADD COUNTRY INFO END
        }
        catch (Mage_Core_Exception $e) {
            $session->addException($e, $this->__('There was a problem with the subscription: %s', $e->getMessage()));
        }
        catch (Exception $e) {
            $session->addException($e, $this->__('There was a problem with the subscription'));
        }
    }
    $this->_redirectReferer();
}

Going through the above steps should take care of the most part of your problem. Let me know how that last part worked out, as I did not have a chance to test it.

Once you have your additional field in the Subscriber object you can do whatever you want with it. I did not really get what you mean by

be sent as an email to a preset recipient

If you can explain that I will try to help you out with this part too.

Edit - how to send a mail when someone subscribes

Just add the following code to the controller after the part which adds country to a subscriber object.

$mail = new Zend_Mail();
$mail->setBodyHtml("New subscriber: $email <br /><br />Country: ".$this->getRequest()->getPost('country'));
$mail->setFrom("[email protected]")
->addTo("[email protected]")
->setSubject("Your Subject here");
$mail->send(); 
Austronesian answered 3/7, 2010 at 22:11 Comment(5)
thanks for a brilliant reply. 'be sent as an email.." means i'd like the subscriber info (email and country in this case) to be sent as an email to the admin (say [email protected]). so i have the info added to the database and sent as an email too. thanksMultitudinous
there is no _prepareSave function in the file that you mentioned.. I'm using 1.4.0.1... or I'm just missing something?Faux
I'm also missing the _prepareSave function. Can't actually find it anywhere within app/code/Petersham
@Austronesian I am using 1.7 and did not find the _prepareSave in the file you mentioned above. Please let me know how to do it? Thanks in advance.Odont
sorry guys, I'm not working with magento anymore, so can't comment on the changes in recent releases. Hopefully other users can pitch in...Austronesian
L
0

Adding to the accepted answer, you can also get away with this a little easier if you're adding a date, datetime, or timestamp-type column.

In my case, I wanted to add a "Subscribed at Date" to my grid. To do this, I wrote my upgrade script, column type being TIMESTAMP and the default value being CURRENT_TIMESTAMP. This way, when the row is added, the current date/time is recorded.

Then, all you have to do is add your block customizations. I'd suggest doing it by extending Magento's grid block rather than doing the local codepool override though. This way, you only need to override _prepareColumns();

Loats answered 10/12, 2012 at 22:35 Comment(1)
"I wrote my upgrade script, column type being TIMESTAMP and the default value being CURRENT_TIMESTAMP. This way, when the row is added, the current date/time is recorded." This is a very good solution.Saenz
C
0

Old thread but if someone has the same question, there is a free extension, that adds fields for gender, firstname and lastname and makes it available in the backend grid for export via xml/csv: http://www.magentocommerce.com/magento-connect/extended-newsletter-subscription-for-guests.html

Perhaps you can extend the code to fit your needs.

Carlyle answered 19/1, 2014 at 16:42 Comment(1)
Could you add the extension code to GitHub?Saenz
S
0

This is a warning for anyone who's installed the Ebizmarts_MailChimp extension.

It's a great extension. But it adds subscriber_firstname and subscriber_lastname to the newsletter_subscriber table.

If you intend to create these fields, you should either "require" the Ebizmarts_MailChimp extension or check the fields don't exist before your extension creates them.

In the opposite, where you've created them and want to install the the Ebizmarts_MailChimp extension after you've created these fields, you will have to comment out the addColumn code for these two fields during installation.

Saenz answered 2/11, 2022 at 8:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.