CVS edit link for dfylstra

I've developed a "Third-Party Integration" module for the Infusionsoft CRM and email marketing system, originally for my own company's use. Infusionsoft has been growing in popularity, and there are some comments in the Drupal forums from people who are using it, but there doesn't seem to be a module on Drupal.org for Infusionsoft integration. So I'd like to contribute the module I've written, and I've sought to make it general-purpose and reasonably well documented. Below is the text displayed by the module's Help function:

[Infusionlink] This module links a Drupal site with an Infusionsoft application. It synchronizes Users in your Drupal site with Persons in Infusionsoft, in both directions, using contact information drawn from Profiles in Drupal. It allows you to run Infusionsoft Action Sets that can tag a Person, or add them to a follow-up sequence in Infusionsoft when they perform certain actions on your site, recognized by the Triggers module in Drupal.

This module uses Drupal XML-RPC facilities and the Infusionsoft XML-RPC API. To use this module, your Infusionsoft application must be API-enabled and you must save your Infusionsoft application name and API key in Site configuration - Infusionlink Settings.

This module will synchronize certain standard Person fields in Infusionsoft with User Profile fields in Drupal. To enable this, choose User Management - Profiles to define the fields. All of them must be in one Profile category - you enter this category name in Infusionlink settings. The field names must match the list below:

profile_firstname, profile_lastname, profile_jobtitle, profile_company, profile_phone1, profile_address1, profile_address2, profile_city, profile_state, profile_postalcode, profile_country, profile_persontype. If you use profile_persontype, your list of choices must match between Infusionsoft and the Profile field. To add fields or change these names, you will need to modify the module PHP source code (not very difficult).

If you use Infusionsoft Webforms for opt-ins, and you want these people added to your Drupal site, you must add an action to your Webform to send an HTTP POST to your Drupal site at http://yoursite.com/infusionlink_webform.

For your security, this module checks that the HTTP POST comes from an Infusionsoft server IP address, that you specify in Infusionlink settings (the last quad in the IP address is ignored). The default IP address 208.76.24.x is OK as of September 2010, but to make sure, leave this setting blank, fill out and submit your Webform, then use Reports - Recent log entries to see the IP address.

To define Action Sets to run, use Site configuration - Actions, choose an Advanced Action, enter an Infusionsoft Action Set ID and Drupal Node ID, then associate that Action with a Trigger on Content, Comment or User activity. To determine Action Set IDs, choose Setup - Action Sets in Infusionsoft, find your action and check the Id column.

Comments

dfylstra’s picture

Status: Postponed (maintainer needs more info) » Needs review
StatusFileSize
new13.69 KB

This is a CVS account application to start a new project for the module Infusionlink described in this issue. A zip archive containing the module files is attached.

avpaderno’s picture

Issue tags: +Module review

Hello, and thank you for applying for a CVS account. I am adding the review tags, and some volunteers will review the code, pointing out what it needs to be changed.

dfylstra’s picture

Category: task » feature

Reviewing the code myself, I have three changes planned to the initial upload:

1. Add an infusionlink.install file with a small uninstall function to remove the variables the module adds to the variables table.

2. Generalize the handling of profile categories to remove the requirement that all the profile fields to be synchronized are defined in one category. I just need to call profile_categories() and _profile_get_fields() to determine which categories I need to use when calling profile_save_profile().

3. Document/highlight and/or generalize the way the module forms the Drupal username when an HTTP POST from Infusionsoft is used to add a user to the Drupal site. In the current code, a username is formed from the first letter of the first name plus the last name.

It's worth noting that the Infusionsoft side of this integration is NOT very flexible -- there are a set of fixed field names in the Infusionsoft CRM database that must be used when sending user data to the CRM via XML-RPC, and an even more limited set of fixed field names that are passed to Drupal via an HTTP POST in the other direction. Because of this, and the specialized nature of the module, I haven't tried to build a general field mapping facility into this module.

avpaderno’s picture

Category: feature » task

Reviewing the code myself, I have three changes planned to the initial upload

If you plan to change the code, it would be better if you upload here the new version; it would be better for who review the code to review the latest developed code, to avoid to point out changes that you already did.

avpaderno’s picture

