Learn how to create your custom ReportBurster Portal with the help of AI.
Accelerate your portal development using AI-powered tools and automation. This guide walks you through the full process of adding a new document/content type—from idea to automated publishing with ReportBurster—using real scripts, templates, and AI prompts.
Read here about Our AI Philosophy (how to build your own portal and use artificial intelligence to do it)
See sample scripts, templates, and AI prompts; get tips for best results
Fast-track your next setup
1. Plan Your Document Type
Think about the document type you need to automate and publish to the portal. Define its purpose, fields, and access rules to ensure smooth setup.
Note:
ReportBurster Portal comes bundled with three sample content types: Paystub, Payslip, and Invoice.
In this guide, you will configure a new custom content type called Statement.
Even if screenshots show Paystub, Payslip, or Invoice, always think in analogy for your own Statement type.
Caption: Example bundled templates for Paystub, Payslip, and Invoice.
You can use these bundled examples as guides for your own custom type.
To set up a new custom content type, you’ll update two existing scripts and create one new file:
Createsingle-(new-content-type).php — displays individual documents to users.
Updatepage-my-documents.php — shows the list of documents for each user (their account page).
UpdateendExtractDocument.groovy — uploads your document data to ReportBurster2Portal.
Good news:
You don’t need to write these scripts yourself (unless you want to).
AI will generate the code for you, so you can focus on building your dream portal.
2. Configure Your Content Type in Portal Admin UI
To add a new document type (e.g., Statement), use the portal admin UI.
AI is not needed here—simply configure your content type and fields as you need.
Why this step?
Every document type (like Statement, Payslip, Invoice) must be defined as a Pods "Custom Post Type" with the fields you want. This is the foundation for all portal features and automation.
How to do it:
Go to Pods Admin in your portal admin dashboard.
Click Add New to create a new Pod.
Choose Custom Post Type and fill in the name (e.g., "Statement").
Add all the fields you need (e.g., account holder, period, opening/closing balance).
Save your Pod.
Caption: Example fields for Paystub. For Statement, define your own fields.
You can configure multiple document types—there is no limit.
Once you save, your new content type is instantly available in the portal and can be used in all further steps.
Create one or two sample records for testing the full flow end to end.
Caption: Creating sample records for testing.
3. Create or Customize Templates
Now you need to control how your documents are displayed to users.
This is where AI can help you the most — by generating or adapting existing PHP templates for your new content type.
a. Single Document View
Caption: Example template files for single document view.
Copy single-paystub.php to single-statement.php.
Adjust the new template file to display your Statement fields and enforce access control.
Tip:
You don't have to write the PHP code yourself—AI can generate the script for you by adapting the existing example.
Replace the marked areas in the AI prompt with your Statement content type definition and the full content of the example script (single-paystub.php).
Give the prompt to your preferred AI chat vendor and paste the returned code into your new single-statement.php file.
When you view a single Statement document, you'll see your custom layout (not the sample Paystub layout).
Caption: Example single document view. Your Statement will have its own layout.
b. List View (My Documents)
Caption: Example template for listing documents.
For the list view, modify the existing page-my-documents.php to list your Statement documents for the logged-in user.
Provide your Statement content type definition and the full code of the example script (page-my-documents-paystub.php) to the AI.
Paste the returned code into your updated page-my-documents.php file.
When you visit /my-documents, you'll see your custom Statement list layout.
Caption: Example list view. Your Statement will have its own layout.
4. Automate Statements Publishing with ReportBurster
Generate a Groovy script to publish documents to the portal via the API.
What the script must do:
Check if the target portal user exists (by username/email); create if missing.
Prepare document data for your content type.
Publish the document via REST API (with authentication).
Provide your Statement content type definition and the full code of the example script (curl_paystub2portal.groovy) to the AI.
Paste the returned code into your scripts/burst/endExtractDocument.groovy file.
Tip:
Guard your code with:
if (ctx.settings.getTemplateName().toLowerCase().indexOf("statements2portal") != -1) { // AI-generated code here}
so it only runs for Statement documents.
Caption: Example publishing script location.
Now, your Statement documents will be uploaded to ReportBurster2Portal automatically.
Caption: Example execution for Statement documents.
ReportBurster works with any reporting or business software, including Crystal Reports, SAP, Oracle, Microsoft Dynamics, and more.
You can generate reports and upload to ReportBurster2Portal from any datasource.
5. Test and Iterate
Log in as admin and as a regular user to verify:
Documents appear in the dashboard/list view.
Access controls work as expected.
Single document view displays all fields correctly.
Automated publishing works and users are created as needed.
6. Reference & Tips for Using AI Effectively
Reference Scripts
Single document template:
single-paystub.php
<?php/** * Generic secure single document template (works also for invoices etc.) * * Plain PHP (WordPress, Pods Framework, Tailwind CSS) * * Features: * - Requires login. * - Ownership via Pods User Relationship field: associated_user (if present). * * OPTIONAL Pods fields you may add (all boolean/relationships can be left empty): * - allow_public_view (Boolean) If true: anyone with URL can view (no auth required). * - associated_user (User Relationship) Exact WP User owner. * - associated_groups (Pick / Multi-Select) One or more WP group slugs allowed (e.g. it, hr). * - associated_roles (Pick / Multi-Select) One or more WP role slugs allowed (e.g. employee, customer). * * Logic (in order): * 1. If allow_public_view = true => bypass all other checks. * 2. Otherwise user must be logged in. * 3. If associated_user set => only that user (or admin) allowed. * 4. Else if associated_groups set => user must be in at least one matching group. * 5. Else if associated_roles set => user must have at least one matching role. * 6. Else fallback: require logged-in user (already enforced). * * You can reuse this file for other doc types by copying & renaming to single-invoice.php etc. */if ( ! defined('ABSPATH') ) { exit; }$pod = function_exists('pods') ? pods( get_post_type(), get_the_ID() ) : null;if ( ! $pod ) { wp_die('Document data unavailable.');}$doc_type = get_post_type();// --- 1. Public flag (uncomment after creating the field) ---$allow_public_view = false;/*$allow_public_view = (bool) $pod->field('allow_public_view');*/// --- 2. Require login unless public ---if ( ! $allow_public_view && ! is_user_logged_in() ) { auth_redirect(); // redirects & exits exit;}$current_user = wp_get_current_user();$is_admin = current_user_can('administrator');// Collect intended access controls (may be empty if fields not defined)$associated_user_id = 0;/*$associated_user_id = (int) $pod->field('associated_user.ID');*/$associated_groups_ids = [];/*$associated_groups_ids = (array) $pod->field('associated_groups'); // adjust depending on Pods storage*/$associated_roles = [];/*$raw_roles = $pod->field('associated_roles');$associated_roles = is_array($raw_roles) ? $raw_roles : ( $raw_roles ? [ $raw_roles ] : [] );*/// --- 3–5. Conditional enforcement (skip if public or admin) ---if ( ! $allow_public_view && ! $is_admin ) { // 3. Exact user ownership if ( $associated_user_id ) { if ( get_current_user_id() !== $associated_user_id ) { wp_die('Not authorized (owner mismatch).'); } } // 4. Group membership (placeholder – implement your own check) elseif ( $associated_groups_ids ) { /* // Example placeholder: $user_group_ids = []; // TODO: fetch groups for current user. if ( ! array_intersect( $associated_groups_ids, $user_group_ids ) ) { wp_die('Not authorized (group mismatch).'); } */ } // 5. Role-based access elseif ( $associated_roles ) { $user_roles = (array) $current_user->roles; if ( ! array_intersect( $associated_roles, $user_roles ) ) { wp_die('Not authorized (role mismatch).'); } } // 6. Else: already logged in so allowed.}// ---------------- DATA FIELDS (only those that currently exist) ----------------$employee = esc_html( (string) $pod->display('employee') );$period = esc_html( (string) $pod->display('period') );$grossAmount = number_format( (float) $pod->field('gross_amount'), 2 );$netAmount = number_format( (float) $pod->field('net_amount'), 2 );// Load theme header (includes Tailwind and other assets)get_header();?><div class="max-w-xl mx-auto bg-white font-sans text-gray-900 p-6"> <h1 class="text-2xl font-bold mb-2"><?php echo esc_html( get_the_title() ); ?></h1> <?php if ( $allow_public_view ): ?> <div class="text-xs text-gray-500 mb-4">Public document (no login required).</div> <?php endif; ?> <table class="w-full border border-gray-300 rounded-lg mt-6"> <tbody> <tr class="border-b border-gray-200"> <td class="py-2 px-4 font-medium">Employee</td> <td class="py-2 px-4"><?php echo $employee; ?></td> </tr> <tr class="border-b border-gray-200"> <td class="py-2 px-4 font-medium">Period</td> <td class="py-2 px-4"><?php echo $period; ?></td> </tr> <tr class="border-b border-gray-200"> <td class="py-2 px-4 font-medium">Gross Amount</td> <td class="py-2 px-4 text-right">$<?php echo $grossAmount; ?></td> </tr> <tr> <td class="py-2 px-4 font-medium">Net Amount</td> <td class="py-2 px-4 text-right">$<?php echo $netAmount; ?></td> </tr> </tbody> </table> <div class="mt-8 font-bold text-right bg-gray-100 p-4 rounded-lg text-lg"> Net Pay: $<?php echo $netAmount; ?> </div> <div class="mt-10 flex justify-center gap-4 print:hidden"> <?php $account_page_id = (int) get_option('reportburster_account_page_id'); $back_url = $account_page_id ? get_permalink($account_page_id) : ( get_permalink( get_page_by_path('my-documents') ) ?: home_url() ); ?> <a href="<?php echo esc_url( $back_url ); ?>" class="inline-block px-5 py-2 rounded bg-green-600 text-white hover:bg-green-700 transition"> Back to Documents </a> <a class="inline-block px-5 py-2 rounded bg-blue-600 text-white hover:bg-blue-700 transition" href="javascript:window.print();"> Print </a> </div></div><?php// Load theme footer (includes scripts and closes HTML)get_footer();?>