This page is still a work in progress.
Blocks are self-contained add-ons that expand what you can display on your LinkStack page.
Blocks can be selected on the drop-down menu on the add links page.
All required files for the block should be included in the block folder. No editing of external files required. The block system takes care of loading assets, creating paths validation, translation etc.
THE BLOCK SYSTEM IS STILL IN EARLY DEVELOPMENT, THINGS MAY CHANGE. If you have any suggestions for improvements, please open an issue on this repository.
- Dynamic file loading
- Dynamic asset paths
- Translation support
- Validation
- Variable storage
- Pre-loaded libraries
- Indipendent HTML
- File uploads
- Error handling
- Form submission on links page
- Page for admins to manage and upload blocks
- Place to share and download blocks
- Built-in block updater
What are LinkStack blocks?
LinkStack blocks are self-contained add-ons that expand the functionality of your LinkStack instance, allowing you to display additional features on your page.How do I create my own block?
You can create your own block by following the structure outlined in the documentation, using the provided example block as a reference.How do I add blocks to my site?
To add a block to your instance, you have to upload the block into the blocks directory on your server. Blocks can then be selected when adding a new link.Do I need programming knowledge to create a block?
Yes. You should have prior experience with Laravel Blade, PHP, HTML, CSS, and JavaScript.Where can I report issues or provide feedback about the block system?
You can open an issue on this repository to report problems or suggest improvements and new features.How can I share my blocks with others?
A future feature will provide a dedicated space for sharing and downloading blocks. Currently, you can manually share your block directories.Can I include third-party libraries in my block?
It is recommended to include all necessary assets locally to ensure compliance with regulations like GDPR.Where is the data for my blocks stored?
Any block can store values inside the LinkStack database and are treated as any other link. The logic to store and display those values are contained in your block.Are blocks secure?
Blocks have full access to your instance and database. It is not recommended installing blocks from untrusted sources.Use the LinkStack Example Block as a practical demonstration of how to utilize the block system. This repository features a fully functional block that you can read and modify. It includes comprehensive comments to guide you through each step. This example is intended to complement the existing documentation and provide further clarity.
This powerful feature allows you to enhance your application by adding custom functionality. Here’s everything you need to know to get started:
Blocks are directories added to your instance that contain all necessary components for functionality. Each installed block is read from the blocks directory and can be accessed through the blocks dropdown menu in your app.
Each block consists of three main components:
- User Interface (UI) Form: Allows users to add or edit the block.
- Backend Component: Validates and stores the block data securely.
- Display File: Renders the block on the user’s links page.
A configuration file is essential for instructing the app on how to utilize your block effectively.
- Dynamic Asset Loading: Any additional assets your theme requires can be dynamically loaded from your blocks folder.
- Translation Support: Built-in translation support enables your blocks to be displayed in multiple languages.
- Automated Management: The block system automates tasks such as asset loading, dynamic URLs, and database management.
With this framework, you can create anything from simple buttons to complex elements like embedded videos or dynamic feeds.
.
└── your-block/
├── config.yml
├── display.blade.php
├── form.blade.php
├── handler.php
└── assets/
└── /* Any assets you need live here */
Blocks are written in Laravel Blade and PHP, utilizing HTML, CSS, and JavaScript. Previous experience with all of these technologies is expected.
The Blocks System offers a set of predefined functions designed to simplify tasks by automating specific operations. These functions are available for use across all three component files of each block.
Use block_asset($file_path)
to generate a dynamic URL for loading assets from the block directory.
Files can be used from everywhere within the block folder. For general assets like JS or CSS files, it is recommended to put those in the assets
directory. Subdirectories can be created as needed.
Loading a CSS file from the block's assets folder could look something like this:
Blade
<link rel="stylesheet" href="{{ block_asset('assets/style.css') }}">
Use get_block_file_contents($file_path)
to load contents of a file from the block directory.
This could be used to load a custom config file for the block itself.
Blade
<p>{{ get_block_file_contents('values.json') }}</p>
PHP
$json_data = get_block_file_contents('values.json');
Always use block_text($text)
or the shorthand bt($text)
function for text. It uses the translated value if available, otherwise defaults to the input string.
Blade
<h1>{{ block_text('Text to translate.') }}</h1>
PHP
$text = block_text('Text to translate.');
typename: example
title: "Displayed title of your block"
description: "Short description."
icon: "bi bi-code-square"
custom_html: true
ignore_container: true
include_libraries:
jquery: true
sweetalert: true
The config is formatted as YAML.
Most of these values are later stored with the block in the database.
-
The
typename
must be the same as your folder name. The app uses this value to load your files. -
The
title
anddescription
are displayed on the block selection page. -
bi bi-code-square
is used as the icon on the blocks selection tab. The system currently only supports Bootstrap icons for this. -
custom_html
defines if display.blade.php should be used to use custom HTML to display your block. If false, a generic button is used. In most use cases, this should be settrue
. -
ignore_container
places your block outside the default container all LinkStack buttons are normally nested in. This is useful for elements other than buttons. To use thiscustom_html
must be set totrue
. -
include_libraries
allows you to load certain libraries that the app already includes, should your block need it. Any included libraries don't have to be included in your block files anymore and can be used as normal. To use thiscustom_html
must be set totrue
.
This file is used to display the block on the user's links page.
The @once
directive is used to load assets only a single time, even if the block appears multiple times on the page. This is useful for preventing duplicate asset loading.
Blade
@once
<script>
var foo = 'bar';
</script>
@endonce
Use the @push
directive to ensure assets are loaded in the correct order.
Combine it with @once
for optimal performance.
Available positions include:
linkstack-head
linkstack-head-end
linkstack-body-start
linkstack-body-end
Blade
@push('linkstack-head-end')
<style> body { background: green; } </style>
@endpush
Assets and other files should be loaded, or global variables defined, only once when the page is loaded. Without using the @once
directive, these elements may be repeated each time your block is displayed on the page.
The @push
directive is typically used to run a section only once. You can use multiple @push
and @once
directives within a single file as needed.
Note that the order of the @push
directives in your file is not significant.
Blade
@once
@push('linkstack-head')
<script src="{{block_asset('assets/some.js')}}"></script>
<script>SomeFunction();</script>
<link rel="stylesheet" href="{{block_asset('assets/some.css')}}">
<style>
.some-class {
color: red;
}
</style>
@endpush
@push('linkstack-body-end')
<script>
const someConst = '{{block_text('Some text')}}';
</script>
<script src="{{block_asset('assets/library.js')}}"></script>
@endpush
@endonce
Use $link->some_value
to access stored variables.
Common values include:
$link->id
$link->user_id
$link->button_id
$link->link
$link->title
$link->click_number
$link->created_at
Blade
<div class="button">
<a id="{{ $link->id }}" href="{{ $link->link }}">{{ $link->title }}</a>
<span>This link has been clicked {{ $link->click_number ?? 0 }} times!</span>
</div>
This file is used to create and edit the block on the add/edit link page.
Your file is dynamically integrated into a form that submits your block via a POST request. Ensure that your file contains only the necessary form fields and assets, without any additional <form>
tags.
Structure
<form type="submit" method="post">
<!-- Loads: form.blade.php -->
</form>
This page is styled using Bootstrap 5.
In this file, stored values can be accessed using $some_value
instead of $link->some_value
. These variables should be utilized when the user is editing an existing block, ensuring that all form fields are pre-filled with existing data if available.
To enable an input field to be populated when editing a saved block, use the ??
operator to set default values and prevent errors. Set null
if no value is necessary.
Blade
<div class="form-group">
<input type="text" name="title" value="{{ $title }}">
<input type="url" name="link" value="{{ $link }}">
<input type="email" name="custom_value" value="{{ $custom_value ?? null }}">
</div>
This file validates and stores the block form input in the database.
Everything should be handled within the
handleLinkType()
function. It replaces the backend controller and ensures data is processed and stored correctly.
Structure
function handleLinkType($request, $linkType) {
$rules = [];
$linkData = [];
return ['rules' => $rules, 'linkData' => $linkData];
}
You can access any submitted value via the $request
variable.
If the form field has name="my_value"
, you can access it with: $request->my_value
.
The same name should be used when validating or storing the input.
PHP
$some_value = $request->my_value;
Always validate user input to ensure it's in the expected format.
This step is crucial for ensuring the security of the application. Proper validation helps prevent malicious input and maintains data integrity, protecting against potential vulnerabilities. Always validate user inputs before processing or storing them.
- It is recommended to set maximum input lengths.
- It is not recommended storing large values or files this way.
Validation is performed using the $rules
array, following standard Laravel validation rules. If the submitted data does not comply with the specified rules, the system will reject the request and redirect the user back to the form.
See: https://laravel.com/docs/11.x/validation#available-validation-rules
PHP
$rules = [
'my_value' => [
'required',
'numeric',
'max:1',
'regex:/[0-9]%/',
],
'other_value' => [
'required',
'string',
'max:255',
],
];
After validation succeeds, values can be stored in the database.
- Add any value you want to save to the
$linkData
array. - Predefined values include 'title' and 'link' (can be left empty).
PHP
$linkData = [
'title' => $request->title,
'link' => $request->link
];
You can store any amount of custom values in $linkData
. These values can be named however you like.
PHP
$linkData = [
'title' => $request->title,
'custom_value_1' => $request->something,
'custom_value_2' => 'Some Text',
'custom_value_3' => $some_var,
// Add more as needed
...
];
Thoroughly test your block alongside other elements on the links page and with various themes to ensure maximum compatibility. Additionally, verify that your block is secure against malicious attacks by validating user input on the backend.
Most themes utilize a generic skeleton CSS template to provide default styling for elements. You may need to override styles using !important
to achieve your desired results.
When creating blocks for the community, ensure that all assets, including libraries, stylesheets, and fonts, are included locally. This approach helps ensure compliance with GDPR and contributes to future-proofing your work.
When selecting names for CSS classes and JavaScript functions or classes, keep in mind that your block must be compatible with other blocks and themes. Since some systems may use identical names, a best practice is to add a unique prefix that corresponds to your block’s name.
This system is currently in development. Should you have any suggestions for changes or new features, please open an issue on this repository to share your ideas.
The overarching goal of this system is to make it as user-friendly and easy to learn as possible while maximizing its functionality.