Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include custom templates in Elementor template library (Not My template) #5860

Closed
dinhtungdu opened this issue Oct 5, 2018 · 17 comments

Comments

Projects
None yet
@dinhtungdu
Copy link

commented Oct 5, 2018

Prerequisites

  • I have searched for similar features requests in both open and closed tickets and cannot find a duplicate.
  • The feature is still missing in the latest stable version of Elementor ( Elementor Pro. )

What problem is your feature request going to solve? Please describe.
Allow developers to include their custom templates/blocks in Elementor Template Library.

I know there are many issue about the custom library like #454 and #3127.. But those issue are about improving My templates. Mine is not about My templates, it's about to append templates to Elementor built-in library.

Describe the solution you'd like
My solution is very simple, just extending the data of the library. The idea here is adding custom template data to Elementor library data, host those templates on developer's server, and then allow template data can be download from there. By doing that, developers can include their custom template by a plugin or theme.

  • Library data is loaded from remote http://my.elementor.com/api/v1/info and save to elementor_remote_info_library key. We can alter this data by one of following:

    • Developer update that key manually, no change in Elementor source required. Get that option key, unserialize, add custom data, serialize, then save it again.
    • Add a filter to get_info_data function to allow developer include their custom data when Elementor update library or when user syncs the library manually.
  • Currently, Elementor downloads template from http://my.elementor.com/api/v1/templates/%d only. To support templates hosted on developer's server, we can add a filter to function get_template_content allows developer to hook in there and add their custom logic to retrieve template data from their server. IMO, only a filter on $url is needed. The developer job is providing an API that return similar response as Elementor API does.

@dinhtungdu dinhtungdu changed the title Extend Elementor Library. Include custom template/block in Elementor template library (Not My template) Include custom template/block in Elementor template library (Not My template) Oct 5, 2018

@dinhtungdu dinhtungdu changed the title Include custom template/block in Elementor template library (Not My template) Include custom templates in Elementor template library (Not My template) Oct 5, 2018

@dinhtungdu

This comment has been minimized.

Copy link
Author

commented Oct 5, 2018

Ps: I'm working on the implementation of my solution btw, post it here for discussing first.

@stevecove

This comment has been minimized.

Copy link

commented Oct 6, 2018

This would be great, especially if it allowed us as theme Devs to filter out the existing prebuilt templates. It's one of the main hurdles we have (along with being able to create custom widgets with drop zones aka custom sections) in bringing elementor into our larger projects.

@dinhtungdu

This comment has been minimized.

Copy link
Author

commented Oct 7, 2018

Here is what I got so far. I'm able to list and import my custom templates

I can include my custom templates in template list of Elementor: http://prntscr.com/l32jqh. Currently I'm using a function that get library data from Elementor, then I add my templates to it before save to elementor_remote_info_library option.

Because Elementor only download template data from its server, we need a filter to tell it where to download our template. I did it by modifying elementor/includes/api.php:

public static function get_template_content( $template_id ) {
	$url = sprintf( self::$api_get_template_content_url, $template_id );
	$url = apply_filters( 'elementor/api/get_templates/url', $url, $template_id );
	...
}

Then I add a filter base on $template_id to return my correct url. Something like this:

add_filter( 'elementor/api/get_templates/url', function ( $url, $template_id ) {
	...
}, 10, 2 );

Listing and inserting template work perfectly!

@bainternet

This comment has been minimized.

Copy link
Collaborator

commented Oct 7, 2018

@dinhtungdu

Thanks for the PR, but currently we have different Ideas for Template Library and this will conflict with them.

thanks again.

@bainternet bainternet closed this Oct 7, 2018

@dinhtungdu

This comment has been minimized.

Copy link
Author

commented Oct 7, 2018

Can we have some detail about your idea?

@dinhtungdu

This comment has been minimized.

Copy link
Author

commented Oct 8, 2018

@bainternet Do you have any roadmap or plan to release this feature? I'm very happy to help with this.

@ihsansahab

This comment has been minimized.

Copy link

commented Oct 20, 2018

Here is what I got so far. I'm able to list and import my custom templates

I can include my custom templates in template list of Elementor: http://prntscr.com/l32jqh. Currently I'm using a function that get library data from Elementor, then I add my templates to it before save to elementor_remote_info_library option.

Because Elementor only download template data from its server, we need a filter to tell it where to download our template. I did it by modifying elementor/includes/api.php:

public static function get_template_content( $template_id ) {
	$url = sprintf( self::$api_get_template_content_url, $template_id );
	$url = apply_filters( 'elementor/api/get_templates/url', $url, $template_id );
	...
}

Then I add a filter base on $template_id to return my correct url. Something like this:

