I have created a custom module in divi builder. Below given is the code:
function ex_divi_child_theme_setup() {
if ( class_exists('ET_Builder_Module')) {
class ET_Builder_Module_Image2 extends ET_Builder_Module {
function init() {
$this->name = __( 'Image_1', 'et_builder' );
$this->slug = 'et_pb_image2';
// a whole bunch of php code that defines how the class functions
}
}
$et_builder_module_image2 = new ET_Builder_Module_Image2();
add_shortcode( 'et_pb_image2', array($et_builder_module_image2, '_shortcode_callback') );
}
}
add_action('et_builder_ready', 'ex_divi_child_theme_setup');
I need to add fields to this custom module. How could i achieve this.
If you want to add your custom field in your custom module, you have to use "$this->whitelisted_fields" property and get_fields() function. ill give you some example that, how to add text field.
class ET_Builder_Module_Image2 extends ET_Builder_Module {
function init() {
$this->name = __( 'Image_1', 'et_builder' );
$this->slug = 'et_pb_image2';
// a whole bunch of php code that defines how the class functions
}
$this->whitelisted_fields = array(
'my_title',
);
function get_fields () {
$fields = array(
'my_title' => array(
'label' => __( 'My Title', 'wb' ),
'type' => 'text',
),
);
return $fields;
}
add your custom filed slug in whitelisted_fields propertys then add details in get_fields() function. i hope it will solve your problem.
Related
I'm using the Wordpress Plugin Boilerplate as foundation for my own plugin. In the admin area I intend to display data using the WP_List_Table class of Wordpress. I know I have to create my own child class to access it. Doing so is not the issue, however I get the following error:
Fatal error: Uncaught Error: Call to a member function render_screen_reader_content() on
During my research I discovered a few cases with the same issue (1, 2), but none of the solutions worked in my case.
Using the structure of the boilerplate, I created the child class in a file inside the includes folder:
if ( !class_exists( 'WP_List_Table' ) ) {
require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
}
if ( !class_exists( 'Hedwig_tables' ) ) {
class Hedwig_tables extends WP_List_Table {
private array $hd_columns;
private array $hd_data;
private array $hd_hidden;
private array $hd_sortable;
private array $hd_column_names;
public function __construct() {
//parent::__construct();
}
public function set_column_names(array $column_names) {
$this->hd_column_names = $column_names;
}
public function set_columns(array $columns) {
$this->hd_columns = $columns;
}
public function set_data(array $data) {
$this->hd_data = $data;
}
public function set_hidden(array $hidden) {
$this->hd_hidden = $hidden;
}
public function set_sortable(array $sortable) {
$this->hd_sortable = $sortable;
}
public function prepare_items() {
$this->_column_headers = array($this->hd_columns, $this->hd_hidden, $this->hd_sortable);
$this->items = $this->hd_data;
}
public function column_default( $item, $column_name ): mixed {
if (in_array($column_name, $this->hd_column_names)) {
return $item[ $column_name ];
}
return print_r($item, true);
}
}
}
The file is then loaded in the boilerplate's load_dependencies() function in class-plugin-name.php inside the includes folder.
In the boilerplate's class-plugin-name-admin.php (inside the admin folder) I created a function which generates the admin menu entry.
public function add_hedwig_page() {
$this->plugin_screen_hook_suffix = add_menu_page(
__( 'Hedwig Settings', 'Hedwig' ),
__( 'Hedwig Settings', 'Hedwig' ),
'manage_options',
$this->plugin_name,
array( $this, 'hedwig_admin_display_page' ),
'dashicons-buddicons-activity'
);
$this->plugin_screen_hook_suffix = add_submenu_page(
$this->plugin_name,
__( 'Hedwig Settings', 'Hedwig' ),
__( 'Hedwig Settings', 'Hedwig' ),
'manage_options',
$this->plugin_name,
array( $this, 'hedwig_admin_display_page' )
);
public function hedwig_admin_display_page() {
include_once 'partials/hedwig-admin-display.php';
}
Inside the display.php a function is called which I created inside the class-plugin-name-admin.php which creates the object for the child class of WP_List_Table.
public function get_data() {
$hedwig_list_table = new Hedwig_tables();
$sql = "SELECT id, value FROM y";
$results = $this->wpdb->get_results($sql, ARRAY_A);
if (count($results)<=0) {
?>
<div class="hedwig-msg-error"><?php _e('No data found.','Hedwig');?></div>
<?php
return false;
}
$hedwig_list_table->set_columns(
array(
'id' => __('ID','Hedwig'),
'value' => __('Art','Hedwig')
)
);
$hedwig_list_table->set_column_names(
array(
'id',
'value'
)
);
$hedwig_list_table->set_data($results);
$hedwig_list_table->set_hidden(array());
$hedwig_list_table->set_sortable(array());
$hedwig_list_table->prepare_items();
$hedwig_list_table->display();
return true;
}
Based on my aforementioned research the issue must be somewhere along the line of when the object for the child class is created (see this answer). I tried using add_actions() at different places (on __construct of the admin class, inside the run() function of the plugin-name.php trying to either load it after the menu items are generated or loading the class as a $GLOBALS. Everything I came up with failed. I used to create some smaller plugins without a boilerplate, but in this project I actually want to do the switch to this OOP and get new plugins kickstarted this way.
Update #1
Still got no solution, but I stumbled upon another solution which looked promising. However, using a function when creating the menu item for initialising the child class doesn't work either.
public function add_hedwig_page() {
$this->plugin_screen_hook_suffix = add_menu_page(
__( 'Hedwig Settings', 'Hedwig' ),
__( 'Hedwig Settings', 'Hedwig' ),
'manage_options',
$this->plugin_name,
function() {
$this->hedwig_list_table = new Hedwig_tables();
$this->hedwig_admin_display_page();
},
'dashicons-buddicons-activity'
);
$this->plugin_screen_hook_suffix = add_submenu_page(
$this->plugin_name,
__( 'Hedwig Settings', 'Hedwig' ),
__( 'Hedwig Settings', 'Hedwig' ),
'manage_options',
$this->plugin_name,
function() {
$this->hedwig_list_table = new Hedwig_tables();
$this->hedwig_admin_display_page();
}
);
public function hedwig_admin_display_page() {
include_once 'partials/hedwig-admin-display.php';
}
You shouldn't load this class like your custom classes since this is an extension of a core class and it has many more dependencies to rely on. Don't use add_action or $GLOBALS to initialize this class at all.
If you load it in boilerplate's load_dependencies() function in class-plugin-name.php inside the includes folder it will be instantiated too early and it will not function properly.
Instead, call it only when needed, inside your partials/hedwig-admin-display.php that you will use to output your markup for that page.
Something like this should work in your example:
<?php $table = new Hedwig_tables(); ?>
<h1>Hedwig_tables</h1>
<div class="wrap">
<div id="poststuff">
<div id="post-body" class="metabox-holder">
<div id="post-body-content">
<div class="meta-box-sortables ui-sortable">
<?php $table->prepare_items();?>
<form method="get">
<?php $table->display(); ?>
</form>
</div>
</div>
</div>
<br class="clear">
</div>
</div>
I thought Wordpress supports creating multiple widget instances in the same location but it looks like it does not in my code. I have created a plugin that shows recent posts. And in it I have created a widget that I want to be able to display multiple times in the same location.
class My_Recent_Posts_Widget extends WP_Widget {
function __construct() {
parent::__construct(
'recent_posts', // Base ID
esc_html__( 'Recent posts', 'text_domain' ), // Name
array( 'description' => esc_html__( 'Display posts via widgets', 'text_domain' ), ) // Args
);
}
And I register the widget like this;
function register_my_recent_posts_widget() {
register_widget( 'My_Recent_Posts_Widget' );
}
add_action( 'widgets_init', 'register_my_recent_posts_widget' );
The problem is if I try to place 2 instances of the same widget in the same location on the Widgets page in the admin the second widget does not show up.
Try this code
class My_Recent_Posts_Widget extends WP_Widget {
public function __construct() {
$widget_ops = array('classname' => 'my_widget_recent_entries', 'description' => esc_html__( "Your most recent Posts.",'text_domain') );
parent::__construct('my-recent-posts', esc_html__('My Recent Posts Widget','text_domain'), $widget_ops);
$this->alt_option_name = 'my_widget_recent_entries';
}
I'm using this tutorial (http://projects.tareq.co/wp-generator/index.php) and its creator to generate a WordPress CRUD administration. The problem, however, already arises at the point where I'm adding the new menu button. The code says
add_action('init', 'init_conference');
function init_conference () {
include(dirname(__FILE__).'/includes/class-conference-events-admin-menu.php');
$menu_dgvs = new Conference_Events_Admin_Menu();
}
Which seems to call the corresponant __construct in that class:
class Conference_Events_Admin_Menu {
public function __construct() {
add_action( 'admin_menu', array( $this, 'admin_menu' ) );
}
public function admin_menu() {
// menu that does work
add_menu_page(__('Watu PRO', 'watupro'), __('Watu PRO', 'watupro'), WATUPRO_MANAGE_CAPS, "watupro_exams", 'watupro_exams');
// menu that does not work
add_menu_page( __( 'Konferenz', '' ), __( 'Konferenz', '' ), '', 'conference', array( $this, 'plugin_page' ), 'dashicons-groups', null );
add_submenu_page( 'conference', __( 'Konferenz', '' ), __( 'Konferenz', '' ), '', 'conference', array( $this, 'plugin_page' ) );
}
// here's some more code that has nothing to do with the menu
}
The first add_menu_page() is copied over from another plugin, it is shown as it should. The second is copied from the generator. It shows nothing, as if these calls weren't present.
What am I getting wrong here? I can't find a difference between the add_menu call from the other plugin and the generated one from the generator.
Thanks in advance.
Work on a problem for 5 hours, no solution, post to stackoverflow => solution found: it was the capabilities field. 'manage_options' in parameter 3 and everything works.
Every time you try and set a custom/action topic within webhooks (from WooCommerce > Settings > Webhooks) it would unset it as soon as you update your changes to the webhook. In other words, it will undo your custom topic and return it back to 'Select an option' for the topic dropdown.
Any help at all is appreciated. Thank you very much!
edit: In addition to my comment below, I've also attempted to create my own custom topic via the following filter woocommerce_webhook_topic_hooks, however, it doesn't show within the dropdown list as an option.
The below code runs from functions.php as with any WordPress hook..
Code
function custom_woocommerce_webhook_topics( $topic ) {
$topic['order.refunded'] = array(
'woocommerce_process_shop_order_meta',
'woocommerce_api_edit_order',
'woocommerce_order_edit_status',
'woocommerce_order_status_changed'
);
return $topic;
}
add_filter( 'woocommerce_webhook_topic_hooks', 'custom_woocommerce_webhook_topics', 10, 1 );
edit 2: Added more context
I was having the same issue. Selecting any of the built-in topics worked fine. But selection Action and entering any WooCommerce Subscription actions kept reverting. I had also tried creating a new custom topic in the same file (wp-content/plugins/woocommerce-subscriptions/includes/class-wcs-webhooks.php) that the built-in topics are created, mirroring 1:1 the code of one of the topics that 'stick' (e.g subscription.created) for a new 'subscription.paymentcomplete' topic. It appears in the drop down, but after saving the drop-down reverts to the default 'Selection an option...'.
//wp-content/plugins/woocommerce-subscriptions/includes/class-wcs-webhooks.php
public static function init() {
...
add_action( 'woocommerce_subscription_created_for_order', __CLASS__ . '::add_subscription_created_callback', 10, 2 );
add_action( 'woocommerce_subscription_payment_complete', __CLASS__ . '::add_subscription_payment_complete_callback', 10, );
...
}
public static function add_topics( $topic_hooks, $webhook ) {
if ( 'subscription' == $webhook->get_resource() ) {
$topic_hooks = apply_filters( 'woocommerce_subscriptions_webhook_topics', array(
'subscription.created' => array(
'wcs_api_subscription_created',
'wcs_webhook_subscription_created',
'woocommerce_process_shop_subscription_meta',
),
'subscription.paymentcomplete' => array(
'wcs_webhook_subscription_payment_complete'
'woocommerce_process_shop_subscription_meta',
),
...
), $webhook );
}
return $topic_hooks;
}
public static function add_topics_admin_menu( $topics ) {
$front_end_topics = array(
'subscription.created' => __( ' Subscription Created', 'woocommerce-subscriptions' ),
'subscription.paymentcomplete' => __( ' Subscription Payment Complete', 'woocommerce-subscriptions' ),
...
);
return array_merge( $topics, $front_end_topics );
}
public static function add_subscription_created_callback( $order, $subscription ) {
do_action( 'wcs_webhook_subscription_created', $subscription->id );
}
public static function add_subscription_payment_complete_callback( $order, $subscription ) {
do_action( 'wcs_webhook_subscription_payment_complete', $subscription->id );
}
The solution was:
add_filter( 'woocommerce_valid_webhook_events', __CLASS__ . '::add_event', 10, 1 );
public static function add_event( $events) {
$events[] = 'paymentcomplete';
return $events;
}
I'm writing a plug-in for wordpress in classes and I'm adding an action hook to 'save_post' in the constructor of a class. However it does not seem to fire. Am I using it in the right way?
EDIT 25-05-2014 - I wrote a new (tested) minimal example that definitely reproduces the problem for me.
If I use the save_post in a procedural way (like directly in the index.php) it does work, but obviously that's not helpful when I'm structuring everything in classes.
/*
File index.php
This file handles the installation and bootstrapping of the plugin
*/
define("XX_POST_TYPE", 'testposttype');
if( !class_exists('MyPlugin') ):
class MyPlugin {
var $savecontroller;
public function __construct(){
add_action('init', array($this, 'init'), 1);
//include stuff before activation of theme
$this->include_before_theme();
}
//Include these before loading theme
private function include_before_theme(){
include_once("controllers/savecontroller.php");
}
public function init(){
register_post_type( XX_POST_TYPE,
array(
'labels' => array(
'name' => __('Tests'),
'singular_name' => __('Test'),
'add_new' => __('Add new test'),
'add_new_item' => __('Add new test')
),
'public' => true,
'has_archive' => true,
'hierarchical' => true
)
);
add_action('add_meta_boxes', function(){
$this->savecontroller = new SaveController();
});
}
}
function startup(){
global $myPlugin;
if( !isset($myPlugin) ){
$myPlugin = new MyPlugin();
}
return $myPlugin;
}
//Initialize
startup();
endif;
?>
The save actions happen in a different class and file.
<?php
// file savecontroller.php
class SaveController{
public function __construct(){
add_meta_box('xx_field_box', 'Field', array($this, 'setup_field'), XX_POST_TYPE);
}
public function setup_field( $post ){
?>
<input type="text" name="xx_custom_field" id="xx_custom_field" value="">
<?php
add_action('save_post', array($this, 'save_my_post'), 1, 1);
}
public function save_my_post($post_id){
if(isset($_POST['xx_custom_field'])){
update_post_meta($post_id, 'xx_custom_field', $_POST['xx_custom_field']);
}
}
}
?>
It does create my custom posttype and field so I know the classes are working. But the save_post is not triggered. It does not 'die()' and it does not do the 'update_post_meta()'. The custom field does appear in the POST request so the isset() checks out.
It's probably something dumb, but I can't get it to work.
You're trying to add the hook save_post inside the add_meta_box callback, and that's not the place for it.
To solve it, change the init method to
public function init(){
register_post_type( $args );
$this->savecontroller = new SaveController();
}
And modify the SaveController to
class SaveController{
public function __construct(){
add_action( 'add_meta_boxes', array( $this, 'meta_box' ) );
add_action( 'save_post', array( $this, 'save_my_post'), 10, 2 );
}
public function meta_box(){
add_meta_box( 'xx_field_box', 'Field', array($this, 'setup_field'), XX_POST_TYPE );
}
public function setup_field( $post ){
?>
<input type="text" name="xx_custom_field" id="xx_custom_field" value="">
<?php
}
public function save_my_post( $post_id, $post_object ){
wp_die( '<pre>'. print_r( $post_object, true) . '</pre>' );
}
}
Note that the save_post action takes two parameters and the priority can be default (10). You can find lots of examples for meta boxes and save_post here.