We are using the Domain Access module to run affiliate sites off of our core site. That is, the affiliates show most of the same content as the core site, but with a different theme (and some Affiliate-specific content exposed as well). Without Drupal for Facebook, users can connect to any of the affiliate sites with one login, which is what we want.

However, with Drupal for Facebook, when using the FB Connect functionality, a user can only log in from one of the sites (the one whose domain is listed in the facebook app settings page at facebook.com). Attempting to use Facebook Connect from an affiliate site results in an infinite login loop error in the browser, because the requesting domain doesn't match what facebook is expecting.

Is there a way we can make this work? If it means setting up one fb app for each domain, that's just fine.

In some cases, the affiliate domain has absolutely no relationship to our own domain (so we can't set up fb to allow from *.example.com), but in other cases, we can do that.

Comments

Dave Cohen’s picture

Go to the "remote settings" on facebook.com. Under the connect tab, specify the "Base Domain". Then facebook's cookies should apply to all of your sites.

friolator’s picture

Hi Dave,

Actually - that's not the issue, and that only solves part of the problem. The issue is that many of the affiliates have completely different domain names. What this means is that we need to have one facebook app for each of those (the ones that share our base domain name could of course use the same facebook app).

This means that there would need to be some kind of mechanism within Drupal for Facebook that allows us to map facebook apps to domains. I'm picturing a list of domains on the left and a pulldown menu next to each one that lets you choose the facebook app that that domain will connect with. It seems like that functionality might already be there to some degree, since you can choose a primary app for facebook connect, and that this might not be a huge addition in terms of coding. no?

-perry

Dave Cohen’s picture

You're welcome to submit a patch if you have a way to make it easier than it currently is.

friolator’s picture

Hi Dave,

I don't really have the programming skills to do this, at least not without so much guidance that it might be easier for someone else to do it. but I can definitely spec out exactly how I think this would best work in a multi-domain environment, if that helps you to code it up faster.

Other than that I can try to muddle through, but I don't really know where to start.

friolator’s picture

Ok, i've been screwing with this all day and I think I have my head wrapped around what I need to do. Can you confirm that I'm on the right track here?

I'm making a contrib module to handle this, called fb_domain

1) set up the admin interface so that you can specify domain/fb app mappings if the domain module is installed. (this part is done, i've got the UI basically working).

2) in fb_connect.module, modify fb_connect_get_app() to:
a) Check for the existence of the domain module, and if there find the current domain
b) find the fb app that's associated with that domain
c) call _fb_connect_set_app(), passing it the $fb_app that we want

I *think* that's basically all I need to do to make it go, right? fb_connect_get_app() seems like the right function to do this in, but if not, let me know. I'm not 100% there yet, but very close. I just want to make sure I'm heading in the right direction with this.

Dave Cohen’s picture

In fb_domain.module, implement fb_domain_fb(). Respond to $op==FB_OP_CURRENT_APP in a way similar to what fb_connect_fb does, but return the domain specific app instead. There's no need to change fb_connect.module for this.

If you can figure out the domain-specific app even earlier during settings.php, its possible to make session support a little more efficient.

Dave Cohen’s picture

But I think the harder more complicated part is managing all the apps. You'll have to fill out forms on facebook and drupal for each one.

friolator’s picture

thanks. very helpful, and a lot simpler than the way i was doing it!

Personally, i have no problem with filling out multiple forms on both FB and drupal. We had pretty much expected that that would be the case for this setup anyway, before we ever even installed Drupal for Facebook. At least in our case, many of the affiliate sites will use the same base domain, so the only time new apps need to be created is when an affiliate has its own domain, and there's not a lot of that with our setup.

friolator’s picture

OK, I think I'm really close on this now. I've got the Facebook Connect admin form set up with two fieldsets. Each one contains a list of domains, and a pulldown menu of fb apps. One is for mapping fb apps to domains, and one is for login buttons. These work, you can set the preference and they all stick. so that's that.

