Jump to content
benneke1984

Module natif Newsletter et le multilingue

Recommended Posts

Bonjour,

J'ai un site Prestashop 1.6.1.13 avec 3 langues installées.  J'ai des abonnés à ma newsletter, mais impossible de connaitre la langue de l'abonné.

Cette fonctionnalité est prévue ? Si non, comment puis-je l'ajouter? Un module dédié ou une modification du module existant?

Merci pour votre aide !

Ben

Share this post


Link to post
Share on other sites

Bonjour, je ne suis pas expert mais avec le gestionnaire SQL inclus dans Presta il doit y avoir moyen de faire çà. Par exemple en modifiant "simplement" la requête d'export clients.

J'espère que quelqu'un de plus calé te répondra dans ce sens.

Share this post


Link to post
Share on other sites

Hello Kokoon,

 

Oui effectivement pour les clients ayant un compte il n'y a pas de souci, je sais le faire.  Mais pas pour les clients qui se sont "simplement" inscrit à la newsletter via le bloc newsletter sur le site.  Je n'ai rien vu dans la DB qui me permette de voir dans quelle langue le client s'est inscrit.

Merci pour l'indice en tout cas !

Ben

Share this post


Link to post
Share on other sites

Bonjour,

Non en effet il n'y a aucun moyen, si ce n'est l'adresse IP qui peut être géolocalisée mais c'est compliqué et un peu boiteux comme solution (le résultat n'est pas fiable à % pour différente raisons).

Donc la seule solution serait de modifier le code et la table SQL du module pour qu'il enregistre la langue en se basant sur le cookie.

Share this post


Link to post
Share on other sites

Bonjour,

Il me semblait bien que ce serait une chose du genre...

L'url ou le cookie peuvent être utiliser effectivement.

Quelqu'un a déjà fait une telle modification ? J'i des connaissances en PHP et Mysql mais le système de codage prestashop est parfois... confus ;-)

Pour ne pas perdre ses modifications une fois codées, il faut passer par un override si j'ai bien capté ? Il faut aller lui dire qu'il existe un override ou il le découvre tout seul comme un grand ? (j'ai pas envie de recommencer la bidouille à la première mise à jour du bidulle)

Share this post


Link to post
Share on other sites

Salut ! 

Donc en gros si on parle bien du module blocknewsletter ça me semble pas trop dur. 

 

1) Override du module

L'action se passe dans blocknewsletter.php mais comme tu l'as dit, il faut l'override pour faire la modification proprement. 

Il faut donc créer un fichier blocknewsletter.php dans override/modules/blocknewsletter/ 

Avec la classe suivante :

<?php

class BlocknewsletterOverride extends Blocknewsletter
{
}

Ensuite il faut supprimer le fichier class_index.php dans /cache/ sinon Presta verra pas ta nouvelle classe.

2) Modification SQL

A. Version simple : 

Exécuter simplement : 

ALTER TABLE PREFIX_newsletter add id_lang int(11) not null AFTER id_shop_group;

B. Version propre qui demande une réinstallation du module : 

Il faut override (c'est à dire ajouter la méthode suivante dans la classe créée plus haut) la méthode install en ajoutant la colonne id_lang lors de la création de la table.

public function install()
{
	if (!parent::install() || !Configuration::updateValue('PS_NEWSLETTER_RAND', rand().rand()) || !$this->registerHook(array('header', 'footer', 'actionCustomerAccountAdd')))
		return false;

	Configuration::updateValue('NW_SALT', Tools::passwdGen(16));

	return Db::getInstance()->execute('
	CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'newsletter` (
		`id` int(6) NOT NULL AUTO_INCREMENT,
		`id_shop` INTEGER UNSIGNED NOT NULL DEFAULT \'1\',
		`id_shop_group` INTEGER UNSIGNED NOT NULL DEFAULT \'1\',
		`id_lang` int(11) NOT NULL,
		`email` varchar(255) NOT NULL,
		`newsletter_date_add` DATETIME NULL,
		`ip_registration_newsletter` varchar(15) NOT NULL,
		`http_referer` VARCHAR(255) NULL,
		`active` TINYINT(1) NOT NULL DEFAULT \'0\',
		PRIMARY KEY(`id`)
	) ENGINE='._MYSQL_ENGINE_.' default CHARSET=utf8');
}

3) Sauvegarde de la langue

Cette fois il faut override registerGuest de la sorte (on ajoute la colonne langue)

