How to set tracking URL for custom link?

Discussion in 'General discussions' started by Lakjin, Jun 3, 2015.

  1. Lakjin

    Lakjin Active Member

    Joined:
    Mar 1, 2015
    Messages:
    391
    Likes Received:
    30
    S.E:
    Expired
    L.T:
    Regular
    L.C:
    6
    I've added custom markup to at function getCommonTagsSearchReplace in CampaignHelper.php; the markup involves inserting URLs into campaigns. The markup itself works fine. However, the URLs are not being parsed into tracking URLs. Any way for me to do that?

    Thanks!
     
  2. twisted1919

    twisted1919 Administrator Staff Member

    Joined:
    Dec 27, 2014
    Messages:
    10,446
    Likes Received:
    2,430
    I am away from the code now, but i think the app trats tags that end with _URL] specially, so try to name your custom tags that are transformed into urls like [WHATEVER_DO_THIS_URL]
     
  3. Lakjin

    Lakjin Active Member

    Joined:
    Mar 1, 2015
    Messages:
    391
    Likes Received:
    30
    S.E:
    Expired
    L.T:
    Regular
    L.C:
    6
    Tried that, won't work :-( I think the function for parsing URLs into tracking URLs is called before getCommonTagsSearchReplace, so my markup doesn't have the URLs in there yet.
     
  4. twisted1919

    twisted1919 Administrator Staff Member

    Joined:
    Dec 27, 2014
    Messages:
    10,446
    Likes Received:
    2,430
    that would make sense and you'd have to hook in the behavior file directly, which isn't that desirable.
     
  5. Lakjin

    Lakjin Active Member

    Joined:
    Mar 1, 2015
    Messages:
    391
    Likes Received:
    30
    S.E:
    Expired
    L.T:
    Regular
    L.C:
    6
    Ya, I don't want to hook in the behavior file. Is there any other way?
     
  6. twisted1919

    twisted1919 Administrator Staff Member

    Joined:
    Dec 27, 2014
    Messages:
    10,446
    Likes Received:
    2,430
    There's no other way... Maybe we can add a new filter hook inthere and you could then use it?
    But you'll have to tell me what exactly you need and where you want the changes to happen in code so that i can take proper decision for the hook.
     
  7. Lakjin

    Lakjin Active Member

    Joined:
    Mar 1, 2015
    Messages:
    391
    Likes Received:
    30
    S.E:
    Expired
    L.T:
    Regular
    L.C:
    6
    What I needed was the ability to show different content to each user. So I added a shortcode (e.g. [MYSHORTCODE]) to my campaign and in getCommonTagsSearchReplace I replace that shortcode with my code to generate content for each user. This way, when a campaign is processed for each user, everyone gets the different content I want to show them as opposed to everyone getting the same thing.

    As part of this new markup, I have links that I would prefer to be tracked by MailWizz.
     
  8. twisted1919

    twisted1919 Administrator Staff Member

    Joined:
    Dec 27, 2014
    Messages:
    10,446
    Likes Received:
    2,430
    @Lakjin - Current code says:
    PHP:
    if (!$onlyPlainText) {
                if ((
    $emailFooter $customer->getGroupOption('campaigns.email_footer')) && strlen(trim($emailFooter)) > 5) {
                    
    $emailContent CampaignHelper::injectEmailFooter($emailContent$emailFooter$campaign);
                }
               
                if (!empty(
    $campaign->option) && !empty($campaign->option->embed_images) && $campaign->option->embed_images == CampaignOption::TEXT_YES) {
                    list(
    $emailContent$embedImages) = CampaignHelper::embedContentImages($emailContent$campaign);
                }
               
                if (!empty(
    $campaign->option) && $campaign->option->xml_feed == CampaignOption::TEXT_YES) {
                    
    $emailContent CampaignXmlFeedParser::parseContent($emailContent$campaign$subscribertrue);
                }
               
                if (!empty(
    $campaign->option) && $campaign->option->json_feed == CampaignOption::TEXT_YES) {
                    
    $emailContent CampaignJsonFeedParser::parseContent($emailContent$campaign$subscribertrue);
                }
       
                if (!empty(
    $campaign->option) && $campaign->option->url_tracking == CampaignOption::TEXT_YES) {
                    
    $emailContent CampaignHelper::transformLinksForTracking($emailContent$campaign$subscribertrue);
                }
               
                
    $emailData CampaignHelper::parseContent($emailContent$campaign$subscribertrue);    
                list(
    $toName$emailSubject$emailContent) = $emailData;
            }
    The parts that we are interested in is
    PHP:
                if (!empty($campaign->option) && $campaign->option->url_tracking == CampaignOption::TEXT_YES) {
                    
    $emailContent CampaignHelper::transformLinksForTracking($emailContent$campaign$subscribertrue);
                }
    What we can do is to have a hook that executes like:
    PHP:
               if (!empty($campaign->option) && $campaign->option->url_tracking == CampaignOption::TEXT_YES) {
                    
    $emailContent Yii::app()->hooks->applyFilters('some_hook_name_before_transform_links_for_tracking'$emailContent$campaign$subscribertrue);
                    
    $emailContent CampaignHelper::transformLinksForTracking($emailContent$campaign$subscribertrue);
                    
    $emailContent Yii::app()->hooks->applyFilters('some_hook_name_after_transform_links_for_tracking'$emailContent$campaign$subscribertrue);
                }
    and then you could eventually do, from an extension for example:
    PHP:
    Yii::app()->hooks->addFilter('some_hook_name_before_transform_links_for_tracking', function($emailContent$campaign$subscriber$bool){
         
    // alter the email content, i.e:
         
    $emailContent str_replace($arrayOfTags$arrayOfValues$emailContent);
         return 
    $emailContent;
    });
    If that helps you i could implement and then give you modified files.
     
  9. twisted1919

    twisted1919 Administrator Staff Member

    Joined:
    Dec 27, 2014
    Messages:
    10,446
    Likes Received:
    2,430
  10. Lakjin

    Lakjin Active Member

    Joined:
    Mar 1, 2015
    Messages:
    391
    Likes Received:
    30
    S.E:
    Expired
    L.T:
    Regular
    L.C:
    6
    If I were to throw my custom code in here:

    Code:
    Yii::app()->hooks->addFilter('some_hook_name_before_transform_links_for_tracking', function($emailContent, $campaign, $subscriber, $bool){
        //My code here
         return $emailContent;
    });
    Would this coded be executed on a per subscriber basis for each campaign or once per campaign? I ask because I need the shortcode replaced for each user individually (e.g. just like how [UPDATE_PROFILE] is a unique link for each user) as opposed to replace the shortcode once per campaign.
     
  11. twisted1919

    twisted1919 Administrator Staff Member

    Joined:
    Dec 27, 2014
    Messages:
    10,446
    Likes Received:
    2,430
    It's for each subscriber ;)
    Basically $subscriber is always a different one.

    I went further and implemented this:
    Open apps/common/components/helpers/CampaignHelper.php and find the transformLinksForTracking() public static method and make it:

    PHP:
    public static function transformLinksForTracking($contentCampaign $campaignListSubscriber $subscriber$canSave false)
        {
            
    $content    StringHelper::decodeSurroundingTags($content);
            
    $list       $campaign->list;
            
    $mustSave   false;
           
            
            
    $content Yii::app()->hooks->applyFilters('campaign_content_before_transform_links_for_tracking'$content$campaign$subscriber$list);
           
            if (!isset(
    self::$_trackingUrls[$campaign->campaign_id])) {
               
                
    self::$_trackingUrls[$campaign->campaign_id] = array();
               
                
    $urlModelsCount 0;
                if (
    $canSave) {
                    
    $urlModelsCount CampaignUrl::model()->countByAttributes(array(
                        
    'campaign_id' => $campaign->campaign_id,
                    ));    
                }

                
    $mustSave       $urlModelsCount == 0;
                
    $baseUrl        Yii::app()->options->get('system.urls.frontend_absolute_url');
                
    $trackingUrl    $baseUrl 'campaigns/[CAMPAIGN_UID]/track-url/[SUBSCRIBER_UID]';
       
                
    // (\042|\047) are octal quotes.
                
    $pattern '/href(\s+)?=(\s+)?(\042|\047)(\s+)?(.*?)(\s+)?(\042|\047)/i';
                if (!
    preg_match_all($pattern$content$matches)) {
                    return 
    $content;
                }
               
                
    $urls $matches[5];
                
    $urls array_map('trim'$urls);
                
    // combine url with markup
                
    $urls array_combine($urls$matches[0]);
                
    $foundUrls = array();
               
                foreach (
    $urls as $url => $markup) {
       
                    
    // external url which may contain one or more tags(sharing maybe?)
                    
    if (preg_match('/https?.*/i'$url$matches) && filter_var($urlFILTER_VALIDATE_URL)) {
                        
    $_url trim($matches[0]);
                        
    $foundUrls[$_url] = $markup;
                        continue;
                    }
                   
                    
    // local tag to be transformed
                    
    if (preg_match('/^\[([A-Z_]+)_URL\]$/'$url$matches)) {
                        
    $_url trim($matches[0]);
                        
    $foundUrls[$_url] = $markup;
                        continue;
                    }
                }
               
                if (empty(
    $foundUrls)) {
                
                    
    $content Yii::app()->hooks->applyFilters('campaign_content_after_transform_links_for_tracking'$content$campaign$subscriber$list);
                    return 
    $content;
                }
       
                
    $prefix $campaign->campaign_uid;
                
    $sort   = array();
               
                foreach (
    $foundUrls as $url => $markup) {

                    
    $urlHash sha1($prefix $url);
                    
    $track   $trackingUrl '/' $urlHash;
                    
    $length  strlen($url);
                   
                    
    self::$_trackingUrls[$campaign->campaign_id][] = array(
                        
    'url'       => $url,
                        
    'hash'      => $urlHash,
                        
    'track'     => $track,
                        
    'length'    => $length,
                        
    'markup'    => $markup,
                    );
                   
                    
    $sort[] = $length;
                }
               
                unset(
    $foundUrls);    
                
    // make sure we order by the longest url to the shortest
                
    array_multisort($sortSORT_DESCSORT_NUMERICself::$_trackingUrls[$campaign->campaign_id]);
               
                
    // one final check
                
    if (!$mustSave) {
                    
    $mustSave count(self::$_trackingUrls[$campaign->campaign_id]) != $urlModelsCount;
                }
            }
           
            if (!empty(
    self::$_trackingUrls[$campaign->campaign_id])) {
               
                
    $searchReplace = array();
                foreach (
    self::$_trackingUrls[$campaign->campaign_id] as $urlData) {
                    
    $searchReplace[$urlData['markup']] = 'href="'.$urlData['track'].'"';
                }
               
                
    $content str_replace(array_keys($searchReplace), array_values($searchReplace), $content);
                unset(
    $searchReplace);

                
    // save the url tags.
                
    if ($mustSave && $canSave) {
                   
                    foreach (
    self::$_trackingUrls[$campaign->campaign_id] as $urlData) {
                       
                        
    $urlModel CampaignUrl::model()->findByAttributes(array(
                            
    'campaign_id' => (int)$campaign->campaign_id,
                            
    'hash'        => $urlData['hash'],
                        ));
                       
                        if (!empty(
    $urlModel)) {
                            continue;
                        }
                       
                        
    $urlModel = new CampaignUrl();
                        
    $urlModel->campaign_id $campaign->campaign_id;
                        
    $urlModel->destination $urlData['url'];
                        
    $urlModel->hash $urlData['hash'];
                        
    $urlModel->save(false);
                    }
                }
            }
           
           
            
    $content Yii::app()->hooks->applyFilters('campaign_content_after_transform_links_for_tracking'$content$campaign$subscriber$list);
           
            
    // return transformed
            
    return $content;
        }
    After you save, you can do:
    PHP:
    Yii::app()->hooks->addFilter('campaign_content_before_transform_links_for_tracking', function($emailContent$campaign$subscriber$list){
    //My code here
    return $emailContent;
    });
    Test it and lemme know how it went.
     
  12. Lakjin

    Lakjin Active Member

    Joined:
    Mar 1, 2015
    Messages:
    391
    Likes Received:
    30
    S.E:
    Expired
    L.T:
    Regular
    L.C:
    6
    Awesome, will do! One question, though.

    How do I create an extension for MailWizz? Meaning, where do I throw this code into:
    PHP:
    Yii::app()->hooks->addFilter('campaign_content_before_transform_links_for_tracking', function($emailContent$campaign$subscriber$list){//My code herereturn $emailContent;
    });
    Right now I'm directly modifying MailWizz files which is a big no no since they will be overwritten upon update. If I can create an extension with the code shown above, that would work best.
     
  13. twisted1919

    twisted1919 Administrator Staff Member

    Joined:
    Dec 27, 2014
    Messages:
    10,446
    Likes Received:
    2,430
    Always create extensions, because from extensions you can simply replace the entire application...
    Here's an example:

    PHP:
    <?php defined('MW_PATH') || exit('No direct script access allowed');

    class 
    MyCampaignTagsExt extends ExtensionInit
    {
        
    // name of the extension as shown in the backend panel
        
    public $name 'My Campaign Tags';

        
    // description of the extension as shown in backend panel
        
    public $description 'My Campaign Tags';

        
    // current version of this extension
        
    public $version '1.0';

        
    // the author name
        
    public $author 'Your name';

        
    // author website
        
    public $website 'http://www.website.com/';

        
    // contact email address
        
    public $email 'your.email@domain.com';

        
    // in which apps this extension is allowed to run
        
    public $allowedApps = array('*');

        
    // can this extension be deleted? this only applies to core extensions.
        
    protected $_canBeDeleted true;

        
    // can this extension be disabled? this only applies to core extensions.
        
    protected $_canBeDisabled true;

        
    // run the extension, ths is mandatory
        
    public function run()
        {
            
    Yii::app()->hooks->addFilter('campaign_content_before_transform_links_for_tracking', function($content$campaign$subscriber$list){
                
    //My code here
                
    return $content;
            });
        }
    }
    Put this in a file called MyCampaignTagsExt.php then create a folder named my-campaign-tags and put the .php file in it and zip the folder then upload it into mailwizz as an extension.
     
  14. Lakjin

    Lakjin Active Member

    Joined:
    Mar 1, 2015
    Messages:
    391
    Likes Received:
    30
    S.E:
    Expired
    L.T:
    Regular
    L.C:
    6
    Awesome, thank you, will do that!
     
  15. Lakjin

    Lakjin Active Member

    Joined:
    Mar 1, 2015
    Messages:
    391
    Likes Received:
    30
    S.E:
    Expired
    L.T:
    Regular
    L.C:
    6
    Question. How do I utilize MailWizz's connection to MySQL? I want to run some queries directly on the database in the extension.
     
  16. twisted1919

    twisted1919 Administrator Staff Member

    Joined:
    Dec 27, 2014
    Messages:
    10,446
    Likes Received:
    2,430
  17. Lakjin

    Lakjin Active Member

    Joined:
    Mar 1, 2015
    Messages:
    391
    Likes Received:
    30
    S.E:
    Expired
    L.T:
    Regular
    L.C:
    6
  18. twisted1919

    twisted1919 Administrator Staff Member

    Joined:
    Dec 27, 2014
    Messages:
    10,446
    Likes Received:
    2,430
  19. Lakjin

    Lakjin Active Member

    Joined:
    Mar 1, 2015
    Messages:
    391
    Likes Received:
    30
    S.E:
    Expired
    L.T:
    Regular
    L.C:
    6
    I finally got around to doing what you said -- I updated apps/common/components/helpers/CampaignHelper.php and created and activated the following extension:

    PHP:
    <?php defined('MW_PATH') || exit('No direct script access allowed');

    class 
    MyCampaignTagsExt extends ExtensionInit
    {
        
    // name of the extension as shown in the backend panel
        
    public $name 'My Campaign Tags';

        
    // description of the extension as shown in backend panel
        
    public $description 'My Campaign Tags';

        
    // current version of this extension
        
    public $version '1.0';

        
    // the author name
        
    public $author 'Your name';

        
    // author website
        
    public $website 'http://www.website.com/';

        
    // contact email address
        
    public $email 'your.email@domain.com';

        
    // in which apps this extension is allowed to run
        
    public $allowedApps = array('*');

        
    // can this extension be deleted? this only applies to core extensions.
        
    protected $_canBeDeleted true;

        
    // can this extension be disabled? this only applies to core extensions.
        
    protected $_canBeDisabled true;

        
    // run the extension, ths is mandatory
        
    public function run()
        {
            
    Yii::app()->hooks->addFilter('campaign_content_before_transform_links_for_tracking', function($content$campaign$subscriber$list){
                        
    $content str_replace('[xxx]','yyy',$content);
                return 
    $content;
            });
        }
    }
    However, [xxx] is not being replaced in emails.
     
  20. Lakjin

    Lakjin Active Member

    Joined:
    Mar 1, 2015
    Messages:
    391
    Likes Received:
    30
    S.E:
    Expired
    L.T:
    Regular
    L.C:
    6
    I don't know if it helps but if I do this, then it works:

    PHP:
    public static function transformLinksForTracking($contentCampaign $campaignListSubscriber $subscriber$canSave false)
     {
    //code here
    $content StringHelper::decodeSurroundingTags($content);$list $campaign->list;$mustSave false;
    Of course, we don't want to edit MailWizz files, so I tried the following as well, but it didn't work:

    PHP:
    public static function transformLinksForTracking($contentCampaign $campaignListSubscriber $subscriber$canSave false)
     {
    $list $campaign->list;
    $content Yii::app()->hooks->applyFilters('campaign_content_before_transform_links_for_tracking'$content$campaign$subscriber$list);
    $content StringHelper::decodeSurroundingTags($content);$mustSave false;
     

Share This Page