function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
paul.mcgurnpaul.mcgurn 

Chatter Answers vs. PKB

I've been struggling to deliver a (good) user experience on an existing Force.com Sites implementation where we want to add in a public knowledge base.  So far, I've hit roadblock after roadblock in being able to do this without doubling the administrative burden in managed FDC administration.  Here's where I'm at, I'm hoping I'm just missing something trivial and not multiple design flaws:

PKB
  • PKB doesn't seem to be supported any more.  It's an unmanaged package, which means that even if there we updates, they are extremely hard to integrate into a custom-styled FDC website.
  • PKB will not render articles if it is configured to use a Force.com site with a URL Rewriter.  It uses an undocumented page renderer/API to render the articles.  This means that you would have to put PKB in a separate FDC Site if your main site requires the use of a URL Rewriter (and many do, for SEO).

Chatter Answers in a public Force.com site
  • The administrative setup for this was atrocious.  Back and forth over dozens of Setup Area UI screens, some of which had to be visited/edited multiple times just by following the implementation guide from top to bottom.  And that's after already having set up all the the Knowledge dependencies while implementing PKB in the same SF Org.
  • When enabling a Chatter Answers zone to "bind" to a Force.com site, it actually creates a NEW Force.com site loosely tied to the original one.  The issue with this approach, is that it requires a different cookie domain (which breaks transitioning logged in users in and out of the Chatter Answers pages).  It also requires the admin to set up identical settings for the main FDC Site AND this newly created site, including the FDC Site Settings, Public Access Settings, Login Access Settings, etc.  Nightmare.
I'm hoping I'm missing something here, but after literally days of configuring both of these, each, all I can see is a complete disregard for a user experience allowing a developer to deliver these solutions alongside an existing Sites implementation in a way that will be acceptable.
 
PratikPratik (Salesforce Developers) 
Hi Paul,

