+ Start a Discussion
MayTheForceBeWithYouMayTheForceBeWithYou 

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'; } } }

 

Best Answer chosen by Admin (Salesforce Developers) 
MayTheForceBeWithYouMayTheForceBeWithYou

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.

 

RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}

 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!

 

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 list<String> jsonData() {
        
        list<String> jsonDataArray = new list<String>();
        
        for (jsonObjectData o : allObjects){
            JSONgenerator gen = JSON.createGenerator(true);
            gen.writeStartObject();
            gen.writeStringField('title',o.name);
            gen.writeStringField('status','publish');
            gen.writeStringField('type','custom');
            gen.writeStringField('content_raw',o.content);
            gen.writeStringField('excerpt_raw',o.excerpt);
            gen.writeStringField('comment_status','closed');
            gen.writeEndObject();
            jsonDataArray.add(gen.getAsString());
        }
        return jsonDataArray;
        
    } 
     
    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';
        
        }               
    
    }
    
}

 

All Answers

MayTheForceBeWithYouMayTheForceBeWithYou

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.

 

RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}

 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!

 

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 list<String> jsonData() {
        
        list<String> jsonDataArray = new list<String>();
        
        for (jsonObjectData o : allObjects){
            JSONgenerator gen = JSON.createGenerator(true);
            gen.writeStartObject();
            gen.writeStringField('title',o.name);
            gen.writeStringField('status','publish');
            gen.writeStringField('type','custom');
            gen.writeStringField('content_raw',o.content);
            gen.writeStringField('excerpt_raw',o.excerpt);
            gen.writeStringField('comment_status','closed');
            gen.writeEndObject();
            jsonDataArray.add(gen.getAsString());
        }
        return jsonDataArray;
        
    } 
     
    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';
        
        }               
    
    }
    
}

 

This was selected as the best answer
Vishal Dube 1Vishal Dube 1
I recently made an integration using this approach. This works as expected. Thanks for the post and solutions
ravinder singh 95ravinder singh 95
I am trying to get Post from wordpress and store into Salesforce Account.

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;}
        
    }
}


 
Chery SparkChery Spark

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.