protected function registerGuest($email, $active = true)
{
    $sql = 'INSERT INTO '._DB_PREFIX_.'newsletter (id_shop, id_shop_group, id_lang, email, newsletter_date_add, ip_registration_newsletter, http_referer, active)
            VALUES
            ('.$this->context->shop->id.',
            '.$this->context->shop->id_shop_group.',
            '.(int)$this->context->cookie->id_lang.',
            \''.pSQL($email).'\',
            NOW(),
            \''.pSQL(Tools::getRemoteAddr()).'\',
            (
                SELECT c.http_referer
                FROM '._DB_PREFIX_.'connections c
                WHERE c.id_guest = '.(int)$this->context->customer->id.'
                ORDER BY c.date_add DESC LIMIT 1
            ),
            '.(int)$active.'
            )';

    return Db::getInstance()->execute($sql);
}

4) Afficher la langue dans la liste des emails.

On verra plus tard mais je pense que ça se passe dans la méthode renderList.

Et voila. 

Bon j'ai absolument pas testé mais ça me semble être la bonne direction... hésite à me dire si tu as un problème. :)

Bon courage

Edited by Matt K. (see edit history)

Share this post


Link to post
Share on other sites

Bonjour,

Voila j'ai réussi à avoir une partie de mon souci...

Une partie car j'ai toujours que des id et je voudrais aussi modifier cet id vers la langue, mais je tourne en rond.

 

Par contre pour l'affichage, il y a plus à modifier, car il faut aussi lui dire de récupérer la langue dans la table des clients (ce qu'il ne fait pas de base) et dans la table des inscrits sans compte.

J'ai donc écrit ceci (au cas ou cela pourrait servir à quelqu'un d'autre...)

	public function renderList()
	{
		$fields_list = array(

			'id' => array(
				'title' => $this->l('ID'),
				'search' => false,
			),
			'shop_name' => array(
				'title' => $this->l('Shop'),
				'search' => false,
			),
			'gender' => array(
				'title' => $this->l('Gender'),
				'search' => false,
			),
			'lastname' => array(
				'title' => $this->l('Lastname'),
				'search' => false,
			),
			'firstname' => array(
				'title' => $this->l('Firstname'),
				'search' => false,
			),
			'email' => array(
				'title' => $this->l('Email'),
				'search' => false,
			),
			'subscribed' => array(
				'title' => $this->l('Subscribed'),
				'type' => 'bool',
				'active' => 'subscribed',
				'search' => false,
			),
			'newsletter_date_add' => array(
				'title' => $this->l('Subscribed on'),
				'type' => 'date',
				'search' => false,
			),
			'id_lang' => array(
				'title' => $this->l('Language'),
				'search' => false,
			)
		);
		
		if (!Configuration::get('PS_MULTISHOP_FEATURE_ACTIVE'))
			unset($fields_list['shop_name']);

		$helper_list = New HelperList();
		$helper_list->module = $this;
		$helper_list->title = $this->l('Newsletter registrations');
		$helper_list->shopLinkType = '';
		$helper_list->no_link = true;
		$helper_list->show_toolbar = true;
		$helper_list->simple_header = false;
		$helper_list->identifier = 'id';
		$helper_list->table = 'merged';
		$helper_list->currentIndex = $this->context->link->getAdminLink('AdminModules', false).'&configure='.$this->name;
		$helper_list->token = Tools::getAdminTokenLite('AdminModules');
		$helper_list->actions = array('viewCustomer');

		/* Before 1.6.0.7 displayEnableLink() could not be overridden in Module class
		   we declare another row action instead 			*/
		if (version_compare(_PS_VERSION_, '1.6.0.7', '<'))
		{
			unset($fields_list['subscribed']);
			$helper_list->actions = array_merge($helper_list->actions, array('unsubscribe'));
		}

		// This is needed for displayEnableLink to avoid code duplication
		$this->_helperlist = $helper_list;

		/* Retrieve list data */
		$subscribers = $this->getSubscribers();
		$helper_list->listTotal = count($subscribers);

		/* Paginate the result */
		$page = ($page = Tools::getValue('submitFilter'.$helper_list->table)) ? $page : 1;
		$pagination = ($pagination = Tools::getValue($helper_list->table.'_pagination')) ? $pagination : 50;
		$subscribers = $this->paginateSubscribers($subscribers, $page, $pagination);

		return $helper_list->generateList($subscribers, $fields_list);
	}
	
	public function getSubscribers()
	{
		$dbquery = new DbQuery();
		$dbquery->select('c.`id_customer` AS `id`, s.`name` AS `shop_name`, gl.`name` AS `gender`, c.`lastname`, c.`firstname`, c.`email`, c.`newsletter` AS `subscribed`, c.`newsletter_date_add`, c.`id_lang`');
		$dbquery->from('customer', 'c');
		$dbquery->leftJoin('shop', 's', 's.id_shop = c.id_shop');
		$dbquery->leftJoin('gender', 'g', 'g.id_gender = c.id_gender');
		$dbquery->leftJoin('gender_lang', 'gl', 'g.id_gender = gl.id_gender AND gl.id_lang = '.(int)$this->context->employee->id_lang);
		$dbquery->where('c.`newsletter` = 1');
		if ($this->_searched_email)
			$dbquery->where('c.`email` LIKE \'%'.pSQL($this->_searched_email).'%\' ');

		$customers = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($dbquery->build());

		$dbquery = new DbQuery();
		$dbquery->select('CONCAT(\'N\', n.`id`) AS `id`, s.`name` AS `shop_name`, NULL AS `gender`, NULL AS `lastname`, NULL AS `firstname`, n.`email`, n.`active` AS `subscribed`, n.`newsletter_date_add`, n.`id_lang`');
		$dbquery->from('newsletter', 'n');
		$dbquery->leftJoin('shop', 's', 's.id_shop = n.id_shop');
		$dbquery->where('n.`active` = 1');
		if ($this->_searched_email)
			$dbquery->where('n.`email` LIKE \'%'.pSQL($this->_searched_email).'%\' ');

		$non_customers = Db::getInstance()->executeS($dbquery->build());

		$subscribers = array_merge($customers, $non_customers);

		return $subscribers;
	}