The issue I'm having now is that the login button will only appear on the login form if you set a primary connect application in the Facebook Connect admin settings form. However, that setting seems to be overriding the preferences set from the admin UI. below is my fb_domain module. If anything jumps out as being totally wrong here, please let me know. (one thing I haven't resolved yet is adding a "" option on the pulldown menus. Using your method from elsewhere in the module results in an array key of "0" which can also be a domain ID. Still trying to figure out how I'd deal with that.

/**
 * @file
 * 
 * fb_domain allows you to use Drupal for Facebook with the Domain Access
 * module. 
 *
 * This module modifies the Facebook Connect  admin UI to map facebook apps to
 * domains. If all of your affiliate domains are one one base domain, then
 * you don't need this. But if your affiliates have completely different
 * domain names, you'll need to use this to specify which facebook app 
 * should be used for each domain. Note that you will need to create a new
 * Facebook app for each unique domain you have, and you'll need to set those
 * up through the normal Drupal for Facebook "add application" screen.
 *
 */

define('FB_DOMAIN_MAPPING', 'fb_domain_mapping');
define('FB_DOMAIN_MAPPING_LOGIN', 'fb_domain_mapping_login');

/**
 * Implementation of hook_form_alter().
 * 
 * Add Domain Access settings to the admin form
 * and modify the user login forms to show domain-specific login buttons
 */
function fb_domain_form_alter(&$form, &$form_state, $form_id) {
	if($form_id == "fb_connect_admin_settings"){
		//get a list of all the affiliate domains
		$domains = domain_domains();

		//get a list of all the fb apps
		$fb_apps = fb_admin_get_app_options();

		//put it in a fieldset
		$form['fb_domain_mapping'] = array(
			'#type' => 'fieldset',
			'#title' => t('Domain/FB App Mappings'),
			'#description' => t("For each domain, choose a Facebook App to use for each affiliate domain. If you don't set this, FB connect may not work properly on some domains."),
			'#tree' => TRUE,
		);
		$form['fb_domain_mapping_login'] = array(
			'#type' => 'fieldset',
			'#title' => t('Domain Login Button Mappings'),
			'#description' => t("For each domain, choose the appropriate facebook app to use for the login button on login forms."),
			'#tree' => TRUE,
		);
		$domain_mappings = variable_get(fb_domain_mapping, NULL);
		$domain_mappings_login = variable_get(fb_domain_mapping_login, NULL);

		//generate a select list of fb apps for each affiliate domain
		foreach($domains as $key){
			//dsm($key);
			//this is for the domain/fb app mapping
			$form['fb_domain_mapping'][$key['domain_id']] = array(
			  '#type' => 'select',
			  '#title' => $key['sitename'],
			  '#options' => $fb_apps,
			  '#description' => $key['subdomain'],
			  '#default_value' => $domain_mappings[$key['domain_id']],
			);
			//this is for the login button mappings
			$form['fb_domain_mapping_login'][$key['domain_id']] = array(
			  '#type' => 'select',
			  '#title' => $key['sitename'],
			  '#options' => $fb_apps,
			  '#description' => $key['subdomain'],
			  '#default_value' => $domain_mappings_login[$key['domain_id']],
			);
		}

		//modify the #buttons weight to put them at the end of the form
		$form['buttons']['#weight'] = 10;
	}
	
	
	// Add a Domain-specific login button to login form.
	if (($form_id == 'user_login_block' || $form_id == 'user_login') && !fb_is_fbml_canvas()) {
	  
		//figure out what our current domain is
		$domain = domain_get_domain();
		
		//determine the facebook app to use for the login button	
		$domain_mappings = variable_get(fb_domain_mapping_login, NULL);
	  	
		if ($label = $domain_mappings[$domain['domain_id']]) {
		  $fb_app = fb_get_app($label);
		  
			// Ensure that facebook javascript is in the page closure.
			if ($fb = fb_connect_app_init($fb_app)) {
				fb_connect_require_feature('XFBML', $fb_app);
				fb_connect_init_option('ifUserConnected', "{FB_Connect.on_connected}", $fb_app);
				fb_connect_init_option('ifUserNotConnected', "{FB_Connect.on_not_connected}", $fb_app);
				
				// Add button to the form.
				$form['fb_connect_button'] = array(
				  '#type' => 'markup',
				  '#value' => '<fb:login-button v="2"><fb:intl>Connect with Facebook</fb:intl></fb:login-button>',
				  '#prefix' => '<div class="form-item" id="fb-connect-button">',
				  '#suffix' => '</div>',
				  '#weight' => 4, // LOG IN button weight is 2.
				);
			}		
		}
	}
}