PKB is supported by Salesforce.
(https://appexchange.salesforce.com/listingDetail?listingId=a0N300000059QxXEAU)
As it's unmanaged package, you can do customizations as per your requirements.

Chatter Answer setup:
https://help.salesforce.com/HTViewHelpDoc?id=questions_portal_setup_sites.htm&language=en_US


Thanks,
Pratik
paul.mcgurnpaul.mcgurn
I've already read all documentation on both, neither cover my concerns listed here.
Chris GaryChris Gary
Paul,

I feel your pain, after deploying multiple communities that have implemented both the PKB, and Chatter Answers, it is a difficult toss up.  Short answer, roll your own.  if you have a Force.com site being run by VF pages,  go ahead and create the necessary pages to display your article and category lists using the <knowledge: VF elements available. If you have concerns on how to display a proper navigation based on the Data Categories, I acutally had to create a JSON output representing the Categories in my Page Controller, and then on the front end, I used a Javascript library (pick one  - javascript, angularJS  - whatever) to render the navigation dynamically from the JSON String exposed as a public variable.  Below is a sample of code I used to do that.... took me a minute to figure it out....
/**
	 * This method is designed to get a hierarchal represnetation of the Data Categories assigned to 
	 * knowledge articles. 
	 *
	 * @param categoryGroupName - the Category Group to Get the Data FROM
	 * @param categoryName - the Name to consider as the Top level Category. Will not be included in output.
	 * @return String - the resulting Data Category Structure in JSON Format.
	 **/
	public static String GetDataCatetgoryInformation(String categoryGroupName, String categoryName)
	{
		String jsonString;
		Schema.DataCategoryGroupSobjectTypePair startingPair = new Schema.DataCategoryGroupSobjectTypePair();
		startingPair.setDataCategoryGroupName(categoryGroupName);
		startingPair.setSObject('KnowledgeArticleVersion');
		List<Schema.DescribeDataCategoryGroupStructureResult>results = Schema.describeDataCategoryGroupStructures(new Schema.DataCategoryGroupSobjectTypePair[]{startingPair},false);
		System.debug(LoggingLevel.INFO,'\n*****\n Group Structure Result: ' + results[0] + '\n*****\n\n');
		List<Schema.DataCategory> allList = results[0].getTopCategories();
		Schema.DataCategory allCat = allList[0];
		System.debug(LoggingLevel.INFO,'\n*****\nChild Categories of all: ' + allCat.getChildCategories() + '\n*****\n');
		List<Schema.DataCategory> ts360CatList = allList[0].getChildCategories();
		System.debug(LoggingLevel.INFO,'\n*****\n ts360CatList: ' + ts360CatList + '\n*****\n');
		Schema.DataCategory startingCategory;
		for(Schema.DataCategory category:ts360CatList){
			if(category.getLabel() == categoryName){
				startingCategory = category;
				break;
			}
		}
		if(startingCategory != null && startingCategory.getChildCategories().size() > 0){
			JSONGenerator jsonCategoryListing = TS360ComKnowledgeExtension.JSONifyCategoryNames(JSON.createGenerator(false), startingCategory.getChildCategories()) ;
			jsonCategoryListing.close();
			jsonString = jsonCategoryListing.getAsString();
			System.debug(LoggingLevel.INFO,'\n*****\n JSON Information: ' + jsonString + '\n*****\n');
		} else {

			System.debug(LoggingLevel.INFO,'\n\n*****\n Starting Categories might be empty:\n*****\n');
		}

		return jsonString;
	}



private static JSONGenerator JSONifyCategoryNames(JSONGenerator gen, List<Schema.DataCategory> dcList){
		try{
			gen.writeStartArray();
			for(Schema.DataCategory dc:dcList){
				gen.writeStartObject();

				gen.writeStringField('label',dc.getLabel());
				gen.writeStringField('name',dc.getName());
				if(dc.getChildCategories().size() > 0){
					gen.writeFieldName('children');
					gen = TS360ComKnowledgeExtension.JSONifyCategoryNames(gen,dc.getChildCategories());
				}

				gen.writeEndObject();
			}
			gen.writeEndArray();
		}catch(System.Exception ex){
			System.debug(LoggingLevel.INFO,'\n******\nError: ' + ex.getMessage() + '\n*****\n\n');
			throw ex;
		}
		return gen;
	}

As far as the chatter Answers portion of the Communities, I simply used the <chatteranswers: elements which work pretty well and stay self contained.  My only warning on using these elements is that sometimes your page formatting can screw up these displays, so be careful about your CSS structure. Jsut remember that in using these elements, the documentation says pass in the communityId, but you must pass in the ZONE ID of the Zone assigned to the Community.

Why use both?  Because Answers has the unique benefit of providing users the capability to ask a question to the community, if they can't find it in the Knowledge or if it already hasn't been asked.  Knowledge however, can be much more structured that Answers.  My clients wanted the best of both worlds.

You final option would be to utilize the Site.com 'Community Templates' offered in the new Spring '15 implementations of Communities.  They are very nice - and offer great examples of a SPA App (Single Page Application) - but they ARE NOT MODIFIABLE - that sucks... Great examples though of what cold be put together with some ingenuity.

Hope this helps.  You question is kind of subjective, but if I was able to answer your questions, please mark this reply as 'Solved'.

Thanks!
paul.mcgurnpaul.mcgurn
Thanks Chris. It kind of confirms my dread that the stock solutions are no good on the customization front. How are you rendering articles for PKB? The stock method breaks with a URL rewriter. Regarding Chatter Answers and style, I’m hoping they play nice with Bootstrap. I’m moving this customer’s content to that framework in prep to start moving the site to a responsive design. (Side note, that’s WAY easier to do at the start than it is after the fact…)
Chris GaryChris Gary
For those customers that did not care about the friendly URLs - simply pointing to a VF page with the knowledgeArticleId and the Article Type did the trick.  For those who did care about the Friendly url, we prefaced the friendly URL link on the Article with something like '/articletype/<article_type>/article/<url_vield_value_on_article>' and in the custom URL Rewriter class, parse the path to look for the special word (in this case 'article'), then used the remainder of the path to look for the Article by the URL provided. The article type will be used to query the right object as well as to display the right visualforce page  (because, yep, in many cases, we had a separate VF page for each Article Type).
paul.mcgurnpaul.mcgurn
Good stuff. I’ll take this to heart as I look to deliver this solution for the customer. Thanks much!