Multiple Widgets on One Page
Mount two or more independent Xcrud grids side by side on a single page with Xcrud::get_instance().
get_instance() is not a true singleton
Despite the name (kept for backward compatibility with the old xCrud's own get_instance()), every call to Xcrud::get_instance() returns a brand new, independently-configured instance - never a shared one. That's what makes mounting several widgets on one page safe: configuring the second widget's table()/columns/options never leaks back into the first.
Example: two grids on one page
Each widget needs its own table() and, critically, its own unique route() value - the route is what the client-side widget uses to address its own AJAX calls, so two widgets sharing one route would collide:
$xcrud1 = Xcrud::get_instance();
$xcrud1->table('orders');
$xcrud1->route('multi-orders');
$xcrud1->title('Orders');
$xcrud1->columns('orderNumber,orderDate,status,customerNumber');
$xcrud2 = Xcrud::get_instance();
$xcrud2->table('payments');
$xcrud2->route('multi-payments');
$xcrud2->title('Payments');
$xcrud2->columns('customerNumber,checkNumber,paymentDate,amount');
$xcrud3 = Xcrud::get_instance();
$xcrud3->table('customers');
$xcrud3->route('multi-customers');
$xcrud3->title('Customers');
?><main>
<section>
<h2>Orders</h2>
<?php echo $xcrud1->render(); ?>
</section>
<section>
<h2>Payments</h2>
<?php echo $xcrud2->render(); ?>
</section>
<section>
<h2>Customers</h2>
<?php echo $xcrud3->render(); ?>
</section>
</main>
A page mounting several widgets like this produces its own full HTML output (rather than just configuring one $xcrud for the router's automatic wrapping) - the same shape pages/multi.php and pages/admin.php already use. One minor, harmless characteristic of calling ->render() more than once on a page: each call's own theme CSS/JS <link>/<script> tags are emitted again - browsers dedupe an identical src/href fine, it's just a little redundant markup.
Why this matters
Before this behavior was fixed, get_instance() returned the same object every time, so a second ->table() call would mutate the very same instance the first widget already configured - not just switching which table it points at, but leaving every other already-accumulated setting (columns(), highlight(), and so on) from the first configuration still attached too. Each call being a fresh instance is what lets independent widgets coexist safely on one page.