{"id":1867,"date":"2026-04-25T06:53:23","date_gmt":"2026-04-25T06:53:23","guid":{"rendered":"https:\/\/sfplugin.com\/docs\/?post_type=docs&#038;p=1867"},"modified":"2026-04-25T10:25:06","modified_gmt":"2026-04-25T10:25:06","slug":"create-self-service-salesforce-customer-portal-in-wordpress","status":"publish","type":"docs","link":"https:\/\/sfplugin.com\/docs\/how-to\/create-self-service-salesforce-customer-portal-in-wordpress\/","title":{"rendered":"How to Create a Salesforce Customer Portal in WordPress in 2026 (Step-by-Step)"},"content":{"rendered":"<p><strong>If your team is spending hours every week chasing customers for updates, answering &#8220;what&#8217;s my account status?&#8221; emails, or manually re-entering data that your users could just type themselves, this one&#8217;s for you.<\/strong><\/p>\n<p>This guide walks through exactly how to turn your WordPress site into a self-service Salesforce portal using Sawfish. One page. Unlimited users. Each person logs in and sees only their own data from Salesforce, in real time, and they can update it themselves without picking up the phone.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/sfplugin.com\/img\/Create%20Salesforce%20Portals%20in%20WordPress%20Website.png\" alt=\"Create a Salesforce Customer Portal in WordPress with Sawfish\" style=\"width:100%; height:auto; margin-bottom: 2em;\" \/><\/p>\n<p>No Salesforce Community Cloud. No expensive per-user licensing. No custom development work. Just WordPress, Sawfish, and a bit of setup time.<\/p>\n<hr \/>\n<h2>What We&#8217;re Building<\/h2>\n<ul>\n<li><strong>Clients:<\/strong> Manage and update their own contact details instantly.<\/li>\n<li><strong>Donors:<\/strong> Log in to access and review their complete giving history.<\/li>\n<li><strong>B2B Customers:<\/strong> View open cases and submit new requests directly, bypassing the need for back-and-forth emails.<\/li>\n<li><strong>Members:<\/strong> Audit their account information and correct outdated data, such as a phone number changed months ago.<\/li>\n<\/ul>\n<p>All of that data is coming live from Salesforce, and you only build the page once. Sawfish handles loading the right records for whoever is logged in at the time. The flow looks like this:<\/p>\n<blockquote><p>\n<strong>User logs into WordPress &rarr; Sawfish matches them to their Salesforce record &rarr; They see only their own data<\/strong>\n<\/p><\/blockquote>\n<p>This works for any type of user: members, donors, volunteers, clients, partners, B2B contacts. As long as they have a record in Salesforce and a login on your WordPress site, the portal works for them.<\/p>\n<hr \/>\n<h2>Before You Start: What You&#8217;ll Need<\/h2>\n<ul>\n<li><strong><a href=\"https:\/\/sfplugin.com\" target=\"_blank\">Sawfish plugin<\/a><\/strong> installed and connected to your Salesforce org<\/li>\n<li>A <strong>WordPress login or membership plugin<\/strong> to manage user accounts and restrict page access (free options covered below)<\/li>\n<li>A <strong>form plugin.<\/strong> We use <a href=\"https:\/\/wordpress.org\/plugins\/html-forms\/\" target=\"_blank\">HTML Forms<\/a> throughout this guide. It&#8217;s free, lightweight, and works seamlessly with Sawfish. Elementor Forms works too if that&#8217;s already in your stack.<\/li>\n<li>Your <strong>Salesforce org<\/strong> with existing Contact or Account records<\/li>\n<\/ul>\n<hr \/>\n<h2>Step 1: Decide How You&#8217;ll Match WordPress Users to Salesforce Records<\/h2>\n<p>This is the foundation of the whole portal. Sawfish needs to know which Salesforce record belongs to which logged-in WordPress user. There are two ways to set that up.<\/p>\n<h3>Option A: Match by Email (Usually the easiest starting point)<\/h3>\n<p>If the email address a user logs into WordPress with is the same email on their Salesforce Contact record, you&#8217;re already halfway there. No extra Salesforce fields needed.<\/p>\n<p>Sawfish uses the dynamic variable <code>$WPEmail<\/code> to grab the logged-in user&#8217;s email at the moment they load the page, then filters Salesforce records to find the one where the Email field matches. In the shortcode, the filter looks like this:<\/p>\n<pre><code>filter=\"Email='$WPEmail'\"<\/code><\/pre>\n<p>This approach works best when you&#8217;re using the Contact object and your users&#8217; emails are consistent across both systems.<\/p>\n<h3>Option B: Match by WordPress User ID (More robust for Account-based setups)<\/h3>\n<p>Every WordPress user has a unique numeric ID. If you create a custom field on your Salesforce Account or Contact object, typically named <code>WordPress_ID__c<\/code>, and populate it with each user&#8217;s WordPress ID, Sawfish can filter by that instead.<\/p>\n<pre><code>filter=\"WordPress_ID__c=$WPId\"<\/code><\/pre>\n<p>This is the approach shown in the example code throughout this post, and it&#8217;s particularly useful when you&#8217;re working with Account records (which don&#8217;t have a standard Email field), or when you want a guaranteed unique identifier that won&#8217;t change if someone updates their email address.<\/p>\n<p><em>For most organisations working with individual contacts, email matching is the faster route to getting something live. For B2B setups using Account records, go with the WordPress ID approach.<\/em><\/p>\n<hr \/>\n<h2>Step 2 (Optional): Set Up the WordPress ID Field in Salesforce<\/h2>\n<p><strong>This step only applies if you chose Option B (WordPress ID matching) in Step 1. If you&#8217;re matching users by email, you can skip straight to <a href=\"#step4\">Step 4: Display the User&#8217;s Salesforce Record<\/a>.<\/strong><\/p>\n<p>Why is this optional? Because if your WordPress users log in with the same email address that&#8217;s on their Salesforce Contact record, Sawfish can match them automatically with no extra setup. The WordPress ID approach is an alternative for situations where email matching isn&#8217;t reliable, such as when you&#8217;re working with Account records rather than Contacts, or when email addresses aren&#8217;t consistent across both systems.<\/p>\n<p>If that doesn&#8217;t apply to your setup, skip ahead. If it does, here&#8217;s how to link the two systems.<\/p>\n<ol>\n<li>\n    <strong>Create a custom field in Salesforce.<\/strong> On your Account or Contact object, add a new field. Name it something like <code>WordPress ID<\/code>. Salesforce will give it the API name <code>WordPress_ID__c<\/code>. Text or Number type both work.\n  <\/li>\n<li>\n    <strong>Export your WordPress users.<\/strong> Install a free plugin like <a href=\"https:\/\/wordpress.org\/plugins\/export-users-to-csv\/\" target=\"_blank\">Export Users to CSV<\/a> from the WordPress plugin directory. Export your user list and make sure the User ID column is included. You&#8217;ll see the IDs in the URL when you click on a user under <strong>Users &rarr; All Users<\/strong> in the WordPress dashboard.\n  <\/li>\n<li>\n    <strong>Import those IDs into Salesforce.<\/strong> Use Salesforce&#8217;s Import Wizard (for smaller datasets) or Data Loader (for larger ones) to update your existing Account or Contact records with the corresponding WordPress User ID in the field you just created.\n  <\/li>\n<\/ol>\n<p>Once that&#8217;s done, every Salesforce record is linked to a specific WordPress user account, and Sawfish can filter to exactly the right record every time someone logs in.<\/p>\n<hr \/>\n<h2>Step 3 (Optional): Restrict Your Portal Page to Logged-In Users<\/h2>\n<p><strong>This step only applies if your WordPress site doesn&#8217;t already have a membership or login system in place. If you already have a plugin handling page access restrictions, skip to <a href=\"#step4\">Step 4<\/a>.<\/strong><\/p>\n<p>Why is this optional? Because many sites already have this sorted. If you&#8217;re running MemberPress, WooCommerce Memberships, or any other membership plugin, you very likely already have a way to restrict pages to logged-in users. In that case, create your portal page, apply the restriction you normally would, and move on.<\/p>\n<p>If you don&#8217;t have anything like that set up yet, here&#8217;s the quickest way to get there.<\/p>\n<p>Create a new page in WordPress, something like &#8220;My Account&#8221; or &#8220;Client Portal&#8221;. Then install one of these free plugins to restrict it to logged-in users only:<\/p>\n<ul>\n<li><a href=\"https:\/\/wordpress.org\/plugins\/members\/\" target=\"_blank\">Members<\/a> &#8211; lets you set role-based visibility on any page<\/li>\n<li><a href=\"https:\/\/wordpress.org\/plugins\/restrict-content\/\" target=\"_blank\">Restrict Content<\/a> &#8211; straightforward page-level login restrictions<\/li>\n<\/ul>\n<p>Set the page to redirect anyone who isn&#8217;t logged in to your WordPress login page. Once that&#8217;s in place, you&#8217;re ready to add the Sawfish shortcodes.<\/p>\n<p>You&#8217;ll also want to add a logout link somewhere on the page. A simple way to do that is to place this at the top:<\/p>\n<pre><code>&lt;p style=\"text-align: right;\"&gt;&lt;a href=\"https:\/\/yoursite.com\/log-out\/\"&gt;Log Out&lt;\/a&gt;&lt;\/p&gt;<\/code><\/pre>\n<hr \/>\n<h2 id=\"step4\">Step 4: Display the User&#8217;s Salesforce Record<\/h2>\n<p>This is the core of the portal. The <code>[sectionsforce]<\/code> shortcode queries Salesforce for the logged-in user&#8217;s record and lets you display any field from it using the <code>{!FieldName}<\/code> merge syntax.<\/p>\n<p>Here&#8217;s a working example using the Account object with WordPress ID matching:<\/p>\n<pre><code>[sectionsforce o=\"Account\" by=\"Id\" n=\"1\" filter=\"WordPress_ID__c=$WPId\"]\r\n\r\n&lt;h2&gt;&lt;b&gt;{!Name}&lt;\/b&gt;&lt;\/h2&gt;\r\n\r\n&lt;p&gt;Phone: {!Phone}&lt;\/p&gt;\r\n&lt;p&gt;State: {!BillingState}&lt;\/p&gt;\r\n\r\n[\/sectionsforce]<\/code><\/pre>\n<p>Breaking down what each parameter does:<\/p>\n<ul>\n<li><code>o=\"Account\"<\/code>: the Salesforce object to query. Change this to <code>Contact<\/code> if you&#8217;re working with Contact records.<\/li>\n<li><code>by=\"Id\"<\/code>: tells Sawfish to retrieve the record by its Salesforce ID<\/li>\n<li><code>n=\"1\"<\/code>: limits the result to one record. Since each user maps to one Account, this keeps things clean.<\/li>\n<li><code>filter=\"WordPress_ID__c=$WPId\"<\/code>: this is where the matching happens. Sawfish substitutes <code>$WPId<\/code> with the logged-in user&#8217;s WordPress ID at page load.<\/li>\n<li><code>{!Name}<\/code>, <code>{!Phone}<\/code>, <code>{!BillingState}<\/code>: Salesforce field API names. Swap in whichever fields you want to display.<\/li>\n<\/ul>\n<p>Save the page and load it while logged in as a test user. If your Salesforce connection is set up and the matching field is populated, you&#8217;ll see their Account data appear.<\/p>\n<hr \/>\n<h2>Step 5: Pre-Fill Your Update Form Using jQuery<\/h2>\n<p>Once you&#8217;ve got the record displaying, the next step is letting users edit their own information. Sawfish handles this by letting you use a small jQuery snippet to pull the rendered Salesforce values from the page and inject them into the form fields, so the form arrives pre-populated with the user&#8217;s current data and they only change what needs updating.<\/p>\n<p>Inside your <code>[sectionsforce]<\/code> shortcode block, add this script:<\/p>\n<pre><code>&lt;script&gt;\r\njQuery(function() {\r\n    jQuery('[name=\"sf-AccountId\"]').val('{!Id}');\r\n    jQuery('[name=\"sf-Id\"]').val('{!Id}');\r\n    jQuery('[name=\"sf-Name\"]').val('{!Name}');\r\n    jQuery('[name=\"sf-Phone\"]').val('{!Phone}');\r\n});\r\n&lt;\/script&gt;<\/code><\/pre>\n<p>When the page loads, Sawfish has already rendered the <code>{!Id}<\/code>, <code>{!Name}<\/code>, and <code>{!Phone}<\/code> values from Salesforce into the HTML. The jQuery reads those rendered values and injects them into the corresponding form fields. The hidden field <code>sf-Id<\/code> is the critical one. That&#8217;s what tells Salesforce which record to update when the form is submitted. Without it, nothing will update.<\/p>\n<p>Your HTML Forms update form (created under <strong>HTML Forms &rarr; Add New<\/strong>) should include these hidden fields alongside the visible inputs:<\/p>\n<pre><code>&lt;input type=\"hidden\" name=\"sf-o\" value=\"Account\" \/&gt;\r\n&lt;input type=\"hidden\" name=\"sf-form\" value=\"update\" \/&gt;\r\n&lt;input type=\"hidden\" name=\"sf-Id\" value=\"\" \/&gt;\r\n&lt;input type=\"hidden\" name=\"sf-AccountId\" value=\"\" \/&gt;\r\n\r\n&lt;p&gt;\r\n  &lt;label&gt;Account Name&lt;\/label&gt;\r\n  &lt;input type=\"text\" name=\"sf-Name\" value=\"\" \/&gt;\r\n&lt;\/p&gt;\r\n\r\n&lt;p&gt;\r\n  &lt;label&gt;Phone&lt;\/label&gt;\r\n  &lt;input type=\"text\" name=\"sf-Phone\" value=\"\" \/&gt;\r\n&lt;\/p&gt;\r\n\r\n&lt;p&gt;\r\n  &lt;input type=\"submit\" value=\"Update Details\" \/&gt;\r\n&lt;\/p&gt;<\/code><\/pre>\n<p>The <code>value=\"\"<\/code> fields start empty in the HTML Forms editor. The jQuery fills them at runtime. The <code>name<\/code> attribute for each visible field must match the Salesforce field API name prefixed with <code>sf-<\/code>. So <code>Phone<\/code> becomes <code>sf-Phone<\/code>, <code>BillingCity<\/code> becomes <code>sf-BillingCity<\/code>, and so on.<\/p>\n<p>Once you&#8217;ve saved the HTML Form, embed it on your portal page using its shortcode, e.g. <code>[hf_form slug=\"update-account-form\"]<\/code>.<\/p>\n<hr \/>\n<h2>Step 6: Add a Case Submission Form<\/h2>\n<p>If you want users to raise support requests from their portal, you can add a Case creation form alongside the update form. A common layout puts both forms side by side, update on the left and new Case on the right.<\/p>\n<p>Here&#8217;s what the Case form looks like inside HTML Forms:<\/p>\n<pre><code>&lt;input type=\"hidden\" name=\"sf-o\" value=\"Case\" \/&gt;\r\n&lt;input type=\"hidden\" name=\"sf-form\" value=\"create\" \/&gt;\r\n&lt;input type=\"hidden\" name=\"sf-AccountId\" value=\"\" \/&gt;\r\n\r\n&lt;p&gt;\r\n  &lt;label&gt;Subject&lt;\/label&gt;\r\n  &lt;input type=\"text\" name=\"sf-Subject\" placeholder=\"Brief description of your issue\" required \/&gt;\r\n&lt;\/p&gt;\r\n\r\n&lt;p&gt;\r\n  &lt;label&gt;Description&lt;\/label&gt;\r\n  &lt;textarea name=\"sf-Description\" rows=\"5\" placeholder=\"As much detail as you can...\"&gt;&lt;\/textarea&gt;\r\n&lt;\/p&gt;\r\n\r\n&lt;p&gt;\r\n  &lt;input type=\"submit\" value=\"Submit Case\" \/&gt;\r\n&lt;\/p&gt;<\/code><\/pre>\n<p>The key difference from the update form: <code>sf-form=\"create\"<\/code> tells Sawfish to create a new Salesforce record rather than updating an existing one. The <code>sf-AccountId<\/code> hidden field gets pre-filled by the same jQuery snippet from the previous step, so the Case is automatically linked to the logged-in user&#8217;s Account record with no manual association required.<\/p>\n<p>To lay the two forms side by side on the portal page:<\/p>\n<pre><code>&lt;div style=\"width: 100%; display: table;\"&gt;\r\n  &lt;div style=\"display: table-row;\"&gt;\r\n\r\n    &lt;div style=\"width: 600px; display: table-cell; padding-right: 40px;\"&gt;\r\n      &lt;h4&gt;&lt;b&gt;Update your account details&lt;\/b&gt;&lt;\/h4&gt;\r\n      [hf_form slug=\"update-account-form\"]\r\n    &lt;\/div&gt;\r\n\r\n    &lt;div style=\"display: table-cell;\"&gt;\r\n      &lt;h4&gt;&lt;b&gt;Create a new Case&lt;\/b&gt;&lt;\/h4&gt;\r\n      [hf_form slug=\"create-case\"]\r\n    &lt;\/div&gt;\r\n\r\n  &lt;\/div&gt;\r\n&lt;\/div&gt;<\/code><\/pre>\n<hr \/>\n<h2>Step 7: Show the User&#8217;s Related Records<\/h2>\n<p>The last piece that makes this feel like a proper portal is showing the user their related records. Their open Cases, Opportunities, past transactions, whatever is relevant to your org.<\/p>\n<p>The <code>[showsforce]<\/code> shortcode handles this. Here&#8217;s how to display a user&#8217;s Cases in a table, filtered to only show records linked to the logged-in user:<\/p>\n<pre><code>[showsforce fields=\"CaseNumber,Subject,Priority,Status\" o=\"Case\" filter=\"WordPress_ID__c=$WPId\" by=\"Id\" n=\"10\" search=\"off\" t=\"1\"]<\/code><\/pre>\n<p>And for Opportunities linked to the user&#8217;s Account, note the cross-object filter using dot notation, which follows the Account relationship from the Opportunity:<\/p>\n<pre><code>[showsforce fields=\"Name,Amount,StageName\" o=\"Opportunity\" filter=\"Account.WordPress_ID__c=$WPId\" by=\"Id\" n=\"100\" t=\"1\"]<\/code><\/pre>\n<p>A quick explanation of the parameters:<\/p>\n<ul>\n<li><code>fields<\/code>: a comma-separated list of Salesforce field API names to display as columns in the table<\/li>\n<li><code>filter<\/code>: the filter that scopes results to this user. For records with a direct <code>WordPress_ID__c<\/code> field, use <code>WordPress_ID__c=$WPId<\/code>. For related objects, use dot notation: <code>Account.WordPress_ID__c=$WPId<\/code><\/li>\n<li><code>n<\/code>: the maximum number of records to return<\/li>\n<li><code>t=\"1\"<\/code>: renders results as a table<\/li>\n<li><code>search=\"off\"<\/code>: hides the search bar, which usually isn&#8217;t needed in a personal portal<\/li>\n<\/ul>\n<p>Place these below your forms section with a clear heading for each section:<\/p>\n<pre><code>&lt;h4&gt;&lt;b&gt;Your Cases&lt;\/b&gt;&lt;\/h4&gt;\r\n&lt;hr \/&gt;\r\n[showsforce fields=\"CaseNumber,Subject,Priority,Status\" o=\"Case\" filter=\"WordPress_ID__c=$WPId\" by=\"Id\" n=\"10\" search=\"off\" t=\"1\"]<\/code><\/pre>\n<hr \/>\n<h2>Putting the Whole Page Together<\/h2>\n<p>Here&#8217;s the full structure of a working portal page, pulling together everything from the steps above:<\/p>\n<pre><code>&lt;p style=\"text-align: right;\"&gt;&lt;a href=\"https:\/\/yoursite.com\/log-out\/\"&gt;Log Out&lt;\/a&gt;&lt;\/p&gt;\r\n\r\n[sectionsforce o=\"Account\" by=\"Id\" n=\"1\" filter=\"WordPress_ID__c=$WPId\"]\r\n\r\n&lt;h2&gt;&lt;b&gt;{!Name}&lt;\/b&gt;&lt;\/h2&gt;\r\n\r\n&lt;p&gt;Phone: {!Phone}&lt;\/p&gt;\r\n&lt;p&gt;State: {!BillingState}&lt;\/p&gt;\r\n\r\n&lt;hr \/&gt;\r\n\r\n&lt;script&gt;\r\njQuery(function() {\r\n    jQuery('[name=\"sf-AccountId\"]').val('{!Id}');\r\n    jQuery('[name=\"sf-Id\"]').val('{!Id}');\r\n    jQuery('[name=\"sf-Name\"]').val('{!Name}');\r\n    jQuery('[name=\"sf-Phone\"]').val('{!Phone}');\r\n});\r\n&lt;\/script&gt;\r\n\r\n&lt;div style=\"width: 100%; display: table;\"&gt;\r\n  &lt;div style=\"display: table-row;\"&gt;\r\n\r\n    &lt;div style=\"width: 600px; display: table-cell; padding-right: 40px;\"&gt;\r\n      &lt;h4&gt;&lt;b&gt;Update your account details&lt;\/b&gt;&lt;\/h4&gt;\r\n      [hf_form slug=\"update-account-form\"]\r\n    &lt;\/div&gt;\r\n\r\n    &lt;div style=\"display: table-cell;\"&gt;\r\n      &lt;h4&gt;&lt;b&gt;Create a new Case&lt;\/b&gt;&lt;\/h4&gt;\r\n      [hf_form slug=\"create-case\"]\r\n    &lt;\/div&gt;\r\n\r\n  &lt;\/div&gt;\r\n&lt;\/div&gt;\r\n\r\n&lt;h4&gt;&lt;b&gt;Your Cases&lt;\/b&gt;&lt;\/h4&gt;\r\n&lt;hr \/&gt;\r\n[showsforce fields=\"CaseNumber,Subject,Priority,Status\" o=\"Case\" filter=\"WordPress_ID__c=$WPId\" by=\"Id\" n=\"10\" search=\"off\" t=\"1\"]\r\n\r\n[\/sectionsforce]<\/code><\/pre>\n<p>That&#8217;s one page. Every user who logs in sees their own Account data, their own Cases, and can update their own details or raise a new request without involving your team at any point.<\/p>\n<hr \/>\n<h2>Frequently Asked Questions<\/h2>\n<h3>Will users ever see each other&#8217;s data?<\/h3>\n<p>No. The filter in every <code>[sectionsforce]<\/code> and <code>[showsforce]<\/code> shortcode uses <code>$WPId<\/code> or <code>$WPEmail<\/code>, variables that Sawfish resolves at page load to the currently logged-in user&#8217;s values only. A user who isn&#8217;t logged in at all won&#8217;t see anything, because the page is restricted to logged-in users. And a logged-in user&#8217;s <code>$WPId<\/code> is assigned by WordPress. It can&#8217;t be manipulated by passing something in via the URL or a form field.<\/p>\n<h3>Do I need a separate page for each user?<\/h3>\n<p>No, and that&#8217;s the whole point. You build one page, once. Sawfish dynamically loads different data from Salesforce depending on who&#8217;s logged in. Whether you have 50 users or 50,000, you&#8217;re still maintaining a single page in WordPress.<\/p>\n<h3>Does Sawfish charge per user login?<\/h3>\n<p>Sawfish supports unlimited user logins. There&#8217;s no per-seat cost for your portal users. Check the <a href=\"https:\/\/sfplugin.com\" target=\"_blank\">pricing page<\/a> for current plan details.<\/p>\n<h3>My users already exist in Salesforce but don&#8217;t have WordPress accounts. How do I create them in bulk?<\/h3>\n<p>You&#8217;ll need to create WordPress user accounts for each of them, since WordPress handles the login side. The fastest way to do this at scale is with a CSV import plugin.<\/p>\n<p><a href=\"https:\/\/breakdance.com\/csv-user-import-wordpress\/\" target=\"_blank\">This CSV User Import tool<\/a> lets you upload a spreadsheet with each user&#8217;s first name, last name, email, role, and an initial password, and it creates the WordPress accounts in one go. The process looks like this:<\/p>\n<ol>\n<li>Export your Salesforce Contacts or Account contacts to a CSV.<\/li>\n<li>Reformat the columns to match what the importer expects (typically: first name, last name, email, role).<\/li>\n<li>Run the import. WordPress creates an account for each row.<\/li>\n<li>Export the newly-created WordPress users (using a plugin like Export Users to CSV) to get their User IDs.<\/li>\n<li>Import those User IDs back into Salesforce to populate the <code>WordPress_ID__c<\/code> field on the matching records.<\/li>\n<\/ol>\n<p>The import-export loop sounds like a round trip, but it&#8217;s a one-time job. After that, new users can be created individually as they come on board, and you can set up automation to create matching records in both systems at the same time.<\/p>\n<h3>What Salesforce objects can I use?<\/h3>\n<p>Any of them. Account, Contact, Case, Opportunity, and any custom object you&#8217;ve built in your org. The shortcode takes the API name of the object. If it&#8217;s queryable in Salesforce, you can surface it on the portal page.<\/p>\n<h3>What if I want to show Contacts related to an Account?<\/h3>\n<p>You can use a jQuery approach similar to the one in Step 5 to populate a dropdown of related Contacts. The <code>[showsforce]<\/code> shortcode returns the data as a JSON-style array, and a script maps it into a select element. This is useful if, for example, a B2B account holder wants to assign a Case to a specific contact person on their account. The cross-object filter <code>Account.WordPress_ID__c=$WPId<\/code> pulls only Contacts that belong to the logged-in user&#8217;s Account.<\/p>\n<h3>What if my Account records don&#8217;t have an email field?<\/h3>\n<p>The standard Account object in Salesforce doesn&#8217;t include an Email field by default, which is exactly why the WordPress ID matching approach exists. You could add a custom email field to Account and filter by that, but the WordPress ID field is more reliable long-term since it won&#8217;t break if someone changes their email address in either system.<\/p>\n<hr \/>\n<h2>Ready to Build?<\/h2>\n<p>If you&#8217;ve followed along, you now have a clear picture of how the portal comes together. One page, real Salesforce data, filtered per user, with update forms and related records all in one place.<\/p>\n<p>The time savings for your team are real. Every update a customer makes themselves is an email your staff don&#8217;t have to send, a manual data entry task that doesn&#8217;t have to happen, a Salesforce record that stays accurate without anyone on your team touching it.<\/p>\n<p><strong>Want to see a live demo before you start building?<\/strong> <a href=\"https:\/\/calendly.com\/sawfish-plugin\/30min\" target=\"_blank\">Book a free 30-minute walkthrough<\/a> and we&#8217;ll go through the whole setup with you.<\/p>\n<p>Or if you&#8217;re ready to get into it, <a href=\"https:\/\/sfplugin.com\" target=\"_blank\">download Sawfish and start your free 5-day trial<\/a>.<\/p>\n<p>If you hit a wall at any point, reach out. We&#8217;re happy to help get it working.<\/p>\n<hr \/>\n<p><em>Got questions, or built something you&#8217;re proud of? Leave a comment below. We always like hearing what teams are building with this.<\/em><\/p>\n","protected":false},"featured_media":0,"parent":148,"menu_order":26,"comment_status":"open","ping_status":"closed","template":"","doc_tag":[],"class_list":["post-1867","docs","type-docs","status-publish","hentry"],"comment_count":0,"_links":{"self":[{"href":"https:\/\/sfplugin.com\/docs\/wp-json\/wp\/v2\/docs\/1867","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sfplugin.com\/docs\/wp-json\/wp\/v2\/docs"}],"about":[{"href":"https:\/\/sfplugin.com\/docs\/wp-json\/wp\/v2\/types\/docs"}],"replies":[{"embeddable":true,"href":"https:\/\/sfplugin.com\/docs\/wp-json\/wp\/v2\/comments?post=1867"}],"version-history":[{"count":2,"href":"https:\/\/sfplugin.com\/docs\/wp-json\/wp\/v2\/docs\/1867\/revisions"}],"predecessor-version":[{"id":1869,"href":"https:\/\/sfplugin.com\/docs\/wp-json\/wp\/v2\/docs\/1867\/revisions\/1869"}],"up":[{"embeddable":true,"href":"https:\/\/sfplugin.com\/docs\/wp-json\/wp\/v2\/docs\/148"}],"prev":[{"title":"How to Create an External Client App in Salesforce? (Step-by-Step Guide)","link":"https:\/\/sfplugin.com\/docs\/how-to\/create-an-external-client-app-in-salesforce-step-by-step-guide\/","href":"https:\/\/sfplugin.com\/docs\/wp-json\/wp\/v2\/docs\/1789"}],"wp:attachment":[{"href":"https:\/\/sfplugin.com\/docs\/wp-json\/wp\/v2\/media?parent=1867"}],"wp:term":[{"taxonomy":"doc_tag","embeddable":true,"href":"https:\/\/sfplugin.com\/docs\/wp-json\/wp\/v2\/doc_tag?post=1867"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}