add_filter( 'elementor/api/get_templates/url', function ( $url, $template_id ) {
	...
}, 10, 2 );

Listing and inserting template work perfectly!

very great
i try editing but not show template in my library

@juanpasolano

This comment has been minimized.

Copy link

commented Nov 6, 2018

This is the only thing keeping me from using Elementor for my clients.
I'd love to hand off the theme with a bunch of Blocks that where custom designed for them. This would be a fantastic edition for devs and a extremely nice UX for the client.
Thank you

@tomasvanrijsse

This comment has been minimized.

Copy link

commented Nov 29, 2018

@bainternet can you send us in the right direction how we should add blocks or templates programmatically to our projects?
At the moment the only way seems to export templates and remember to upload/update them all by hand.

@pulla

This comment has been minimized.

Copy link

commented Dec 24, 2018

@bainternet Yes, please can you please give us a little more details? It will be very useful for developers and clients.

Thank you,

@simopetrelli

This comment has been minimized.

Copy link

commented Feb 19, 2019

@bainternet Any update here?

@davelavoie

This comment has been minimized.

Copy link

commented Mar 20, 2019

@dinhtungdu @juanpasolano @simopetrelli @stevecove @ihsansahab @tomasvanrijsse @pulla

There is no need to wait, we can already do what you're asking for since a while. You simply need to do it differently. Here's an example for filtering all pro templates from the list. But basically, you could append new templates the same way.

Simply add the following in your functions.php file (or build a plugin with it if needed) and edit it as needed:

add_action( 'pre_update_option_elementor_remote_info_library', 'hide_pro_templates', 10, 3 );

    /**
     * Hide pro templates from the list of available templates.
     *
     * @param  array  $value  The new, unserialized option value.
     * @return array  $value  The filtered value, with Elementor Pro templates excluded.
     */
function hide_pro_templates( $value ) {
	if ( ! empty( $value['templates'] ) ) {
		// CHANGE THE LIST OF TEMPLATES HERE
		$normal_templates = wp_list_filter( $value['templates'], array( 'is_pro' => '1' ), 'NOT' );
		if ( ! empty( $normal_templates ) ) {
			$value['templates'] = $normal_templates;
		}
	}
	return $value;
}

Like I said, in this example, I'm removing the pro templates from the library, but it's just so you can see what can be done. Simply use var_dump( $value ) to see how the data is displayed, and add your custom templates by modifying the value of $value['templates'].

In order to see the changes in the library, you might need to refresh it by pressing on the refresh button, since the array is edited when updating the 'elementor_remote_info_library' option (which is updated when refreshing the templates).

@sf-steve

This comment has been minimized.

Copy link

commented Mar 21, 2019

@davelavoie Cool, that works nicely to filter out the prebuilt templates. Any clue on adding our own? I can obviously add meta data to the templates array, but not sure how to get Elementor to actually load the template data (from local file, or our own servers)?

@dinhtungdu

This comment has been minimized.

Copy link
Author

commented Mar 21, 2019

but not sure how to get Elementor to actually load the template data (from local file, or our own servers).

@sf-steve Elementor loads template data from their server, you can see my rejected PR above.

@davelavoie Your idea is great! I didn't think about pre_update_option_ hook. Thanks! I will write a blog on this issue, can I use your idea?

@davelavoie

This comment has been minimized.

Copy link

commented Mar 21, 2019

@dinhtungdu Sure, feel free to use this idea! If you want, you can give me credit by mentioning my name with a link pointing to the URL displayed on my GitHub profile :-)

@sf-steve Well, since you can override the whole list of templates with the hook I've shared, you could technically fetch templates from your own source using wp_remote_get. You just need to make sure the data returned has the same format as the one used by the default source. To see how the default data is formatted, open the console in Chrome, click on the "Sync Library" button, and inspect the request (see attached screenshot for an example)

data

This is not the only way to do it though, but this is clearly the easiest way.

By the way it's already possible to replace the default remote source with your own, and it has been possible for many years. I've once replaced the default source with my own on a WP multisite environment, all templates were saved on the main site (with blog ID = 1), and all subsites were able to fetch the list of saved templates from the main site instead of fetching them from the default source.

I might eventually release a plugin that allows anyone to replace the default remote source with their own source if I have enough time, but meanwhile, for those who want to get started, you can do the following:

add_action( 'elementor/init', 'register_custom_remote_source' );

/**
 * Basically Replace Default Remote source with a custom one.
 */
function register_custom_remote_source() {
	// Deregister the default remote source first. Not sure that this is particularly needed but better be safe than sorry.
	\Elementor\Plugin::instance()->templates_manager->unregister_source( 'remote' );

	// Then include your own source which will have the "remote" id.
	\Elementor\Plugin::instance()->templates_manager->register_source( 'Elementor\TemplateLibrary\Custom_Remote_Source' );
}