Ici j'ai bien entendu tout remis, mais il y a moyen de juste écrire ce qui change ou il vaut mieux avoir un "doublon" complet ?

Maintenant je vais m'attarder à l'export en CSV car si je ne sais pas exporter, cette belle liste ne me sert pas à grand chose ;-)

Merci pour les retours et/ou les améliorations à ajouter !

Share this post


Link to post
Share on other sites

Rebonjour à tous.

J'ai continuer de bosser un peu sur mon export en CSV et le fichier généré est bon, pas de souci de ce côté la.

Par contre, je ne sais pas y accéder sans passer par mon ftp. Pour expliquer, voici mon code qui se trouve dans le override :

	public function export_csv()
	{

		
		if (!isset($this->context))
			$this->context = Context::getContext();

		$result = $this->getCustomers();
		if ($result)
		{
			if (!$nb = count($result))
				$this->_html .= $this->displayError($this->l('No customers found with these filters!'));
			elseif ($fd = @fopen(dirname(__FILE__).'/'.strval(preg_replace('#\.{2,}#', '.', Tools::getValue('action'))).'_'.$this->file, 'w'))
			{
				$header = array('id', 'shop_name', 'gender', 'lastname', 'firstname', 'email', 'subscribed', 'subscribed_on','id_lang');
				$array_to_export = array_merge(array($header), $result);
//				pr($array_to_export);
//				die();
				foreach ($array_to_export as $tab)
					$this->myFputCsv($fd, $tab);
				fclose($fd);
				$this->_html .= $this->displayConfirmation(
					sprintf($this->l('The .CSV file has been successfully exported: %d customers found.'), $nb).'<br />
				<a href="'.$this->context->shop->getBaseURI().'modules/blocknewsletter/'.Tools::safeOutput(strval(Tools::getValue('action'))).'_'.$this->file.'">
				<b>'.$this->l('Download the file').' '.$this->file.'</b>
				</a>
				<br />
				<ol style="margin-top: 10px;">
					<li style="color: red;">'.
					$this->l('WARNING: When opening this .csv file with Excel, choose UTF-8 encoding to avoid strange characters.').
					'</li>
				</ol>');
			}
			else
				$this->_html .= $this->displayError($this->l('Error: Write access limited').' '.dirname(__FILE__).'/'.strval(Tools::getValue('action')).'_'.$this->file.' !');
		}
		else
			$this->_html .= $this->displayError($this->l('No result found!'));
	}

Le souci se situe au niveau du fichier créé.  Selon la ligne

$fd = @fopen(dirname(__FILE__).'/'.strval(preg_replace('#\.{2,}#', '.', Tools::getValue('action'))).'_'.$this->file, 'w')

Ce fichier se trouve dans mon dossier override.

Mais selon cette ligne

<a href="'.$this->context->shop->getBaseURI().'modules/blocknewsletter/'.Tools::safeOutput(strval(Tools::getValue('action'))).'_'.$this->file.'">

il va créer le lien vers l'emplacement du module natif.

Le souci est que :

1. je ne peux pas écrire dans un autre répertoire que dans celui ou est excécuté le script

2. je n'ai pas les droits d'accéder à n fichier se trouvant dans un dossier override dans l'état actuel des choses...

Ai-je raté une manipulation ?

La seule modification que j'ai fait dans cette fonction est le contenu de la variable

$header = array('id', 'shop_name', 'gender', 'lastname', 'firstname', 'email', 'subscribed', 'subscribed_on','id_lang');

ou j'ai ajouté en dernière entrée id_lang. Il y a moyen de lui dire que c'est juste cette variable qui change et qu'il doit excécuter le rester de la fonction tel qu'indiqué dans le module en natif ?

Merci pour vos réponses !

Ben

Share this post


Link to post
Share on other sites

Rebonjour,

J'ai encore changé des choses et j'ai le comportement que je souhaite, mais je n'aime pas beaucoup ma solution, donc si quelqu'un a une meilleure solution, elle est la bienvenue !

Dans mon override :

public function renderExportForm()
	{
		// Getting data...
		$countries = Country::getCountries($this->context->language->id);

		// ...formatting array
		$countries_list = array(array('id' => 0, 'name' => $this->l('All countries')));
		foreach ($countries as $country)
			$countries_list[] = array('id' => $country['id_country'], 'name' => $country['name']);

		$fields_form = array(
			'form' => array(
				'legend' => array(
					'title' => $this->l('Export customers\' addresses'),
					'icon' => 'icon-envelope'
				),
				'input' => array(
					array(
						'type' => 'select',
						'label' => $this->l('Customers\' country'),
						'desc' => $this->l('Filter customers by country.'),
						'name' => 'COUNTRY',
						'required' => false,
						'default_value' => (int)$this->context->country->id,
						'options' => array(
							'query' => $countries_list,
							'id' => 'id',
							'name' => 'name',
						)
					),
					array(
						'type' => 'select',
						'label' => $this->l('Newsletter subscribers'),
						'desc' => $this->l('Filter customers who have subscribed to the newsletter or not, and who have an account or not.'),
						'hint' => $this->l('Customers can subscribe to your newsletter when registering, or by entering their email in the newsletter block.'),
						'name' => 'SUSCRIBERS',
						'required' => false,
						'default_value' => (int)$this->context->country->id,
						'options' => array(
							'query' => array(
								array('id' => 0, 'name' => $this->l('All subscribers')),
								array('id' => 1, 'name' => $this->l('Subscribers with account')),
								array('id' => 2, 'name' => $this->l('Subscribers without account')),
								array('id' => 3, 'name' => $this->l('Non-subscribers'))
							),
							'id' => 'id',
							'name' => 'name',
						)
					),
					array(
						'type' => 'select',
						'label' => $this->l('Opt-in subscribers'),
						'desc' => $this->l('Filter customers who have agreed to receive your partners\' offers or not.'),
						'hint' => $this->l('Opt-in subscribers have agreed to receive your partners\' offers.'),
						'name' => 'OPTIN',
						'required' => false,
						'default_value' => (int)$this->context->country->id,
						'options' => array(
							'query' => array(
								array('id' => 0, 'name' => $this->l('All customers')),
								array('id' => 2, 'name' => $this->l('Opt-in subscribers')),
								array('id' => 1, 'name' => $this->l('Opt-in non-subscribers'))
							),
							'id' => 'id',
							'name' => 'name',
						)
					),
					array(
						'type' => 'select',
						'label' => 'Language',
						'desc' => 'Language',
						'name' => 'LANG',
						'required' => false,
						'default_value' => (int)$this->context->country->id,
						'options' => array(
							'query' => array(
								array('id' => 1, 'name' => $this->l('French')),
								array('id' => 3, 'name' => $this->l('Dutch')),
								array('id' => 4, 'name' => $this->l('English'))
							),
							'id' => 'id',
							'name' => 'name',
						)
					),
					array(
						'type' => 'hidden',
						'name' => 'action',
					)
				),
				'submit' => array(
					'title' => $this->l('Export .CSV file'),
					'class' => 'btn btn-default pull-right',
					'name' => 'submitExport',
				)
			),
		);

		$helper = new HelperForm();
		$helper->show_toolbar = false;
		$helper->table = $this->table;
		$lang = new Language((int)Configuration::get('PS_LANG_DEFAULT'));
		$helper->default_form_language = $lang->id;
		$helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0;
		$helper->id = (int)Tools::getValue('id_carrier');
		$helper->identifier = $this->identifier;
		$helper->submit_action = 'btnSubmit';
		$helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false).'&configure='.$this->name.'&tab_module='.$this->tab.'&module_name='.$this->name;
		$helper->token = Tools::getAdminTokenLite('AdminModules');
		$helper->tpl_vars = array(
			'fields_value' => $this->getConfigFieldsValues(),
			'languages' => $this->context->controller->getLanguages(),
			'id_language' => $this->context->language->id
		);

		return $helper->generateForm(array($fields_form));
	}
	


	public function getCustomers()
	{
		$id_shop = false;

		// Get the value to know with subscrib I need to take 1 with account 2 without 0 both 3 not subscrib
		$who = (int)Tools::getValue('SUSCRIBERS');

		// get optin 0 for all 1 no optin 2 with optin
		$optin = (int)Tools::getValue('OPTIN');

		$country = (int)Tools::getValue('COUNTRY');
		
		$id_lang = (int)Tools::getValue('LANG');

		if (Context::getContext()->cookie->shopContext)
			$id_shop = (int)Context::getContext()->shop->id;

		$customers = array();
		if ($who == 1 || $who == 0 || $who == 3)
		{
			$dbquery = new DbQuery();
			$dbquery->select('c.`id_customer` AS `id`, s.`name` AS `shop_name`, gl.`name` AS `gender`, c.`lastname`, c.`firstname`, c.`email`, c.`newsletter` AS `subscribed`, c.`newsletter_date_add`');
			$dbquery->from('customer', 'c');
			$dbquery->leftJoin('shop', 's', 's.id_shop = c.id_shop');
			$dbquery->leftJoin('gender', 'g', 'g.id_gender = c.id_gender');
			$dbquery->leftJoin('gender_lang', 'gl', 'g.id_gender = gl.id_gender AND gl.id_lang = '.$this->context->employee->id_lang);
			$dbquery->where('c.`newsletter` = '.($who == 3 ? 0 : 1));
			if ($optin == 2 || $optin == 1)
				$dbquery->where('c.`optin` = '.($optin == 1 ? 0 : 1));
			if ($country)
				$dbquery->where('(SELECT COUNT(a.`id_address`) as nb_country
													FROM `'._DB_PREFIX_.'address` a
													WHERE a.deleted = 0
													AND a.`id_customer` = c.`id_customer`
													AND a.`id_country` = '.$country.') >= 1');
			if ($id_shop)
				$dbquery->where('c.`id_shop` = '.$id_shop);
			if ($id_lang)
				$dbquery->where('c.`id_lang` = '.$id_lang);

			$customers = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($dbquery->build());
		}

		$non_customers = array();
		if (($who == 0 || $who == 2) && (!$optin || $optin == 2) && !$country)
		{
			$dbquery = new DbQuery();
			$dbquery->select('CONCAT(\'N\', n.`id`) AS `id`, s.`name` AS `shop_name`, NULL AS `gender`, NULL AS `lastname`, NULL AS `firstname`, n.`email`, n.`active` AS `subscribed`, n.`newsletter_date_add`');
			$dbquery->from('newsletter', 'n');
			$dbquery->leftJoin('shop', 's', 's.id_shop = n.id_shop');
			$dbquery->where('n.`active` = 1');
			if ($id_shop)
				$dbquery->where('n.`id_shop` = '.$id_shop);
			if ($id_lang)
				$dbquery->where('n.`id_lang` = '.$id_lang);	

			$non_customers = Db::getInstance()->executeS($dbquery->build());
		}

		$subscribers = array_merge($customers, $non_customers);
		return $subscribers;
	}

Et dans le module d'origine j'ai "bidouillé" la  function getCustomers() en fonction public au lieu de private.

Cela ouvre certainement la porte à des bugs ou des erreurs, mais je n'ai pas trouvé d'autres possibilités.

Merci à tous pour l'aide apportée et pour l'éventuelle solution à ma bidouille...

Share this post


Link to post
Share on other sites

Bonjour, 

Je pense pas que ça va te créer des bugs. Il faudra juste faire attention lors des mises à jour de ce module à remettre "public" (d'ailleurs l'accesseur "protected" me semble être plus approprié mais bon c'est du détail). ;)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...

Important Information

Cookies ensure the smooth running of our services. Using these, you accept the use of cookies. Learn More