You need to sign in to do that
Don't have an account?
MayTheForceBeWithYou
Connecting Salesforce to Wordpress via JSON REST API
I am using an Apex trigger and asynchronous method to perform a callout to the JSON REST API for Wordpress. I continue to receive 500 Internal Server Error responses in my debug log when I edit a Salesforce record, but if I copy/paste the corresponding JSON into the Postman plug-in for Chrome the post is created as expected. Any help is appreciated, thanks!
trigger insertPost on Custom_Object__c (after insert, after update) { String theIds = ''; for (Custom_Object__c c : Trigger.new) { if (theIds == '') theIds = c.Id; else theIds += '|' + c.Id; } //Make asynchronous web service callout to insert post if (theIds != '') WebServiceCallout.sendPost(theIds); }
public class WebServiceCallout { @future (callout=true) public static void sendPost(String theIds) { HttpRequest req = new HttpRequest(); HttpResponse res = new HttpResponse(); Http http = new Http(); if(Test.isRunningTest()){ Website_Settings__c wpSettings = new Website_Settings__c(Wordpress_URL__c = 'https://testing.com/', Wordpress_Username__c = 'Test', Wordpress_Password__c = 'Test'); insert wpSettings; } //Set Headers from Custom Settings & Visualforce Website_Settings__c wpSettings = Website_Settings__c.getInstance(); if (wpSettings.Wordpress_URL__c!=null && wpSettings.Wordpress_Username__c!=null && wpSettings.Wordpress_Password__c!=null){ //Set Endpoint String endpoint = wpSettings.Wordpress_URL__c; if (endpoint.endsWith('/')) req.setEndpoint(endpoint+'wp-json.php/posts/'); else req.setEndpoint(endpoint+'/wp-json.php/posts/'); //Set Method req.setMethod('POST'); //Specify the required user name and password to access the endpoint String username = wpSettings.Wordpress_Username__c; String password = wpSettings.Wordpress_Password__c; Blob headerValue = Blob.valueOf(username + ':' + password); String authorizationHeader = 'Basic ' + EncodingUtil.base64Encode(headerValue); req.setHeader('Authorization', authorizationHeader); //Specify Content-Type req.setHeader('Content-Type', 'application/json'); //Specify Cache-Control req.setHeader('Cache-Control', 'no-cache'); //Set Body objectToJSON.theId = theIds; objectToJSON jsonClass = new objectToJSON(); req.setBody(jsonClass.jsonData()); try { System.debug(req.getHeader('Authorization')); System.debug(req.getHeader('Content-Type')); System.debug(req.getBody()); if (!Test.isRunningTest()) res = http.send(req); } catch(System.CalloutException e) { System.debug('Callout error: '+ e); System.debug(res.toString()); System.debug(req.getBody()); } } } }
public with sharing class objectToJSON { //Global variables public static String theId; public list<String> theIds; public list<jsonObjectData> allObjects{get;set;} public objectToJSON() { //***This method queries the database for information and converts it to JSON*** //If URL parameters are set then query the database if (ApexPages.currentPage()!=null) if (ApexPages.currentPage().getParameters().get('theId')!=null && ApexPages.currentPage().getParameters().get('theId')!='') theId = String.escapeSingleQuotes(ApexPages.currentPage().getParameters().get('theId')); if (theId.contains('|')) theIds = theId.split('\\|',-1); else{ theIds = new list<String>(); theIds.add(theId); } allObjects = new list<jsonObjectData>(); list<Custom_Object__c> objects = [SELECT Id, Name, Description__c, A__c, B__c, C__c FROM Custom_Object__c WHERE Id IN :theIds LIMIT 10000]; for (Custom_Object__c o : objects){ allObjects.add(new jsonObjectData(o)); } } public String jsonData() { String jsonData = '['; Integer x=0; while (allObjects.size()>x) { if (x==0) jsonData += '{'; else jsonData += ',{'; jsonObjectData o = allObjects[x]; jsonData += '\"title\":\"'+o.name.replace('\"','\\"')+'\",'; jsonData += '\"status\":\"publish\",'; jsonData += '\"type\":\"custom\",'; jsonData += '\"content_raw\":\"'+o.content.replace('\"','\\"').replace('\n','')+'\",'; jsonData += '\"excerpt_raw\":\"'+o.excerpt.replace('\"','\\"').replace('\n','')+'\",'; jsonData += '\"comment_status\":\"closed\"'; jsonData += '}'; x++; } jsonData += ']'; if (x==1){
//Remove array formatting for individual post jsonData = jsonData.substring(1); jsonData = jsonData.substring(0,jsonData.length()-1); } return jsonData; } public class jsonObjectData { //*****Wrapper Class***** //Global variables for wrapper class public String name{get;set;} public String content{get;set;} public String excerpt{get;set;} public jsonObjectData(Custom_Object__c o) { //***Constructor method to create a JSON object*** //Define content variables String a = ''; String b = ''; String c = ''; //Set content variables if (o.A__c!=null) a = String.valueOf(o.A__c); if (o.B__c!=null) b = String.valueOf(o.B__c); if (o.C__c!=null) c = String.valueOf(o.C__c); //Define & Set description variable String description = ''; if (o.Description__c!=null) description = String.valueOf(o.Description__c); //Set name name = o.Name; //Set content content = '<div class="custom"></div>\n<div class="row clearfix ">\n<div class="col col_1_2 ">\n<div class="inner">\n<div class="styled_table table_blue">\n<table>\n<thead>\n<tr>\n<th>Custom</th>\n<th> </th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>A</td>\n<td>'+a+'</td>\n</tr>\n<tr>\n<td>B</td>\n<td>'+b+'</td>\n</tr>\n<tr>\n<td>C</td>\n<td>'+c+'</td>\n</tr>\n</tbody>\n</table>\n</div>\n</div>\n</div>\n</div>\n'; //Set excerpt excerpt = '<p>'+description+'</p>\n'; } } }
Thought I'd share my results for any future developers that run across this issue. I used Wireshark to read the exact HTTP callout my Postman plug-in was making and noticed that I had a cookie (wp_logged_in...) stored in my browser that was allowing the post to be created. As a test I hard-coded this cookie into my callout from Salesforce and then my code worked as expected. Of course you can't just hard-code an authentication cookie into your Apex code indefinitely, but at least this showed the 500 error was actually resulting from an authentication issue.
After digging a little deeper I discovered that GoDaddy (my WP domain host) has CGI-mode PHP enabled by default, which breaks Basic HTTP Authentication as the PHP_AUTH_USER and PHP_AUTH_PW are lost. Adding the following rule to my .htaccess file allowed these global keys to be preserved, thereby fixing my authentication problem.
Note: I would recommend placing this above any rules utilizing the 'L' tag to ensure it fires
Although my issue ended up being a result of my PHP settings on GoDaddy rather than my Apex code I thought I'd also share an updated version of my objectToJSON Apex class, as I was able to clean it up a bit with the JSONgenerator class. You'll also notice it now returns a string array back to my WebServiceCallout class. Happy coding!
All Answers
Thought I'd share my results for any future developers that run across this issue. I used Wireshark to read the exact HTTP callout my Postman plug-in was making and noticed that I had a cookie (wp_logged_in...) stored in my browser that was allowing the post to be created. As a test I hard-coded this cookie into my callout from Salesforce and then my code worked as expected. Of course you can't just hard-code an authentication cookie into your Apex code indefinitely, but at least this showed the 500 error was actually resulting from an authentication issue.
After digging a little deeper I discovered that GoDaddy (my WP domain host) has CGI-mode PHP enabled by default, which breaks Basic HTTP Authentication as the PHP_AUTH_USER and PHP_AUTH_PW are lost. Adding the following rule to my .htaccess file allowed these global keys to be preserved, thereby fixing my authentication problem.
Note: I would recommend placing this above any rules utilizing the 'L' tag to ensure it fires
Although my issue ended up being a result of my PHP settings on GoDaddy rather than my Apex code I thought I'd also share an updated version of my objectToJSON Apex class, as I was able to clean it up a bit with the JSONgenerator class. You'll also notice it now returns a string array back to my WebServiceCallout class. Happy coding!
Note : CALLOUT_RESPONSE|[29]|System.HttpResponse[Status=Forbidden, StatusCode=403]
I am getting 403 status code.
public with sharing class WordpressIntegration {
// Created a remote site setting for this Rest API
//public List <JSONWrapper> listWrapper {get;set;}
public List <JSONWrapperWordpess> listWrapper {get;set;}
List<Account> lstAcc = new List<Account>();
public String accessToken = 'YWRtaW46QW1hemluZ0AxMjM=';
public WordpressIntegration() {
listWrapper = new List < JSONWrapperWordpess >();
}
public void fetchDataFromExternalSystem(){
Http h = new Http();
HttpRequest req = new HttpRequest();
String username = 'admin';
String password = 'Amazing@123';
Blob headerValue = Blob.valueOf(username + ':' + password);
String authorizationHeader = 'Basic ' + EncodingUtil.base64Encode(headerValue);
req.setHeader('Authorization', authorizationHeader);
//req.setEndPoint('https://api.github.com/users/hadley/orgs');
req.setEndPoint('http://localhost/project1/wp-json/wp/v2/posts?_fields=author,id,excerpt,title,link');
req.setMethod('GET');
HTTPResponse res = h.send(req);
System.debug('res.getStatusCode() ###'+res.getStatusCode());
//JSONParser parser = JSON.createParser(res.getBody());
if (res.getStatusCode() == 200) {
listWrapper = (List<JSONWrapperWordpess>)System.JSON.deSerialize(res.getBody(), List<JSONWrapperWordpess>.class);
/*
If the response contains only one value instead list, then you can use the below code
JSONWrapper obj = (JSONWrapper) JSON.deSerialize(res.getBody(), JSONWrapper.class);
listWrapper.add(obj);
*/
System.debug('listWrapper @@'+ listWrapper);
for(JSONWrapperWordpess a : listWrapper){
Account aa = new Account();
aa.Name = a.title;
aa.DOB__c = date.newInstance(2012,05,22);
aa.Site = a.link;
aa.AccountNumber = a.id;
lstAcc.add(aa);
}
insert lstAcc;
}
}
public class JSONWrapperWordpess {
public String title {get;set;}
public String id {get;set;}
public String link {get;set;}
}
}
miniOrange helped me in achieving this for my client sites which are developed on WordPress.
Their Object Sync for Salesforce plugin allowed our users to synchronize our WordPress objects with Salesforce. It has kept our WordPress objects in sync with Salesforce for marketing automation. When an object (user, page, posts, blog ,etc) is created/updated/deleted in WordPress, it will be created/updated/deleted in the Salesforce record also.
How their module works :
The module utilizes Salesforce REST API to get to information without utilizing the Salesforce UI's. With API access, the module can perform tasks, for example, make, control-, and search information in Salesforce by sending HTTP solicitations to endpoints in Salesforce. In this way, the module adjusts client metadata with Salesforce objects utilizing REST API.
How does Bidirectional Sync function
Salesforce articles will be created/ updated/ deleted when the information in WordPress is saved as well as vice versa. The Salesforce to WordPress Object sync can be synced at a particular time span. The module recovers the information from the Salesforce object and overwrites the WordPress object in view of the field planning. Ideally, this can be accomplished involving triggers in Salesforce, it sends a solicitation to the module callback URI with a payload of the progressions in objects, which will be refreshed in WordPress objects.
For more information, you can check out their plugin in the WordPress marketplace and their resources.