Then, you must create a class for your custom source. You can see how the current sources are built by taking a look at the remote.php, local.php and base.php files found in the /elementor/includes/template-library/sources/ directory. The simplest would probably be to copy the whole Source_Remote class, changing its name for Custom_Remote_Source, and then edit the methods of the class so it works as you want. For my multisite solution, my custom source is a mix of modified methods found in remote.php and local.php files.

Your custom source should be defined this way (this is not a complete example, and it's not tested!):

<?php
namespace Elementor\TemplateLibrary;

use Elementor\Api;
use Elementor\Plugin;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Elementor template library remote source.
 *
 * Elementor template library remote source handler class is responsible for
 * handling remote templates from Elementor.com servers.
 *
 * @since 1.0.0
 */
class Custom_Remote_Source extends Source_Base {

	/**
	 * Get remote template ID.
	 *
	 * Retrieve the remote template ID.
	 *
	 * @since 1.0.0
	 * @access public
	 *
	 * @return string The remote template ID.
	 */
	public function get_id() {
		return 'remote'; // IMPORTANT: don't change this value.
	}

	/**
	 * Get remote template title.
	 *
	 * Retrieve the remote template title.
	 *
	 * @since 1.0.0
	 * @access public
	 *
	 * @return string The remote template title.
	 */
	public function get_title() {
		return __( 'Remote', 'elementor' ); // You can change this value if you want
	}

	/**
	 * Register remote template data.
	 *
	 * Used to register custom template data like a post type, a taxonomy or any
	 * other data.
	 *
	 * @since 1.0.0
	 * @access public
	 */
	public function register_data() {
		// Anything in this method will be executed on every page load.
	}

	/**
	 * Get remote templates.
	 *
	 * Retrieve remote templates from Elementor.com servers.
	 *
	 * @since 1.0.0
	 * @access public
	 *
	 * @param array $args Optional. Filter templates list based on a set of
	 *                    arguments. Default is an empty array.
	 *
	 * @return array Remote templates.
	 */
	public function get_items( $args = [] ) {
		// This is where you will fetch the data from your custom source!
		// Compare this method in the 'remote.php' and 'local.php' files so you can 
		// see what can be done here. You can fetch anything from an 
		// external source, or even build your own WP Query.
		$templates = array();

		// Populate the $templates var with anything you want here.

		return $templates;
	}

	/**
	 * Get remote template.
	 *
	 * Retrieve a single remote template from a custom source.
	 *
	 * @since 1.0.0
	 * @access public
	 *
	 * @param int $template_id The template ID.
	 *
	 * @return array Remote template.
	 */
	public function get_item( $template_id ) {
		// This is where you must make sure the data from a specific template is processed correctly
		// based on your custom remote source. Make sure to fill the values expected in the array!

		$data = [
			'template_id' => $template_id,
			'source' => $this->get_id(),
			'type' => 'block', // value expected: block, page, popup...
			'title' => 'NAME OF THE TEMPLATE',
			'thumbnail' => 'YOUR THUMBNAIL URL',
			'date' => 'THE DATE',
			'human_date' => date_i18n( get_option( 'date_format' ), 'THE DATE' ),
			'author' => 'AUTHOR NAME',
			'hasPageSettings' => false, // expect true or false based on your needs
			'tags' => array(),
			'export_link' => $this->get_export_link( $template_id ), 
			'url' => 'YOUR TEMPLATE URL',
		];
		return $data;
	}

	/**
	 * Get remote template data.
	 *
	 * Retrieve the data of a single remote template from a custom source.
	 *
	 * @since 1.5.0
	 * @access public
	 *
	 * @param array  $args    Custom template arguments.
	 * @param string $context Optional. The context. Default is `display`.
	 *
	 * @return array Remote Template data.
	 */
	public function get_data( array $args, $context = 'display' ) {
		// You should take a look at the local.php and remote.php files to see what must be done here.

		return $data;
	}
}

Now, you have everything you need to override the default remote source ;-)

@michaelpratt-swervepoint

This comment has been minimized.

Copy link

commented May 14, 2019

It would be great if we got a plugin for this. Where we could just enter the path to the server, and then save our templates in json format there, with an option to override the default template blocks and pages.

@davelavoie

This comment has been minimized.

Copy link

commented May 16, 2019

It would be great if we got a plugin for this. Where we could just enter the path to the server, and then save our templates in json format there, with an option to override the default template blocks and pages.

I plan to create this kind of plugin, I just didn't have the time yet. I'll update this thread once it's available (though I can't tell if it's going to take just a few weeks or a few months right now)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.