Status: Needs review » Needs work
  • The points reported in this review are not in order of importance / relevance.
  • Most of the times I report the code that present an issue. In such cases, the same error can be present in other parts of the code; the fact I don't report the same issue more than once doesn't mean the same issue is not present in different places.
  • Not all the reported points are application blockers; some of the points I report are simple suggestions to who applies for a CVS account. For a list of what is considered a blocker for the application approval, see CVS applications review, what to expect. Keep in mind the list is still under construction, and can be changed to adapt it to what has been found out during code review, or to make the list clearer to who applies for a CVS account.
  1. License files cannot be committed in Drupal.org repository. Projects committed in Drupal.org repository have the same license used by Drupal.
  2.     return t($txt, $replace);
    
    

    The first argument of t() is a literal string, not a concatenation of strings. The script used to create the translation template is not able to handle any dynamic value, even in the case of code similar to t($variable), or t(function()); this means that if the argument of the function is not a literal string, it will not appear in the translation template.

  3. Hook implementation comments should be like the following one:
    /**
     * Implements hook_menu().
     */
    

    As reported in Documenting hook implementations:

    If the implementation of a hook is rather standard and does not require more explanation than the hook reference provides, a shorthand documentation form may be used in place of the full function documentation block described above:

    /**
     * Implements hook_help().
     */
    function blog_help($section) {
      // ...
    }
    

    This generates a link to the hook reference, reminds the developer that this is a hook implementation, and avoids having to document parameters and return values that are the same for every implementation of the hook. Optionally, you can add more information in a separate paragraph to describe the particular quirks of your hook implementation.

    In the case of hooks that have variables in the names, such as hook_form_FORM_ID_alter(), a slightly expanded syntax should be used:

    /**
     * Implements hook_form_FORM_ID_alter() for node_type_form().
     */
    function mymodule_form_node_type_form_alter(&$form, &$form_state) {
      // ...
    }
    

    This generates a link to the hook reference, as well as to the particular form that is being altered. Again, optionally you can add more information in a separate paragraph to describe the particular quirks of your hook implementation.

  4. See http://drupal.org/coding-standards to understand how a module should be written. In particular, see how Drupal variables, global variables, constants, and functions defined from the module should be named; how the code should be formatted (in particular, the control structures).
  5. The module doesn't implement hook_uninstall(), or doesn't implement it to remove the Drupal variables it defines.
  6. /**
     * Implementation of infusionlink_admin_settings().
     * Store the Infusionsoft application name, API key, IP address,
     * and profile category name in the Drupal variables table.
     */
    

    The first part of the comment is used only for hook implementations.

  7.   $form['actionId'] = array(
        '#type' => 'textfield',
        '#title' => t('Action ID'),
        '#description' => t('Enter numeric Action Set ID from Infusionsoft Setup-Action Sets'),
        '#required' => TRUE,
        );
      $form['nodeId'] = array(
        '#type' => 'textfield',
        '#title' => t('Node ID'),
        '#description' => t('Enter numeric Node ID of page on your Drupal site'),
        '#required' => TRUE,
        );
      return $form;
    

    The default values are missing.

  8.       watchdog('infusionlink','Infusionlink_webform: Error saving user account.',
    
    

    The message should simply be Error saving the user account.

  9. function infusionlink_error($error) {
      if ($error->code <= 0) {
        $error->message = t('TCP/IP Socket could not be opened');
      }
      drupal_set_message(t('XML-RPC error: %message (@code)', array(
        '%message' => $error->message, '@code' => $error->code)));
      watchdog('infusionlink', 'XML-RPC error: %message (@code)', array(
        '%message' => $error->message, '@code' => $error->code));
    }
    
    

    The messages should end with a period.

  10.       watchdog('infusionlink', 'XML-RPC added Person: Id=!contactId', 
            array('!contactId' => $contactId), WATCHDOG_DEBUG);
    
    

    The placeholder is not if the right type, if the contact ID is not a number.

  11. The presence of commented out code makes me think the code is not complete, contrary to what required from the CVS application requirements.
  12.   drupal_set_message(t('XML-RPC error: %message (@code)', array(
        '%message' => $error->message, '@code' => $error->code)));
      watchdog('infusionlink', 'XML-RPC error: %message (@code)', array(
        '%message' => $error->message, '@code' => $error->code));
    
    

    Both the function calls miss the parameter for the severity; without that, the message is a notice or status message (which is not an error message).

dfylstra’s picture

Status: Needs work » Needs review
StatusFileSize
new8.25 KB

Thanks for the review comments. Attached is an updated archive in which I've tried to address both my own feature requests on October 4 (#1 - #3), and the review comments on October 11 (#1 - #12). The archive contains a new infusionlink.install file, and it no longer contains a license.txt file.

On #4, I believe the code does follow Drupal coding standards, but if there are exceptions I would appreciate comments. On #11, I have removed the hook_block() function that was used only for debugging, but I've left in a few commented-out watchdog calls that were useful to me in testing, and IMO would be useful to anyone else modifying the code.

avpaderno’s picture

Status: Needs review » Needs work
  1.  variable_get('infusionlink_ipAddress', '208.76.24.x')
    

    The coding standards report that Drupal variables, PHP variables, and PHP functions should use lowercase characters, numbers or the underscore character. This means also that the PHP variable $IPaddress should have a different name.
    The code sometimes call the Drupal variable infusionlink_ipAddress, and sometimes infusionlink_ipaddress; AFAIK, Drupal variable names are not case sensitive, but I could be wrong (or it could be changed in the future).

  2.   if (!empty($_POST['ContactType']))
        $edit['profile_persontype'] = $_POST['ContactType'];
      if (!empty($_POST['FirstName']))
        $edit['profile_firstname'] = $_POST['FirstName'];
      if (!empty($_POST['LastName']))
        $edit['profile_lastname'] = $_POST['LastName'];
      if (!empty($_POST['Company']))
        $edit['profile_company'] = $_POST['Company'];
      if (!empty($_POST['JobTitle']))
        $edit['profile_jobtitle'] = $_POST['JobTitle'];
      if (!empty($_POST['Phone1']))
        $edit['profile_phone1'] = $_POST['Phone1'];
      if (!empty($_POST['StreetAddress1']))
        $edit['profile_address1'] = $_POST['StreetAddress1'];
      if (!empty($_POST['StreetAddress2']))
        $edit['profile_address2'] = $_POST['StreetAddress2'];
      if (!empty($_POST['City']))
        $edit['profile_city'] = $_POST['City'];
      if (!empty($_POST['State']))
        $edit['profile_state'] = $_POST['State'];
      if (!empty($_POST['PostalCode']))
        $edit['profile_postalcode'] = $_POST['PostalCode'];
      if (!empty($_POST['Country']))
        $edit['profile_country'] = $_POST['Country'];
    

    As per Drupal coding standards (the ones I always make reference) the curly parentheses are not optional, in the control structures. This means that an IF-statement is always written as

      if ($test) {
        echo $test;
      }
    

    Following the format suggested from the coding standards help the security team, which has also the task to verify any security issues reported for the modules committed in Drupal.org repository; writing 12 IF-statements like that doesn't help the security team in finding out any possible security issues.

    The same format is used for the following code (it is also followed in other code lines I don't report here):

      if (isset($user->profile_firstname))
        $queryfields['FirstName'] = $user->profile_firstname;
      if (isset($user->profile_lastname))
        $queryfields['LastName'] = $user->profile_lastname;
      // Set contact fields...
      $contactfields = array( 'Email' => $user->init );
      if (isset($user->profile_firstname))
        $contactfields['FirstName'] = $user->profile_firstname;
      if (isset($user->profile_lastname))
        $contactfields['LastName'] = $user->profile_lastname;
      if (isset($user->profile_persontype))
        $contactfields['ContactType'] = $user->profile_persontype;
      if (isset($user->profile_company))
        $contactfields['Company'] = $user->profile_company;
      if (isset($user->profile_jobtitle))
        $contactfields['JobTitle'] = $user->profile_jobtitle;
      if (isset($user->profile_phone1))
        $contactfields['Phone1'] = $user->profile_phone1;
      if (isset($user->profile_address1))
        $contactfields['StreetAddress1'] = $user->profile_address1;
      if (isset($user->profile_address2))
        $contactfields['StreetAddress2'] = $user->profile_address2;
      if (isset($user->profile_city))
        $contactfields['City'] = $user->profile_city;
      if (isset($user->profile_state))
        $contactfields['State'] = $user->profile_state;
      if (isset($user->profile_postalcode))
        $contactfields['PostalCode'] = $user->profile_postalcode;
      if (isset($user->profile_country))
        $contactfields['Country'] = $user->profile_country;
    
  3.   $message = sprintf('XML-RPC error: %s (%d).', $error->message, $error->code);
      drupal_set_message($message, 'error');
    

    Strings used in the user interface should be translated; see the documentation for t() how strings are translated.

  4. As reported by the application requirements, any debugging code (even the commented out code) should be removed.
  5.     $txt = '<p>This module links a Drupal site with an Infusionsoft '
          .'application. It synchronizes Users in your Drupal site '
          .'with Persons in Infusionsoft, in both directions, using '
          .'contact information drawn from Profiles in Drupal. It '
          .'allows you to run Infusionsoft Action Sets that can tag a '
          .'Person, or add them to a follow-up sequence in Infusionsoft '
          .'when they perform certain actions on your site, recognized '
          .'by the Triggers module in Drupal.</p>'
          .'<p>This module uses Drupal XML-RPC facilities and the '
          .'Infusionsoft XML-RPC API. To use this module, your '
          .'Infusionsoft application must be API-enabled and you must '
          .'save your Infusionsoft application name and API key in '
          .'Site configuration - Infusionlink Settings.</p>'
          .'<p>This module will synchronize certain standard Person '
          .'fields in Infusionsoft with User Profile fields in Drupal. '
          .'To enable this, choose User Management - Profiles to define '
          .'the fields. The field names must match the list below:</p>'
          .'<p>profile_firstname, profile_lastname, profile_jobtitle, '
          .'profile_company, profile_phone1, profile_address1, '
          .'profile_address2, profile_city, profile_state, '
          .'profile_postalcode, profile_country, profile_persontype. '
          .'If you use profile_persontype, your list of choices must '
          .'match between Infusionsoft and the Profile field. To '
          .'add fields or change these names, you will need to modify '
          .'the module PHP source code (not very difficult).</p>'
          .'<p>If you use Infusionsoft Webforms for opt-ins, and you '
          .'want these people added to your Drupal site, you must add '
          .'an action to your Webform to send an HTTP POST to your '
          .'Drupal site at http://yoursite.com/infusionlink_webform. '
          .'Usernames for the Drupal site are created from the first '
          .'letter of the first name concatenated with the last name '
          .'as entered on the webform.</p>'
          .'<p>For your security, this module checks that the HTTP POST '
          .'comes from an Infusionsoft server IP address, that you '
          .'specify in Infusionlink settings (the last quad in the '
          .'IP address is ignored). The default IP address 208.76.24.x '
          .'is OK as of September 2010, but to make sure, leave this '
          .'setting blank, fill out and submit your Webform, then use '
          .'Reports - Recent log entries to see the IP address.</p>'
          .'<p>To define Action Sets to run, use Site configuration - '
          .'Actions, choose an Advanced Action, enter an Infusionsoft '
          .'Action Set ID and Drupal Node ID, then associate that '
          .'Action with a Trigger on Content, Comment or User activity. '
          .'To determine Action Set IDs, choose Setup - Action Sets in '
          .'Infusionsoft, find your action and check the Id column.</p>';
        $replace = array();
        return $txt;
    

    Strings used in the user interface should be translated.
    When possible, HTML tags should not be included in the translated strings; that doesn't mean to split a sentence or a phrase just to avoid to include an HTML tag in the string, though. In this case, this means the string can be split before <p> and after </p> (as those tags are placed before or after a sentence).

  6.   $form['infusionlink_apikey'] = array(
        '#type' => 'textfield',
        '#title' => t('API Key'),
        '#default_value' => variable_get('infusionlink_apikey', 'Your API Key'),
        '#description' => t('Copy and paste your API key here -- request this from Infusionsoft'),
        '#required' => TRUE,
        );
    

    The description strings should always end with a period.

  7.   $name = strtolower(substr($firstname,0,1) . $lastname);
    

    There is a Drupal function that should be used instead of strtolower() (see the Unicode Drupal functions reported in the coding standards).

dfylstra’s picture

StatusFileSize
new8.08 KB

On #1, thank you for noting the uppercase A in variable_get('infusionlink_ipAddress' ...) -- that was an oversight on my part, I have fixed this in the attached version.

On #2, the Drupal Coding Standards say "you are strongly encouraged to always use curly braces..." but I read this as an encouragement not a requirement, and I do not believe that adding curly braces, in this code, will add to readability or help the security team.

On #3, since this string is created dynamically, it cannot go inside the t() function as you pointed out earlier. Infusionsoft is available only in English-speaking countries, now and for the future I can foresee. For this specialized module, I do not feel it is worthwhile to put further effort into translation.

On #4, I have removed the commented-out watchdog calls, even though in my view it is much better practice to leave them in.

On #5, it appears that you've changed a simple string "http://yoursite.com/infusionlink_webform", illustrating what must be entered in the Infusionsoft system, into a long href tag which would be invalid if entered in the Infusionsoft system. This is not a good idea. I haven't changed the code here.

On #6, I have added the period at the end.

On #7, I have replaced strtolower() with drupal_strtolower(), even though this string is coming from Infusionsoft and this system is available only in English-speaking countries, and does not (and is unlikely to ever) generate multi-byte strings.

Just FYI, I'm extremely pressed for time and I probably cannot spend much more time on this contribution which is an optional activity for me, especially over the next couple of months. I do appreciate your time spent reviewing the code.

avpaderno’s picture

  1.   $message = sprintf('XML-RPC error: %s (%d).', $error->message, $error->code);
      drupal_set_message($message, 'error');
    
    On #3, since this string is created dynamically, it cannot go inside the t() function as you pointed out earlier.

    The string 'XML-RPC error:' is not dynamically created, but it's a static string. The error code could be only in English, but that is not translated, if passed through a place-holder.
    As such, the string still need to be passed to t() because it's a static string used in the user interface.
    There is then another reason to use t() and its placeholders: the strings used as placeholder are passed to check_plain(), which is necessary to avoid security issues.

  2. Following the Drupal coding standards is not optional; if that would be true, then a module could not suffix its function names with the module name (and have function names like node_test()).

    I do not believe that adding curly braces, in this code, will add to readability or help the security team.

    Believe me, the code as it is now is not much readable, especially from who is used to read code that follows the Drupal coding standards (as the security team is).

  3. On #5, it appears that you've changed a simple string "http://yoursite.com/infusionlink_webform", illustrating what must be entered in the Infusionsoft system, into a long href tag which would be invalid if entered in the Infusionsoft system. This is not a good idea. I haven't changed the code here.

    In point #5, I am reporting that you are using a not translated string in the user interface, when the strings used in the user interface should be translated. The implementation of hook_help() is only relevant on the Drupal-powered site, and it doesn't involve any external sites.

  4. Just FYI, I'm extremely pressed for time and I probably cannot spend much more time on this contribution which is an optional activity for me, especially over the next couple of months. I do appreciate your time spent reviewing the code.

    I take that means you would not have too much time to maintain the module, which is what you are supposed to do. What would happen if a user reports a bug report? Will you have the time to port the code to Drupal 7?

dfylstra’s picture

StatusFileSize
new8.17 KB

Responses to your comments are below. I made one other small change/improvement: If the user has enabled the module but has not (yet) set their Infusionsoft API key, the module would still attempt an XML-RPC connection to Infusionsoft, yielding a message and log entry each time a User account was updated. In the attached version, the connection is skipped when the API key is not set.

1. Your point is well taken. I have put the string 'XML-RPC error: %s (%d).' inside t(). Besides #3 below, I found one other place where t() should be used: The default values for two of the three variables (App Name and API Key) are really English strings, so they are also inside t() in the archive attached to this comment.

2. I don't agree with your readability comment, but I am persuaded by the idea that people who are used to reading lots of Drupal code that follows the curly-braces-always convention might be slowed down by the absence of them. So I've put in curly braces everywhere. I now find the code harder to read myself, but so be it.

3. I think I understand your point here. The Help text now has t() around each string *except* the illustrative URL http://yoursite.com/infusionlink_webform.

4. Regarding Drupal 7, I have looked at the APIs and indeed there are changes to some of the hooks used in this module. It won't be too much work but it will have to be done. When my company moves to D7 this module will be updated, and maybe sooner, but I am not promising #D7CX.

Let me be crystal clear about my intentions with this module. It is a pure volunteer effort and contribution to the community. I'm not a Drupal consultant nor am I seeking any Drupal community status or "cred". I own and I'm managing a software company in an unrelated area, and that comes first and takes about 70 hours per week of my time. I am frankly quite sure that, even in my very limited spare time, I can maintain this module better than many, if not most of the modules I find on Drupal.org, where all too often there have been no updates in the last year or two years. But if this is not good enough for you, I am more than willing to withdraw this CVS application, and either leave the files here for people who need to link to Infusionsoft, or take them down.

brianV’s picture

Status: Needs work » Needs review

Setting to needs review.

dfylstra’s picture

Six weeks have passed since the last comment from the (single) reviewer. I have made some enhancements to this module, and I'm planning some more, but I do not see a reason to post a new version unless and until there is a meaningful response from reviewers.

LateNightDesigner’s picture

I really like the idea and will try testing it if I can.
It's a shame that no one is testing this as this opens up a huge avenue for drupal over the wordpress projects. I'm currently fighting to keep drupal over having to switch to wordpress here in the office using infusionwp.com. So please, I'd love to see this project come to fruition!

dfylstra’s picture

Thanks very much for your comment, LateNightDesigner. I do know and like the InfusionWP people (Bob Keen, Micah Mitchell). If WordPress can meet your needs for site creation, InfusionWP has some very nice integration features. But for our purposes Drupal is far more powerful and flexible than WordPress, especially for a business-to-business marketer.

In the Infusionlink module, I've added the ability to trigger an action sequence in Infusionsoft when a Drupal site user downloads a certain file (the mechanism here is different from a user visiting a page, which can already trigger an action sequence), and the ability to create an order in Infusionsoft when a Drupal site user places an order through Ubercart. If you have a need for these, send me a message through my Drupal contact page and I'll reply.

But since there has been no community review for 10+ weeks, and no progress on turning this into a project on Drupal.org, I don't see the point of posting the enhancements publicly here.

chriscalip’s picture

I am also doing a third party integration with infusionsoft crm and drupal; more specifically just for webform 3.x and infusionsoft data integration. I've glance over this page, installed the infusionlink module and went through reviewing code with the help of the Coder module while it's settings admin/settings/coder are on strictest.

It yielded me the following:

Coder found 1 projects, 2 files, 1 critical warnings, 51 normal warnings, 19 minor warnings, 0 warnings were flagged to be ignored

I think it might help if the infusionlink module gets updated so there won't be any warnings.

regards,
Chris

avpaderno’s picture

Status: Needs review » Needs work

I am changing status as per previous comment.

chriscalip’s picture

For anyone interested on an update about the webform 3.x and infusionsoft crm data integration; my company did not get the work order to have this functionality :( Trying to achieve an integration between webform and infusionsoft crm might take quite a bit of time and doing this during my free time is low in my priority list.

zzolo’s picture

Component: Miscellaneous » miscellaneous
Status: Needs work » Closed (won't fix)

Hi. Please read all the following and the links provided as this is very important information about your CVS Application:

Drupal.org has moved from CVS to Git! This is a very significant change for the Drupal community and for your application. Please read the following documentation on how this affects and benefits you and the application process:
Migrating from CVS Applications to (Git) Full Project Applications

  • The status of this application will be put to "postponed" and by following the instructions in the above link, you will be able to reopen it.
  • Or if your application has been "needs work" for more than 5 weeks, your application will be marked as "closed (won't fix)". You can still reopen it, by reading the instructions above.
zjoia’s picture

With iSoft growing in popularity and the need for a Drupal Integration this module seems the best start to build a full integration plugin. If you are not interested in maintaining it would you be willing to allow someone to take over the development? My firm has a client who is looking for this exact solution, i'd hate to reinvent the wheel you've so nicely created.

zjoia’s picture

Title: dfylstra [dfylstra] » Take Over

I'll take the non-response as an abandonment from the author and will resume this project under a new name. When I have it up I will post back here. I am moving forward with a full membership management plugin with integration via iSoft's API.

mandolinrick’s picture

zjoia,

I would be interested in any new module you are developing. I am currently working with a client who needs Infustionsoft integrated with Drupal membership site.

Rick

dfylstra’s picture

Title: Take Over » Infusionsoft Integration Module
Status: Closed (won't fix) » Active

Not so fast, please, Adam. I am running a company, as you can see from earlier comments, and traveling a lot. I certainly haven't "abandoned" this effort -- we are using an enhanced version of this Infusionlink module on a production site. You are welcome to do whatever you want, but joining Drupal.org two weeks ago, posting one entry here, waiting four days, and then deciding to "take over" the project? How about posting some code, or a useful comment on the code previously posted?

Since I do have many competing priorities for my time, I would certainly be interested in working with someone who has significant Drupal experience to turn this effort into a Drupal.org project and contributed module. Can you do this? There's not enough information on your profile for me to know. You need to know a fair amount about Drupal module development, as well as about the Infusionsoft XML-RPC API. Also, you need to know about the review process on Drupal.org for new projects, and what they look for. Have you read http://groups.drupal.org/code-review?

zzolo’s picture

Component: miscellaneous » new project application

Hi @dfylstra. Not sure what happened when I updated this issue. I was doing a few hundred that night. Must have just made a mistake. You can keep this active, but you will have to move this a Git sandbox and then change the Project type. Please read: http://drupal.org/node/1075406

dfylstra’s picture

Thank you, zzolo. Reading http://drupal.org/node/1075406 about how "the community has been aware for some time that the CVS application process had become unwieldy..." this has certainly been my experience. I'm very impressed that you organized the Friday "Code Review Sprint" at DrupalCon Chicago to review the backlog of project applications (but I had to leave Chicago Thursday evening). I had heard from webchick a couple months ago that sandbox projects were coming, but I did not know that they were now available. So I will take the steps to move this to a Git sandbox.

dfylstra’s picture

This post is meant for people who are interested in using Drupal and Infusionsoft, and have found this page via a Google search or Drupal.org search. I'm trying to answer the question "Will this module work for me?" That depends, of course, on what you are trying to do with Drupal and Infusionsoft.

This module was written to solve the following problem: My company is moving from a conventional (HTML/CSS/JS) website to a Drupal website, and we use Infusionsoft for email marketing. On both our old and new sites, people opt-in via custom forms on the site, which creates a user account for them on the site. We wanted users added to the site this way to also be added (as Person records) in our Infusionsoft account. Second, when users show interest by visiting certain pages and taking other actions on our website, we want to fire action sequences in Infusionsoft, so they receive email follow-ups, our salespeople are notified, etc. (this is done via "Triggers" in Drupal).

Many companies use Infusionsoft Webforms to enable people to opt-in: this adds a Person record in your Infusionsoft account. We don't use Webforms very much ourselves, but the Infusionlink module does include the ability to automatically add a user account on a Drupal site when a visitor opts-in by filling out an Infusionsoft Webform. So "user synchronization" is two-way.

If this is what you need, you are welcome to use the code posted on this page (latest version); however this is NOT (yet) a regular Drupal project, and the module is not supported in any formal way -- so if you don't know Drupal very well, be cautious. But in the hands of an experienced Drupal developer, the code you can download here will likely save a lot of time. As noted in earlier posts, this module has been in production use for some time on our site, and it's based on earlier non-Drupal PHP code that I wrote for our old site, which has been in production use for three years and has registered hundreds of thousands of users.

This page started as a CVS application page. As noted above, I plan to move this effort into a Git sandbox (or "experimental") project, which is new on Drupal.org. I will endeavor to put a link from here to there when it's ready.

We use Ubercart with Drupal for e-commerce. For our site, I've extended the Infusionlink module so that, when a user places an order through Ubercart on the Drupal site, this order is also created and attached to the user's Person record in Infusionsoft (this is not yet in the code posted on this page, but it should show up in the Git sandbox). However, we have no need to go the other way, so that when a user or salesperson enters an order in Infusionsoft, it would be reflected in Ubercart on the Drupal site. This could be done, but it's low on my priority list. If you need this capability right away, this module may not help you.

About Drupal 7: We are using the Drupal Commons distribution, which is based on Drupal 6; since it depends on many other contributed modules for D6, it will be some time before Drupal Commons (and hence our site) moves to Drupal 7. The current Infusionlink module calls the Drupal 6 APIs, and several of these have changed in Drupal 7 ("the drop is always moving"). It shouldn't be hard for an experienced Drupal developer to modify the existing code for D7, but this is not yet high on my priority list. If you want to start with, or move to Drupal 7 very soon, you have to take this into account.

So, is this module for you? Here are some use cases:

  • If you are committed to Drupal, and you're looking for an email marketing and/or customer relationship management system, I can recommend Infusionsoft, and you'll probably find this module very useful. If you are or have someone who's an experienced Drupal developer and you're willing to contribute to this module, by all means contact me, via my Drupal.org contact page.
     
  • If you are committed to Infusionsoft, and looking for a tool to build a website or web application, I can certainly recommend Drupal, but with some caveats: Drupal has a VERY steep learning curve, which may take you a year or more to climb. What you get in return for this is incredible power and flexibility -- but you will need to make that climb. If you do, I'd love to have you help with this module.
     
  • If what you need is a membership site -- where there is some content available to all visitors, some content available only to logged-in users, and some "premium" content available only with paid membership at various levels -- I have two comments:
     
    1. You can rather easily build such a site with Drupal and Ubercart alone, without using Infusionsoft. Ubercart has facilities to automatically grant "roles" (which give users access permissions) when they purchase a certain product, and to make these roles expire after a certain length of time. The Drupal/Ubercart user account system would be the basis for paid memberships.
    2. If you are committed to Infusionsoft, you want a membership site, and you don't have other reasons for moving to Drupal, there are at least two good alternatives you should investigate: Infusionwp.com which is based on WordPress, and Customerhub.net which is a custom system for building membership sites. These systems were developed by people I know (Bob Keen, Micah Mitchell, Kyle and Nathan Leavitt), who are Infusionsoft API experts, and full-time committed (whereas this is a part-time volunteer effort for me). Using either of these systems would be simpler than using Drupal, and much better supported. Both of them cost something, but considering all the time and money you'll spend on your site, they're cheap.

So why use Drupal? It's the right choice when your goals are ambitious and you have some time to implement them, when you need multiple kinds of functionality on your website -- not just what we've discussed here -- and no pre-existing solution provides what you need. You will find, for example, that Ubercart is far more capable and flexible than the Infusionsoft shopping cart. You will find over 9,000 other contributed modules on Drupal.org, and you'll have the ability to create your own modules. You probably won't EVER find yourself in a situation where something you want to do can't be done in Drupal -- in fact, you'll probably find it's more easily doable in Drupal than in virtually any other system. If you've read this far, I hope this explanation has been helpful.

dfylstra’s picture

I have created an Infusionlink sandbox project at http://drupal.org/sandbox/dfylstra/1173826. But I have not uploaded any code yet, except for a dummy .info file as a test of Git. I'll post another message here when I have uploaded a current version of the module code. This may take days, but not weeks.

BenK’s picture

Great to see some progress on this thread... I'm also very interested in Infusionsoft integration with Drupal.

--Ben

mandolinrick’s picture

Also glad to see some progress on this thread. dfylstra, appreciate you work, comments and suggestions on Drupal integration with Infusionsoft.

Rick

avpaderno’s picture

Project: Drupal.org CVS applications » Drupal.org security advisory coverage applications
Component: new project application » module
tr’s picture

Status: Active » Postponed (maintainer needs more info)
Issue tags: -Module review

Still no code in the sandbox ...

tr’s picture

Status: Postponed (maintainer needs more info) » Closed (won't fix)

One of the requirements of a project application is that you provide code for review. This issue is being closed because there is still no code available, thus no review or approval is possible.

This change is not permanent and the application may be re-opened after you have posted code in your sandbox for review.

iboasis’s picture

Would love to see this be kept alive....considering moving to infusionsoft and would love a module that would help me integrate my user data, email campaigns and store.

Thanks!
Patrick