function fb_domain_fb($op, $data, &$return){
  if ($op == FB_OP_CURRENT_APP && !$return) {
	//figure out what our current domain is
	$domain = domain_get_domain();
	
	//determine the facebook app to use for this domain	
	$domain_mappings = variable_get(fb_domain_mapping, NULL);
		
    if ($label = $domain_mappings[$domain['domain_id']]) {
      $return = fb_get_app($label);
    }
  }
}
Dave Cohen’s picture

Component: Miscellaneous » Code
Category: support » feature

This looks pretty good, and concise which is great. I'm not sure whether this module should provide its own admin form, rather than alter the fb_connect admin form. (I don't think this would even be necessary for canvas pages.)

You could also implement a block similar to the fb_connect block, but always showing the domain-specific app.

What's the problem with login form? Even with your code you don't see the button?

Do you have fb_devel enabled? Do you see a lot of "suspicious url" messages?

friolator’s picture

Hi Dave,

Thanks - so what i'm seeing in the login form is this:

1) In the Facebook Connect admin UI, with a primary application set to "none" and a login button set to "none" i get no FB login button in the login form, even with my code.

2) If I set the Login button preference to one of the fb apps, but leave the primary application set to "none" I get the text "connect with facebook" where the login button should go, but it's not a button. just text.

3) if I set the login button to one of the fb apps and then set the primary application to the same one, I get the login button and I'm able to log in with facebook connect. However, if i go to one of the affiliate sites, it's attempting to use the fb app from the other affiliate, and that's causing facebook to display an error that the connect urls don't match up.

I have seen some suspicious URL errors in some cases, but what I am getting a lot of is this:

URL starts with fb_cb/[appname]. This should never happen on connect pages. Did the previous page have a badly formed link?

...where "[appname]" is the name of the currently selected primary facebook app

-perry

Dave Cohen’s picture

In your case, you don't want to select a primary app or add button. Your fb_domain module should handle this instead of fb_connect.

The fact that you call fb_connect_app_init and so on in hook_form_alter should be enough to add facebook's javascript to the footer of your page. (You can view source to confirm this). When you don't see the button, it usually means the javascript is not there, or not executing because of other javascript errors.

