Laravel Shortcodes

WordPress based Shortcodes for Laravel 5.x with shared variables, debugbar integration, flexible configuration and other useful features.

Github: https://github.com/vedmant/laravel-shortcodes

Build powerful and simple layouts using shortcodes in the content or views like this:

[b]Bold text[/b]
[row]
  [col md=8]
     [posts_list types="post,gallery" show_tags="yes"]
  [/col]
  [col md=4]
     [poll id="1"]
     [user_info username="test_user" website="mywebsite.com" active="yes"]
     [last_free_post title="Free Posts"]
  [/col]
[/row]

Installation

Via Composer

$ composer require vedmant/laravel-shortcodes

This package supports Laravel Auto-Discover and will be discovered automatically.

For Laravel version before 5.5 please add the Vedmant\LaravelShortcodes\LaravelShortcodesServiceProvider::class to the providers array in config/app.php. And optionally ‘Shortcodes’ => Vedmant\LaravelShortcodes\Facades\Shortcodes::class, to aliases.

Configuraton

Publish configuration.

php artisan vendor:publish --tag=shortcodes

Usage

Shortcode class

Shortcode class should extend abstract \Vedmant\LaravelShortcodes\Shortcode class.

This packages adds make:shortcode artisan command:

php artisan make:shortcode PostsListShortcode

It will generate a shortcode class in the app/Shortcodes folder by default.

Register shortcodes

You can use AppServiceProvider boot method to register all needed shortcodes.

Using shortcode class:

Shortcodes::add('b', BShortcode::class);

Using shortcode classes in array, preferable for lots of shortcodes:

Shortcodes::add([
   'a' => AShortcode::class,
   'b' => BShortcode::class,
]);

Using closure:

Shortcodes::add('test', function ($atts, $content, $tag, $manager) {
   return new HtmlString('<strong>some test shortcode</strong>');
});

Rendering shortcodes

By default this packages extends View to parse all shortcodes during views rendering. This feature can be disabled in the config file.

Also to enable / disable rendering shortcodes for specific view you can use:

view('some-view')->withShortcodes(); // Or view('some-view')->withoutShortcodes();

To render shortcodes manually use:

{{ Shortcodes::render('[b]bold[/b]') }}

Shared attributes

YOccasionally, you may need to share a piece of data with all shortcodes that are rendered by your application. You may do so using the shortode facade’s share method. Typically, you should place calls to share in the controller, or within a service provider’s boot method.

Shortcodes::share('post', $post);

Then you can get share attributes in the shortcode class:

$post = $this->shared('post'); $allShared = $this->shared();

Comma separated values (array attributes)

If you need to pass an array to a shortcode, you can pass values separated by comma:

[posts_list ids="1,2,3"]

Then in render function you can parse this attribute using build in method:

$ids = $this->parseCommaSeparated($atts['ids']);

Edit configuration file as needed.

Integration with Laravel Debugbar

This packages supports Laravel Debugbar. Integration can be disabled in the config file if needed.

This project is fully free to use for any purpose and licensed under MIT License.

Using WordPress Media Library in Widgets options

So how to add WordPress media uploader popup to our custom widget?

That’s not so hard, hovewer there are a few caveats.

Let’s start from our simple widget class, I’d recommend to get example from https://codex.wordpress.org/Widgets_API#Example. Then we will need to add our new option, it will be called “image”. Just copy and paste fields in the “form” function, to render widget form and “update” function, to save this option.

I would recommend to catch php output buffer, it may be helpful if you will want to cache widget output. So our “widget” function will look like this:


	public function widget( $args, $instance ) {
		// Our variables from the widget settings
		$title = apply_filters( 'widget_title', empty( $instance['title'] ) ? __( 'Default title', 'text_domain' ) : $instance['title'] );
		$image = ! empty( $instance['image'] ) ? $instance['image'] : '';

		ob_start();
		echo $args['before_widget'];
		if ( ! empty( $instance['title'] ) ) {
			echo $args['before_title'] . $title . $args['after_title'];
		}
		?>

		<?php if($image): ?>
			<img src="<?php echo esc_url($image); ?>" alt="">
		<?php endif; ?>

		<?php
		echo $args['after_widget'];
		ob_end_flush();
	}

Our “form” function will be:


	public function form( $instance ) {
		$title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'New title', 'text_domain' );
		$image = ! empty( $instance['image'] ) ? $instance['image'] : '';
		?>
		<p>
			<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:' ); ?></label>
			<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>">
		</p>
		<p>
			<label for="<?php echo $this->get_field_id( 'image' ); ?>"><?php _e( 'Image:' ); ?></label>
			<input class="widefat" id="<?php echo $this->get_field_id( 'image' ); ?>" name="<?php echo $this->get_field_name( 'image' ); ?>" type="text" value="<?php echo esc_url( $image ); ?>" />
			<button class="upload_image_button button button-primary">Upload Image</button>
		</p>
		<?php
	}

And our update function:


	public function update( $new_instance, $old_instance ) {
		$instance = array();
		$instance['title'] = ( ! empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
		$instance['image'] = ( ! empty( $new_instance['image'] ) ) ? $new_instance['image'] : '';

		return $instance;
	}

As you can see, I’ve added a button underneath image input field with class “.upload_image_button”, but it will not work for now and to make it work we will need to add our custom admin javascript.

First what we need is to create our javascript file and put it into our theme, let’s create a file, called our_admin.js in assets/js under our theme folder.

Next we will need to register and enqueue our script to make it load in the admin panel, so lets add few lines to our widget class constructor function:


	function __construct() {

		// Add Widget scripts
		add_action('admin_enqueue_scripts', array($this, 'scripts'));

		parent::__construct(
			'our_widget', // Base ID
			__( 'Our Widget Title', 'text_domain' ), // Name
			array( 'description' => __( 'Our Widget with media files', 'text_domain' ), ) // Args
		);
	}

And we will need then “scripts” function in our widget class:


	public function scripts()
	{
		wp_enqueue_script( 'media-upload' );
		wp_enqueue_media();
		wp_enqueue_script('our_admin', get_template_directory_uri() . '/assets/js/our_admin.js', array('jquery'));
	}

As you can notice, we also added wp_enqueue_script( ‘media-upload’ ); and wp_enqueue_media(); to enqueue media library popup scripts.

And finally, here is our script, that will call WordPress media library popup and put selected image into the input field:


jQuery(document).ready(function ($) {

	$(document).on("click", ".upload_image_button", function (e) {
		e.preventDefault();
		var $button = $(this);


		// Create the media frame.
		var file_frame = wp.media.frames.file_frame = wp.media({
			title: 'Select or upload image',
			library: { // remove these to show all
				type: 'image' // specific mime
			},
			button: {
				text: 'Select'
			},
			multiple: false  // Set to true to allow multiple files to be selected
		});

		// When an image is selected, run a callback.
		file_frame.on('select', function () {
			// We set multiple to false so only get one image from the uploader

			var attachment = file_frame.state().get('selection').first().toJSON();

			$button.siblings('input').val(attachment.url);

		});

		// Finally, open the modal
		file_frame.open();
	});
});

So thats it, now, when you click on “Upload Image” button, WordPress media library popup will open and you will be able easily upload or select already uploaded image for widget options form.