[SalesForce] New page – Parent lookup pre-populated

I'm attempting to create the New button functionality on a visualforce page that will be hosted as a section of
detailed page layout. This vf page will surface child records of a parent detail page record . Think of
this as a manually constructed 'related list' ( which also includes a New button for adding records )

My requirement: Pressing the New button should take one to the standard salesforce New page for the child record with the
parent record lookup pre-populated.

I suspect the answer can be found in the construction of an appropriate url but this is where I hit a slight snag.
The vf page will be part of a managed package so I will have no obvious way (to my mind at least) of
grabbing the custom field Id of the parent lookup field. (ie hard coded lkids are not an option)

All ideas are very much appreciated

Best Answer

A Tooling API Solution

I've been able to try out a hunch I've had since I noticed CustomField support in the Tooling API and have worked up a means to dynamically query the Custom Field Id's via the supported Salesforce Tooling API. My fresh from the press blog entry here goes into more details, though here is a code sample taken from the accompanying GitHub repo.

// Constructs the Tooling API wrapper (default constructor uses user session Id)
ToolingAPI toolingAPI = new ToolingAPI();

// Query CustomObject object by DeveloperName (note no __c suffix required)
List<ToolingAPI.CustomObject> customObjects =
     toolingAPI.queryCustomObject('DeveloperName = \'Test\'').records;

// Query CustomField object by TableEnumOrId (use CustomObject Id not name for Custom Objects)
ToolingAPI.CustomObject customObject = customObjects[0];
Id customObjectId = customObject.Id;
List<ToolingAPI.CustomField> customFields =
     toolingAPI.queryCustomField('TableEnumOrId = \'' + customObjectId + '\'').records;

// Dump field names (reapply the __c suffix) and their Id's
System.debug(customObject.DeveloperName + '__c : ' + customObject.Id);
for(ToolingAPI.CustomField customField : customFields)
     System.debug(
          customObject.DeveloperName + '__c.' +
          customField.DeveloperName + '__c : ' +
          customField.Id);

This results in ....

00:27:38.845 (845882069)|USER_DEBUG|[45]|DEBUG|Test__c : 01IG00000021cXoMAI

00:27:38.846 (846249350)|USER_DEBUG|[47]|DEBUG|Test__c.A_Number__c : 00NG0000009Y0I9MAK

00:27:38.846 (846305290)|USER_DEBUG|[47]|DEBUG|Test_c.Colours_c : 00NG0000009prwyMAA

00:27:38.846 (846328856)|USER_DEBUG|[47]|DEBUG|Test_c.Date_c : 00NG0000009BrnxMAC

00:27:38.846 (846513094)|USER_DEBUG|[47]|DEBUG|Test_c.Message_c : 00NG0000009Y0IOMA0

00:27:38.846 (846535746)|USER_DEBUG|[47]|DEBUG|Test_c.MultiPick_c : 00NG000000AcULrMAN

00:27:38.846 (846558753)|USER_DEBUG|[47]|DEBUG|Test_c.MyCheckbox_c : 00NG0000009Y5C8MAK

00:27:38.846 (846741056)|USER_DEBUG|[47]|DEBUG|Test_c.RichText_c : 00NG0000009XaRJMA0

00:27:38.846 (846816183)|USER_DEBUG|[47]|DEBUG|Test_c.Text_c : 00NG0000009prxwMAA

Summary. There CustomField object has a little amount of queryable fields this way, basically DeveloperName, TableEnumOrId (custom object Id or standard object name) and NamespacePrefix. These should allow you to dynamically query for most use cases. Keep in mind the solution uses a callout from Apex to the Tooling API (REST version), so you will need to have a Remote Site setting for the Tooling API end point added to the org.