I think the fb_cb/[appname] errors will go away with an upgrade to the .dev version. (see http://drupal.org/node/761886)

friolator’s picture

ok, so i realized that I hadn't completely copy/pasted your code from fb_connect.module. I've corrected that so that mine now looks like this:

	// Add button to login form.
	if (($form_id == 'user_login_block' || $form_id == 'user_login') && !fb_is_fbml_canvas()) {
		//figure out what our current domain is
		$domain = domain_get_domain();
		
		//determine the facebook app to use for the login button	
		$domain_mappings = variable_get(fb_domain_mapping_login, NULL);

		if ($app_label = $domain_mappings[$domain['domain_id']]) {
			$fb_app = fb_get_app(array('label' => $app_label));
			
			// Ensure that facebook javascript is in the page closure.
			if ($fb = fb_connect_app_init($fb_app)) {
				fb_connect_require_feature('XFBML', $fb_app);
				fb_connect_init_option('ifUserConnected', "{FB_Connect.on_connected}", $fb_app);
				fb_connect_init_option('ifUserNotConnected', "{FB_Connect.on_not_connected}", $fb_app);
				
				// Add button to the form.
				$form['fb_connect_button'] = array(
					'#type' => 'markup',
					'#value' => '<fb:login-button v="2"><fb:intl>Connect with Facebook</fb:intl></fb:login-button>',
					'#prefix' => '<div class="form-item" id="fb-connect-button">',
					'#suffix' => '</div>',
					'#weight' => 4, // LOG IN button weight is 2.
				);
			}
		dsm($form);
		}
		if ($form_id == 'user_login') {
			// On login, we must leave the user/login page or else get access denied.
			drupal_add_js(array('fb_connect' => array('destination' => url('user'))), 'setting');
		}
	}
	

lo and behold, now I get the "Connect with Facebook" text in the login form, when both the Primary app and the login form are set to "none". So, some progress, I think. Unfortunately, it's still not a clickable button.

I'm stumped. if I dsm() the $form variable (as you see in the code above), I can see that all the right stuff appears to be there.

#fb_connect_button (Array, 5 elements)
    *      #type (String, 6 characters ) markup
    *      #value (String, 81 characters )
             <fb:login-button v="2"><fb:intl>Connect with Facebook</fb:intl></fb:login-button>
    *      #prefix (String, 46 characters ) <div class="form-item" id="fb-connect-button">
    *      #suffix (String, 6 characters ) </div>
    *      #weight (Integer) 4

So i guess it's a javascript thing. Is it possible that by setting the login button to "none" in the Facebook Connect admin settings page, I'm no longer loading some critical javascript here? I can't seem to find anything, but that does seem plausible.

friolator’s picture

By the way, it does look like the following javascript files are loaded on the user/login page:

http://static.ak.connect.facebook.com/connect.php/en_US/js/Api/CanvasUti...

http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php

and then this inline script:

  $(document).ready(function() {
    FB_RequireFeatures(["XFBML"], function () {

      //FB.FBDebug.logLevel = 4;
      //FB.FBDebug.isEnabled = true;

      FB.XFBML.Host.autoParseDomTree = false;

      FB.init("333c2bfe9f3c9c1168c876781aee0a57", "http://staging.MYDOMAINNAME.com/fb_cb/MYAPPNAME/fb_connect/receiver", {"ifUserConnected":FB_Connect.on_connected,"ifUserNotConnected":FB_Connect.on_not_connected});
    });
  });

  FB.ensureInit(function()
    {
      FB_Connect.init();
      
    });
Dave Cohen’s picture

As long as you have that inline and so on, the button should be a button and not just text.

What browser are you using? For IE you need to change your page template. http://www.drupalforfacebook.org/node/1106

friolator’s picture

I'm seeing this is on both firefox 3.5.9 (mac) ad Safari 3.2.3 (mac).

It happens both on user/login and in the lightbox 2 version of our login form. When I set a primary app in the Facebook Connect UI (just to test), the button renders on both browsers in both situations. Turning off the primary app gives me the unrendered button. weird.

(by the way, i'm getting facebook session errors when i click on drupalforfacebook.org): white screen with "Facebook API exception Session key invalid or no longer valid" followed by about 30 lines of debug code.

friolator’s picture

Version: 6.x-2.0-beta10 » 6.x-3.x-dev

just a quick update - I installed the latest dev version, and I'm still seeing this issue of the non-rendered button.

Dave - would it help you to look at the actual development site? If so, let me know how I can contact you privately to get you the URL.

friolator’s picture

Hi Dave,

Just wondering if you have any other ideas for what we might need to do to get this working. I'm out of ideas, but I feel like we're almost there with this.

Thanks!

Dave Cohen’s picture

I don't know off hand. I really don't have even an extra moment between now and the end of DrupalCon (end of April, really). If you'll be at drupalcon, we can talk in person....

friolator’s picture

won't be at drupalcon. I'll try to slog through this as best I can. if I can get a clean setup of drupal on another dev server going maybe I can isolate the issue. If anything springs to mind in the mean time, let me know!

We're trying to get this implemented in the next couple of weeks so the more time we have to test it before we push our next update to the live site, the better.

friolator’s picture

Upgraded from the dev version from last week to beta 11 this morning. Progress - we're now seeing the Connect with Facebook button on user/login. However, we also offer a Lightbox2 version of the login form. I did see the facebook connect button there once, but on subsequent tries (without changing any settings), it's not there. It seems to be there consistently for the form at user/login

So, something changed, but I really don't know what, to make this work for us. huh.

Still trying to debug the multiple domain stuff though, but at least I can test it now!

Exploratus’s picture

Keep us informed of your progress!!! Thanks!

Juan C’s picture

+1

friolator’s picture

We've put this on hold for now, so if someone wants to take a stab at it, please do. Unfortunately, we need to get other stuff done by the middle of May, and with the impending changes to FBConnect from Facebook, it just made sense for us to put this off until that stuff is implemented.

Exploratus’s picture

So aside from this attempt, do Drupal for Facebook and Domain Access work together at all? Thinking of giving this combo a try, just want to know if it is even worth it before a dive in. Any advice or ideas out there?

Thanks!

skizzo’s picture

Subscribing. I am seeing the same infinite loop described in original post, even if
my sites have a common base name e.g.: one.example.com, two.example.com etc...

@ friolator: wouldn't domain_settings (from DA suite) solve at least part of the problem?
"Domain Settings allows forms for other modules to save different settings for each of your affiliate sites...".

webwriter’s picture

subscribe

sorensong’s picture

+1

alejo_m_c’s picture

Does it still on hold?

MickC’s picture

+1

Dejvid’s picture

Any progress? Thanks!

scothiam’s picture

subscribing... thanks again for all of Daves efforts!!!

miro_dietiker’s picture

Note that recently facebook added support for multiple domains.
https://developers.facebook.com/blog/post/570/

stuchl4n3k’s picture

+1 on this

Dave Cohen’s picture

While facebook has documented that "feature", I've never been able to get it to work. Has anyone?

aomw’s picture

+1
Any progress? Is there anyone working on this?

Dave Cohen’s picture

Category: feature » support
Status: Active » Fixed

From facebook:

Each domain specified in the App Domain field must be derived from your App’s URL (Website and/or Mobile Web URL). That is, each domain in this field must share the same 'base' part of the domain name - 'myapp' in the above example.

In other words, you'll need a different app for each domain, unless your domains all share a common base. So foo.example.com and bar.example.com could share a single application, but foo.com and bar.com could not. It's a restriction imposed by facebook and not these modules.

Also, its a setting that can be changed on developers.facebook.com, not automatically by the module.

aomw’s picture

Thanks Dave for the quick reply.
Actually I think I may have misunderstood what you have been working on in this thread.

I have one instance of Drupal which handles 2 different domains (with Domain Access module), so lets say it handles both foo.com and bar.com. Both are social websites.
I've been using DFF for a while on foo.com for FB Connect and for pushing notifications. The thing is now I need FB Connect on bar.com but since its branding is completely different, I cannot reuse the same Facebook app I've been using in DFF for foo.com.

So in fact I need FB connect to use a different FB app depending on the domain.

Is there a way to do something like this with the current version of DFF?
If not, do you think such development could be considered (should I open a new ticket for that?)?

Dave Cohen’s picture

Since the beginning, modules/fb has supported multiple facebook apps. Configure as many as you need at q=admin/build/fb/fb_app_create.

The trick is telling the modules which app to use on which pages. You could implement hook_fb() to control this with whatever logic you need. But in your case it's just a matter of domains so an easier way would be in your settings.php files. Add something like this to each one:

$GLOBALS['conf']['fb_id'] = 12345; // Your app ID goes here.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.