Tag Archives: Visualforce Page

Google reCAPTCHA on Visualforce Page

Step 1: Configure the Google reCAPTCHA and get the Site Key & Secret Key

  • Login to Google reCAPTCHA
  • Register a new site
  • Add Label e.g. Salesforce.com
  • Select reCAPTCHA type “reCAPTCHA v2”
  • Select “I’m not a robot” Checkbox option.
  • Add a domain e.g. yourorgurl.com
  • Accept the reCAPTCHA Terms of Service
  • Submit and get the Site Key & Secret Key

Step 2: Add Google as a Remote Site in Salesforce

Step 3: Create apex controller

/*
@Author : Biswajeet Samal
@CreatedDate : 30th JUL 2020
@Description : Google ReCAPTCHA Controller
*/
public class GoogleReCAPTCHAController {
    
    public Boolean verified { get; private set; }
    public String response  { 
        get {
            return ApexPages.currentPage().getParameters().get('g-recaptcha-response');
        }
    }
    public String firstName{get;set;}
    public String lastName{get;set;}
    public String publicKey {get;set;}
    
    private String remoteHost{
        get {
            String ret = '127.0.0.1';
            //Also could use x-original-remote-host
            Map<String, String> hdrs = ApexPages.currentPage().getHeaders();
            if (hdrs.get('x-original-remote-addr')!= null)
                ret = hdrs.get('x-original-remote-addr');
            else if (hdrs.get('X-Salesforce-SIP')!= null)
                ret = hdrs.get('X-Salesforce-SIP');
            return ret;
        }
    }
    
    //Google Secret Key
    private static String secretKey = 'ADD YOUR GOOGLE RECAPTCHA SECRET KEY';
    private static String baseUrl = 'https://www.google.com/recaptcha/api/siteverify';
    
    //Constructor
    public GoogleReCAPTCHAController(){
        this.publicKey = 'ADD YOUR GOOGLE RECAPATCHA SITE KEY OR PUBLIC KEY';//Google Site Key or Public Key
        this.verified = false;
    }
    
    public PageReference submit(){
        if (response == null ){
            //Google recaptcha empty response
            return null;
        }
        HttpResponse res = getGoogleReCAPTCHAResponse(baseUrl,'secret=' + secretKey + '&remoteip=' + remoteHost + '&response=' + response);
        if (res != null ) {
            JSONParser parser = JSON.createParser(res.getBody());
            while (parser.nextToken() != null) {
                if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'success')) {
                    parser.nextToken();
                    this.verified = parser.getBooleanValue();
                    break;
                }
            }            
        }   
        if(this.verified){
            //Add your logic
            return null;
        }
        else{
            //Stay on page to re-try reCAPTCHA
            return null;
        }
    }
    
    //Get Google reCAPTCHA Service Response 
    private static HttpResponse getGoogleReCAPTCHAResponse(string requestURL, string body){
        HttpResponse response = null;
        HttpRequest req = new HttpRequest();
        req.setEndpoint(requestURL);
        req.setMethod('POST');
        req.setBody (body);
        try{
            Http http = new Http();
            response = http.send(req);
            System.debug('ReCAPTCHA Response-' + response);
            System.debug('ReCAPTCHA Body-' + response.getBody());
        }
        catch(System.Exception ex){
            System.debug('ERROR Message-' + ex.getMessage());
        }
        return response;
    }
}

Step 4: Create VF Page

<apex:page controller="GoogleReCAPTCHAController" sidebar="false" showHeader="false" cache="false" id="pg">
    <script type='text/javascript' src='https://www.google.com/recaptcha/api.js'/>
    <script type='text/javascript'>
        function recaptchaCallback() {
        var btnVerify = document.getElementById("pg:fm:pb:pbb:btnVerify");
        if (btnVerify.classList.contains("hideButton") ) {
            btnVerify.classList.remove("hideButton");
        }
    }
    </script> 
    
    <style type="text/CSS">
        .hideButton{
        display:none !important;
        }
    </style>
    <apex:form id="fm">
        <apex:pageBlock title="Google Captcha Example" id="pb">
            <apex:pageBlockSection columns="1" id="pbs"> 
                <apex:pageBlockSectionItem >
                    <apex:outputLabel for="fnField" value="First Name"/>
                    <apex:inputText value="{!firstName}" id="fnField"/>
                </apex:pageBlockSectionItem>
                <apex:pageBlockSectionItem >
                    <apex:outputLabel for="lnField" value="Last Name"/>
                    <apex:inputText value="{!lastName}" id="lnField"/>
                </apex:pageBlockSectionItem>
                <apex:pageBlockSectionItem >
                    <div data-type="image" class="g-recaptcha" data-sitekey="{!publicKey}" data-callback="recaptchaCallback"></div>
                </apex:pageBlockSectionItem>
                <apex:pageBlockSectionItem rendered="{!verified}">
                    <p>Google reCAPTCHA verified successfully.</p>
                </apex:pageBlockSectionItem>
            </apex:pageBlockSection>
            <apex:pageBlockButtons id="pbb" location="bottom">
                <apex:commandButton action="{!submit}" styleClass="hideButton" value="Verify" id="btnVerify"/>
            </apex:pageBlockButtons>
        </apex:pageBlock>
    </apex:form>
</apex:page>

Helptext Is Not Working In Lighting Out

Due to some issue in Salesforce lightning css, helpText is not displaying properly in lightning out. Using following styles in your visualforce page, you can display the helptext properly.

CSS:

<style>
        .slds-popover {
        position: relative;
        border-radius: .25rem;
        width: 20rem;
        min-height: 2rem;
        z-index: 6000;
        background-color: #fff;
        display: inline-block;
        box-shadow: 0 2px 3px 0 rgba(0, 0, 0, .16);
        border: 1px solid #d9dbdd;
        font-family: 'Salesforce Sans',Arial,sans-serif;
        }
        
        .slds-popover__body,
        .slds-popover__footer,
        .slds-popover__header {
        position: relative;
        padding: .5rem .75rem;
        word-wrap: break-word;
        }
        
        .slds-popover--tooltip .slds-popover__body,
        .slds-popover_tooltip .slds-popover__body {
        font-size: .75rem;
        color: #fff
        }
        
        .slds-popover--tooltip,
        .slds-popover_tooltip {
        width: auto;
        max-width: 20rem;
        background: #16325c;
        border: 0;
        }
        
        .slds-nubbin--bottom-left:before,
        .slds-nubbin_bottom-left-corner:before,
        .slds-nubbin_bottom-left:before {
        width: 1rem;
        height: 1rem;
        position: absolute;
        transform: rotate(45deg);
        content: '';
        background-color: inherit;
        bottom: -.5rem;
        margin-left: -.5rem;
        }
        
        .slds-nubbin--bottom-left:after,
        .slds-nubbin--bottom-left:before,
        .slds-nubbin_bottom-left-corner:after,
        .slds-nubbin_bottom-left-corner:before,
        .slds-nubbin_bottom-left:after,
        .slds-nubbin_bottom-left:before {
        left: 1.5rem;
        top: 100%;
        margin-top: -.5rem;
        }
    </style>

Redirect To Standard New Note & New Attachment Pages Using Apex

Redirect to New Attachment:

public PageReference redirectToNewAttachment() {
   PageReference pgRef = new pageReference('/p/attach/NoteAttach?pid=' + String.valueof(acc.Id).subString(0, 15) + '&retURL=' + acc.Id);
   pgRef.setRedirect(true);
   return pgRef;
}

Redirect to New Note:

public PageReference redirectToNewNote() {
   PageReference pgRef = new pageReference('/002/e?parent_id=' + String.valueof(acc.Id).subString(0, 15) + '&retURL=' + acc.Id);
   pgRef.setRedirect(true);
   return pgRef;
}

Inline Visualforce Page Needs To Redirect

Apex Class:

public class AccountExtensionController {

    public String redirectUrl {get; set;}
    public Boolean isRedirect {get; set;}
    private Account acc {get; set;}
    
    public AccountExtensionController(ApexPages.StandardController sc) {
        this.acc = (Account)sc.getRecord();
    }
    
    public PageReference redirectToNewContact() {
        isRedirect = true;
        redirectUrl = '/003/e?retURL=' + acc.Id + '&accid=' + acc.Id;
        return null;
    }
}

Visualforce Page:

<apex:page standardController="Account" extensions="AccountExtensionController" showHeader="false" sidebar="false">
    <apex:form >
        <apex:commandButton value="New Contact" action="{!redirectToNewContact}" rerender="redirectPanel" />
        <apex:outputPanel id="redirectPanel" >
            <apex:outputPanel rendered="{!isRedirect}">
                <!--redirect using javascript-->
                <script type="text/javascript">
                window.top.location.href = '{!redirectUrl}';
                </script>
            </apex:outputPanel>
        </apex:outputPanel>
    </apex:form>
</apex:page>

InputField datePicker is missing when standardStylesheets are disabled in Visualforce Page

Sample Code:

<apex:page standardController="Opportunity" showHeader="false" standardStylesheets="false" docType="html-5.0">
   <apex:form id="frm">
      <apex:pageBlock title="Opportunity">
         <apex:pageBlockSection title="Opportunity Information" collapsible="false">
            <apex:inputField value="{!Opportunity.ClosedDate}" showDatePicker="false" type="datetime-local" />
         </apex:pageBlockSection>
         <apex:pageBlockButtons>
            <apex:commandButton value="Save" action="{!save}"/>
         </apex:pageBlockButtons>
      </apex:pageBlock>
   </apex:form>
</apex:page>