Related
I'm trying to add a custom settings tab to the WooCommerce settings screen. Basically I want to achieve a similar thing to the Products settings tab, with the subsections/subtabs:
I haven't been able to find any decent documentation on how to do this but I've been able to add a custom tab using this snippet:
class WC_Settings_Tab_Demo {
public static function init() {
add_filter( 'woocommerce_settings_tabs_array', __CLASS__ . '::add_settings_tab', 50 );
}
public static function add_settings_tab( $settings_tabs ) {
$settings_tabs['test'] = __( 'Settings Demo Tab', 'woocommerce-settings-tab-demo' );
return $settings_tabs;
}
}
WC_Settings_Tab_Demo::init();
Based on what I've dug up from various threads/tutorials, I've been trying to add the sections/subtabs to the new settings tab something like this:
// creating a new sub tab in API settings
add_filter( 'woocommerce_get_sections_test','add_subtab' );
function add_subtab( $sections ) {
$sections['custom_settings'] = __( 'Custom Settings', 'woocommerce-custom-settings-tab' );
$sections['more_settings'] = __( 'More Settings', 'woocommerce-custom-settings-tab' );
return $sections;
}
// adding settings (HTML Form)
add_filter( 'woocommerce_get_settings_test', 'add_subtab_settings', 10, 2 );
function add_subtab_settings( $settings, $current_section ) {
// $current_section = (isset($_GET['section']) && !empty($_GET['section']))? $_GET['section']:'';
if ( $current_section == 'custom_settings' ) {
$custom_settings = array();
$custom_settings[] = array( 'name' => __( 'Custom Settings', 'text-domain' ),
'type' => 'title',
'desc' => __( 'The following options are used to ...', 'text-domain' ),
'id' => 'custom_settings'
);
$custom_settings[] = array(
'name' => __( 'Field 1', 'text-domain' ),
'id' => 'field_one',
'type' => 'text',
'default' => get_option('field_one'),
);
$custom_settings[] = array( 'type' => 'sectionend', 'id' => 'test-options' );
return $custom_settings;
} else {
// If not, return the standard settings
return $settings;
}
}
I've been able to add new subsections to the Products tab using similar code to the above, but it isn't working for my new custom tab. Where am I going wrong here?
1) To add a setting tab with sections, you can firstly use the woocommerce_settings_tabs_array filter hook:
// Add the tab to the tabs array
function filter_woocommerce_settings_tabs_array( $settings_tabs ) {
$settings_tabs['my-custom-tab'] = __( 'My custom tab', 'woocommerce' );
return $settings_tabs;
}
add_filter( 'woocommerce_settings_tabs_array', 'filter_woocommerce_settings_tabs_array', 99 );
2) To add new sections to the page, you can use the woocommerce_sections_{$current_tab} composite hook where {$current_tab} need to be replaced by the key slug that is set in the first function:
// Add new sections to the page
function action_woocommerce_sections_my_custom_tab() {
global $current_section;
$tab_id = 'my-custom-tab';
// Must contain more than one section to display the links
// Make first element's key empty ('')
$sections = array(
'' => __( 'Overview', 'woocommerce' ),
'my-section-1' => __( 'My section 1', 'woocommerce' ),
'my-section-2' => __( 'My section 2', 'woocommerce' )
);
echo '<ul class="subsubsub">';
$array_keys = array_keys( $sections );
foreach ( $sections as $id => $label ) {
echo '<li>' . $label . ' ' . ( end( $array_keys ) == $id ? '' : '|' ) . ' </li>';
}
echo '</ul><br class="clear" />';
}
add_action( 'woocommerce_sections_my-custom-tab', 'action_woocommerce_sections_my_custom_tab', 10 );
3) For adding the settings, as well as for processing/saving, we will use a custom function, which we will then call:
// Settings function
function get_custom_settings() {
global $current_section;
$settings = array();
if ( $current_section == 'my-section-1' ) {
// My section 1
$settings = array(
// Title
array(
'title' => __( 'Your title 1', 'woocommerce' ),
'type' => 'title',
'id' => 'custom_settings_1'
),
// Text
array(
'title' => __( 'Your title 1.1', 'text-domain' ),
'type' => 'text',
'desc' => __( 'Your description 1.1', 'woocommerce' ),
'desc_tip' => true,
'id' => 'custom_settings_1_text',
'css' => 'min-width:300px;'
),
// Select
array(
'title' => __( 'Your title 1.2', 'woocommerce' ),
'desc' => __( 'Your description 1.2', 'woocommerce' ),
'id' => 'custom_settings_1_select',
'class' => 'wc-enhanced-select',
'css' => 'min-width:300px;',
'default' => 'aa',
'type' => 'select',
'options' => array(
'aa' => __( 'aa', 'woocommerce' ),
'bb' => __( 'bb', 'woocommerce' ),
'cc' => __( 'cc', 'woocommerce' ),
'dd' => __( 'dd', 'woocommerce' ),
),
'desc_tip' => true,
),
// Section end
array(
'type' => 'sectionend',
'id' => 'custom_settings_1'
),
);
} elseif ( $current_section == 'my-section-2' ) {
// My section 2
$settings = array(
// Title
array(
'title' => __( 'Your title 2', 'woocommerce' ),
'type' => 'title',
'id' => 'custom_settings_2'
),
// Text
array(
'title' => __( 'Your title 2.2', 'text-domain' ),
'type' => 'text',
'desc' => __( 'Your description 2.1', 'woocommerce' ),
'desc_tip' => true,
'id' => 'custom_settings_2_text',
'css' => 'min-width:300px;'
),
// Section end
array(
'type' => 'sectionend',
'id' => 'custom_settings_2'
),
);
} else {
// Overview
$settings = array(
// Title
array(
'title' => __( 'Overview', 'woocommerce' ),
'type' => 'title',
'id' => 'custom_settings_overview'
),
// Section end
array(
'type' => 'sectionend',
'id' => 'custom_settings_overview'
),
);
}
return $settings;
}
3.1) Add settings, via the woocommerce_settings_{$current_tab} composite hook:
// Add settings
function action_woocommerce_settings_my_custom_tab() {
// Call settings function
$settings = get_custom_settings();
WC_Admin_Settings::output_fields( $settings );
}
add_action( 'woocommerce_settings_my-custom-tab', 'action_woocommerce_settings_my_custom_tab', 10 );
3.2) Process/save the settings, via the woocommerce_settings_save_{$current_tab} composite hook:
// Process/save the settings
function action_woocommerce_settings_save_my_custom_tab() {
global $current_section;
$tab_id = 'my-custom-tab';
// Call settings function
$settings = get_custom_settings();
WC_Admin_Settings::save_fields( $settings );
if ( $current_section ) {
do_action( 'woocommerce_update_options_' . $tab_id . '_' . $current_section );
}
}
add_action( 'woocommerce_settings_save_my-custom-tab', 'action_woocommerce_settings_save_my_custom_tab', 10 );
Result:
Based on:
Implement a custom WooCommerce settings page, including page sections
woocommerce/includes/admin/settings/
I am trying to create a WooCommerce plugin that returns a shipping cost for each product in a cart based on the following criteria:
The shipping destination zip code
The product's SKU
This what I have so far: it loads and activates but does not provide the shipping rate. I receive a message from the cart stating in effect that there are no shipping cost associated with the zone found.
/**
* Plugin Name: JxJ Shipping
* Description: Custom Shipping Method for WooCommerce
* Version: 1.0:
* License: GPL-3.0+
* License URI: http://www.gnu.org/licenses/gpl-3.0.html
* Domain Path: /lang
* Text Domain: jxj
*
* WC requires at least: 3.5
* WC tested up to: 4.0
*
*/
if ( ! defined( 'WPINC' ) ) {
die;
}//if not defined
/**
* Check if WooCommerce is active
*/
if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option(
'active_plugins' ) ) ) ) {
function jxj_shipping_method_init() {
if ( ! class_exists( 'WC_JxJ_Shipping_Method' ) ) {
class WC_JxJ_Shipping_Method extends WC_Shipping_Method {
/**
* Constructor for your shipping class
*
* #access public
* #return void
*/
public function __construct() {
$this->id = 'jxj_method';
$this->method_title = __( 'JxJ Shipping Method' );
$this->method_description = __( 'Custom Shipping Method for JuicedbyJ' );
$this->init();
$this->enabled = isset( $this->settings['enabled'] ) ? $this->settings['enabled'] : 'yes';
$this->title = isset( $this->settings['title'] ) ? $this->settings['title'] : __( 'jxj Shipping', 'jxj' );
}
/**
* Init your settings
*
* #access public
* #return void
*/
function init() {
$this->init_form_fields();
$this->init_settings();
add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
}
/**
* Define settings field for this shipping method
* #return void
*/
function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => __( 'Enable', 'jxj' ),
'type' => 'checkbox',
'description' => __( 'Enable this shipping.', 'jxj' ),
'default' => 'yes',
'class'=> 'WC_JxJ_Shipping_Method'
),
'title' => array(
'title' => __( 'Title', 'jxj' ),
'type' => 'text',
'description' => __( 'Title to be display on site', 'jxj' ),
'default' => __( 'jxj Shipping', 'jxj' ),
'class'=> 'WC_JxJ_Shipping_Method'
),
'packaging' => array(
'title' => array(
'title'=>__( '6 Pack (120z)', 'jxj' ),
'type' => 'checkbox',
'description' => __( 'Juice sold in package of 6 (12oz plastic bottles)', 'jxj' ),
'default' => 'yes',
'class'=> 'WC_JxJ_Shipping_Method'
),
'title' => array(
'title' => __( '24 Case (120z)', 'jxj' ),
'type' => 'checkbox',
'description' => __( 'Juice sold in case of 24 (12oz plastic bottles)', 'jxj' ),
'default' => 'yes',
'class'=> 'WC_JxJ_Shipping_Method'
),
'title' => array(
'title' => __( '3 Pack (750ml)', 'jxj' ),
'type' => 'checkbox',
'description' => __( 'Juice sold in package of 3 (750ml glass bottles)', 'jxj' ),
'default' => 'yes',
'class'=> 'WC_JxJ_Shipping_Method'
),
'title' => array(
'title' => __( '12 Case (750ml)', 'jxj' ),
'type' => 'checkbox',
'description' => __( 'Juice sold in case of 12 (750ml glass bottles)', 'jxj' ),
'default' => 'yes',
'class'=> 'WC_JxJ_Shipping_Method'
),
),
'weight' => array(
'title' => __( 'Weight (oz)', 'jxj' ),
'type' => 'number',
'description' => __( 'Maximum allowed weight', 'jxj' ),
'default' => 350,
'class'=> 'WC_JxJ_Shipping_Method'
),
/**Available regions*/
'regions' => array(
array(
'title' => __( 'Bangor', 'jxj' ),
'type' => 'checkbox',
'description' => __( 'Region of Bangor, ME rates', 'jxj' ),
'default' => 'yes',
'class'=> 'WC_JxJ_Shipping_Method'
),
array(
'title' => __( 'Hartford', 'jxj' ),
'type' => 'checkbox',
'description' => __( 'Region of Hartford, CT rates', 'jxj' ),
'default' => 'yes',
'class'=> 'WC_JxJ_Shipping_Method'
),
array(
'title' => __( 'Burlington', 'jxj' ),
'type' => 'checkbox',
'description' => __( 'Region of Burlington, VT rates', 'jxj' ),
'default' => 'yes',
'class'=> 'WC_JxJ_Shipping_Method'
),
array(
'title' => __( 'Atlanta', 'jxj' ),
'type' => 'checkbox',
'description' => __( 'Region of Atlanta, GA rates', 'jxj' ),
'default' => 'yes',
'class'=> 'WC_JxJ_Shipping_Method'
),
array(
'title' => __( 'Miami', 'jxj' ),
'type' => 'checkbox',
'description' => __( 'Region of Miami, FL rates', 'jxj' ),
'default' => 'yes',
'class'=> 'WC_JxJ_Shipping_Method'
),
array(
'title' => __( 'Jackson', 'jxj' ),
'type' => 'checkbox',
'description' => __( 'Region of Jackson, MS rates', 'jxj' ),
'default' => 'yes',
'class'=> 'WC_JxJ_Shipping_Method'
),
array(
'title' => __( 'Louisville', 'jxj' ),
'type' => 'checkbox',
'description' => __( 'Region of Louisville, KY rates', 'jxj' ),
'default' => 'yes',
'class'=> 'WC_JxJ_Shipping_Method'
),
array(
'title' => __( 'Cleveland', 'jxj' ),
'type' => 'checkbox',
'description' => __( 'Region of Cleveland, OH rates', 'jxj' ),
'default' => 'yes',
'class'=> 'WC_JxJ_Shipping_Method'
),
array(
'title' => __( 'Des Moines', 'jxj' ),
'type' => 'checkbox',
'description' => __( 'Region of Des Moines, IA rates', 'jxj' ),
'default' => 'yes',
'class'=> 'WC_JxJ_Shipping_Method'
),
array(
'title' => __( 'Madison', 'jxj' ),
'type' => 'checkbox',
'description' => __( 'Region of Madison, WI rates', 'jxj' ),
'default' => 'yes',
'class'=> 'WC_JxJ_Shipping_Method'
),
array(
'title' => __( 'Minneapolis', 'jxj' ),
'type' => 'checkbox',
'description' => __( 'Region of Minneapolis, MN rates', 'jxj' ),
'default' => 'yes',
'class'=> 'WC_JxJ_Shipping_Method'
),
array(
'title' => __( 'Chicago', 'jxj' ),
'type' => 'checkbox',
'description' => __( 'Region of Chicago, IL rates', 'jxj' ),
'default' => 'yes',
'class'=> 'WC_JxJ_Shipping_Method'
),
array(
'title' => __( 'New Orleans', 'jxj' ),
'type' => 'checkbox',
'description' => __( 'Region of New Orleans, LA rates', 'jxj' ),
'default' => 'yes',
'class'=> 'WC_JxJ_Shipping_Method'
),
array(
'title' => __( 'Little Rock', 'jxj' ),
'type' => 'checkbox',
'description' => __( 'Region of Little Rock, AR rates', 'jxj' ),
'default' => 'yes',
'class'=> 'WC_JxJ_Shipping_Method'
),
),
);
}
/**
* calculate_shipping function.
*
* #access public
* #param mixed $package
* #return void
*/
public function calculate_shipping( $package ) {
$packKey = '';
$cost = 0;
$zone = "";
foreach ( $package['contents'] as $item_id => $values )
{
$_product = $values['data'];
$price = $_product->get_price();
$packaging = $_product->get_sku();
$strPack = strval($packaging);
$strSize = strlen($packaging);
if ( $strSize == 9 ) {
return $packKey = substr($strPack, $strSize-1, 1);
} else {
return $packKey = substr($strPack, $strSize-2, 2);
}
$weight = $_product->get_weight();
$str_weight = strval($weight);
$zipcode = $package [ "destination" ][ "postcode" ];
$str_zip = strval($zipcode);
$subtotal = WC()->cart->get_cart_totals();
$shipZones = array (
"Bangor"=>array('04401','04402'),
"Burlington"=>array('05401','05402'),
"Hartford"=>array('06101','06012'),
"Atlanta"=>array('30301','30302'),
"Miami"=>array('33114','33109'),
"Jackson"=>array('39056','39174'),
"Loiusville"=>array('40018','40023'),
"Cleveland"=>array('44101','44103'),
"Des Moines"=>array('50211','50047'),
"Madison"=>array('53558','53562'),
"Minneapolis"=>array('55111','55401'),
"Chicago"=>array('60106','60131'),
"New Orleans"=>array('70032','70043'),
"Little Rock"=>array('72002','72103'),
);
/**
/*array("zone"=>'pack'=>cost)
*/
$zonePrices = array (
"Bangor"=>array('3'=>18.37,'12'=>46.54,'6'=>14.64,'24'=>29.08),
"Burlington"=>array('3'=>11.54,'12'=>26.62,'6'=>10.35,'24'=>15.46),
"Hartford"=>array('3'=>12.32,'12'=>30.57,'6'=>11.10,'24'=>17.57),
"Atlanta"=>array('3'=>18.37,'12'=>46.54,'6'=>14.64,'24'=>29.08),
"Miami"=>array('3'=>20.64,'12'=>58.16,'6'=>16.64,'24'=>37.74),
"Jackson"=>array('3'=>20.62,'12'=>58.16,'6'=>16.64,'24'=>37.74),
"Louisville"=>array('3'=>18.37,'12'=>46.54,'6'=>14.64,'24'=>29.08),
"Cleveland"=>array('3'=>13.69,'12'=>36.92,'6'=>12.04,'24'=>20.70),
"Des Moines"=>array('3'=>18.37,'12'=>46.54,'6'=>14.64,'24'=>29.08),
"Madison"=>array('3'=>18.37,'12'=>45.54,'6'=>14.64,'24'=>29.08),
"Minneapolis"=>array('3'=>18.37,'12'=>46.54,'6'=>14.64,'24'=>29.08),
"Chicago"=>array('3'=>18.37,'12'=>46.54,'6'=>14.64,'24'=>29.08),
"New Orleans"=>array('3'=>20.62,'12'=>58.16,'6'=>16.64,'24'=>37.74),
"Little Rock"=>array('3'=>20.62,'12'=>58.16,'6'=>16.64,'24'=>37.74)
);
$searchArray1 = [];
$searchArray2 = [];
$shipRate = 0;
$region = '';
$regionRef = '';
foreach ( $shipZones as $key => $value ) {
$searchArray1 = $value;
$regionRef = $key;
//find zipcode in value array
foreach ( $searchArray1 as $key => $value ) {
if ( $zipcode == $value ) {
$region = $regionRef;
foreach ( $zonePrices as $key => $value ) {
$searchArray2 = $value;
if ( $region == $key ) {
foreach ( $searchArray2 as $key => $value) {
if ( $packKey == $key ) {
$shipRate = round($value,2);
return $shipRate = sprintf('%.2f',$value);
}
}
}
}
} else {
return $shipRate = $price * 0.2;
}
}
}
$rate = array(
'id' => $this->id,
'label' => $this->title,
'cost' => $shipRate,
'calc_tax' => 'per_item'
);
$this->add_rate( $rate );
}
}
}
}
}
add_action( 'woocommerce_shipping_init', 'jxj_shipping_method_init' );
function add_jxj_shipping_method( $methods ) {
$methods['jxj_shipping_method'] = 'WC_JxJ_Shipping_Method';
return $methods;
}
add_filter( 'woocommerce_shipping_methods', 'add_jxj_shipping_method' );
}
I am trying to create some custom Divi builder modules.
I followed the sparse documentation at their website, trying to create a module and a child module. Everything seems to be working fine, but the rendering.
It is just rendering the module shortcode as a string, and not the content.
Current code of the parent module is
class DEDE_Cards extends ET_Builder_Module {
public function init(){
$this->name = esc_html__('Custom Card', 'dede-designvox-divi-extension');
$this->plural = esc_html__('Custom Cards', 'dede-designvox-divi-extension');
$this->main_css_element = 'cards-wrapper';
$this->slug = 'dede_cards';
$this->vb_support = 'on';
$this->child_slug = 'dede_card_item';
}
public function get_fields(){
return array(
'title' => array(
'label' => esc_html__( 'Title', 'dede-designvox-divi-extension' ),
'type' => 'text',
'toggle_slug' => 'main_content',
'description' => esc_html__( 'Type the section title' ),
),
'card_title_position' => array(
'label' => esc_html__( 'Title Position', 'dede-designvox-divi-extension' ),
'type' => 'select',
'options' => array(
'overlay' => esc_html__( 'Overlay', 'et_builder' ),
'top' => esc_html__( 'Over image', 'et_builder' ),
'bottom' => esc_html__( 'Under image', 'et_builder' ),
),
'toggle_slug' => 'main_content',
'description' => esc_html__( 'Here you can choose the position of the card title', 'dede-designvox-divi-extension' ),
'default_on_front' => 'bottom',
),
);
}
function before_render() {
global $dede_card_item_number;
$dede_card_item_number = 1;
}
public function render($unprocessed_props, $content = null, $render_slug ){
global $dede_card_item_number;
return sprintf(
'<div>%1$s</div>',
$this->content
);
}
public function add_new_child_text() {
return esc_html__( 'Add New Card Item1', 'dede-designvox-divi-extension' );
}
}
new DEDE_Cards;
And then the child module
class DEDE_Card_Item extends ET_Builder_Module {
public function init(){
$this->name = esc_html__('Custom Card', 'dede-designvox-divi-extension');
$this->plural = esc_html__('Custom Cards', 'dede-designvox-divi-extension');
$this->type= 'child';
$this->child_title_var = 'title';
$this->no_render = true;
$this->slug = 'dede_card_item';
$this->vb_support = 'on';
}
public function get_fields(){
return array(
'title' => array(
'label' => esc_html__('Title', 'dede-designvox-divi-extension'),
'type' => 'text',
'description' => esc_html__('The title of this card', 'dede-designvox-divi-extension'),
'toggle_slug' => 'main_content',
),
'desc' => array(
'label' => esc_html__( 'Description', 'dede-designvox-divi-extension' ),
'type' => 'textarea',
'description' => esc_html__( 'The card description' ),
'toggle_slug' => 'main_content',
),
'src' => array(
'label' => esc_html__( 'Image', 'dede-designvox-divi-extension'),
'type' => 'upload',
'description' => esc_html__( 'Upload your desired image, or type in the URL to the image', 'dede-designvox-divi-extension'),
'upload_button_text' => esc_attr__('Upload an image', 'dede-designvox-divi-extension'),
'choose_text' => esc_attr__('Choose an Image', 'dede-designvox-divi-extension'),
'update_text' => esc_attr__('Set as Image', 'dede-designvox-divi-extension'),
'affects' => 'alt',
'toggle_slug' => 'main_content',
),
'alt' => array(
'label' => esc_html__( 'Image Alternative Text', 'dede-designvox-divi-extension' ),
'type' => 'text',
'depends_show_if' => 'on',
'depends_on' => array(
'src',
),
'description' => esc_html__( 'This defines the HTML ALT text. A short description of your image can be placed here.', 'dede-designvox-divi-extension' ),
'toggle_slug' => 'main_content',
),
'url' => array(
'label' => esc_html__( 'Link URL', 'dede-designvox-divi-extension' ),
'type' => 'text',
'description' => esc_html__( 'Enter the link that you would like this card to direct to.', 'dede-designvox-divi-extension' ),
'toggle_slug' => 'main_content',
),
);
}
}
new DEDE_Card_Item;
The shortcode is just being rendered as a string on the website, like:
[dede_card_item _builder_version=”3.14″ title=”#1 card title” desc=”#1 card desc” src=”http://localhost:8888/wp-content/uploads/2018/09/14079861_1202408189819777_4296465020285869305_n.jpg” use_background_color_gradient=”off” background_color_gradient_start=”#2b87da” background_color_gradient_end=”#29c4a9″ background_color_gradient_type=”linear” background_color_gradient_direction=”180deg” background_color_gradient_direction_radial=”center” background_color_gradient_start_position=”0%” background_color_gradient_end_position=”100%” background_color_gradient_overlays_image=”off” parallax=”off” parallax_method=”on” background_size=”cover” background_position=”center” background_repeat=”no-repeat” background_blend=”normal” allow_player_pause=”off” background_video_pause_outside_viewport=”on” text_shadow_style=”none” module_text_shadow_style=”none” box_shadow_style=”none” /][dede_card_item _builder_version=”3.14″ title=”#1 card title” desc=”#1 card desc” src=”http://localhost:8888/wp-content/uploads/2018/09/14079861_1202408189819777_4296465020285869305_n.jpg” use_background_color_gradient=”off” background_color_gradient_start=”#2b87da” background_color_gradient_end=”#29c4a9″ background_color_gradient_type=”linear” background_color_gradient_direction=”180deg” background_color_gradient_direction_radial=”center” background_color_gradient_start_position=”0%” background_color_gradient_end_position=”100%” background_color_gradient_overlays_image=”off” parallax=”off” parallax_method=”on” background_size=”cover” background_position=”center” background_repeat=”no-repeat” background_blend=”normal” allow_player_pause=”off” background_video_pause_outside_viewport=”on” text_shadow_style=”none” module_text_shadow_style=”none” box_shadow_style=”none” /][dede_card_item _builder_version=”3.14″ title=”#1 card title” desc=”#1 card desc” src=”http://localhost:8888/wp-content/uploads/2018/09/14079861_1202408189819777_4296465020285869305_n.jpg” use_background_color_gradient=”off” background_color_gradient_start=”#2b87da” background_color_gradient_end=”#29c4a9″ background_color_gradient_type=”linear” background_color_gradient_direction=”180deg” background_color_gradient_direction_radial=”center” background_color_gradient_start_position=”0%” background_color_gradient_end_position=”100%” background_color_gradient_overlays_image=”off” parallax=”off” parallax_method=”on” background_size=”cover” background_position=”center” background_repeat=”no-repeat” background_blend=”normal” allow_player_pause=”off” background_video_pause_outside_viewport=”on” text_shadow_style=”none” module_text_shadow_style=”none” box_shadow_style=”none” /][dede_card_item _builder_version=”3.14″ title=”#1 card title” desc=”#1 card desc” src=”http://localhost:8888/wp-content/uploads/2018/09/14079861_1202408189819777_4296465020285869305_n.jpg” use_background_color_gradient=”off” background_color_gradient_start=”#2b87da” background_color_gradient_end=”#29c4a9″ background_color_gradient_type=”linear” background_color_gradient_direction=”180deg” background_color_gradient_direction_radial=”center” background_color_gradient_start_position=”0%” background_color_gradient_end_position=”100%” background_color_gradient_overlays_image=”off” parallax=”off” parallax_method=”on” background_size=”cover” background_position=”center” background_repeat=”no-repeat” background_blend=”normal” allow_player_pause=”off” background_video_pause_outside_viewport=”on” text_shadow_style=”none” module_text_shadow_style=”none” box_shadow_style=”none” /]
You just have to leave out the line $this->no_render = true; and then implement the function render in the child Module.
I try to create the same module to add child items inside module. But I have another problem, when I click add child item I get the empty popup ((( like this https://prnt.sc/156jfev. I tried the same code as author
it's working for me you can try it,
Parents modules::
<?php
class GRDI_Barchart extends ET_Builder_Module {
public $slug = 'grdi_bar_chart';
public $vb_support = 'on';
protected $module_credits = array(
'module_uri' => '',
'author' => '',
'author_uri' => '',
);
public function init() {
$this->name = esc_html__( 'Bar Chart', 'grdi-graphina-divi' );
$this->plural = esc_html__( 'Bar Chart', 'et_builder' );
$this->slug = 'grdi_bar_chart';
$this->vb_support = 'on';
$this->child_slug = 'grdi_bar_chart_child';
$this->settings_modal_toggles = array(
'general' => array(
'toggles' => array(
'main_content' => esc_html__( 'Graphina Text', 'dsm-supreme-modules-for-divi' ),
),
),
'advanced' => array(
'toggles' => array(
'separator' => array(
'title' => esc_html__( 'Separator', 'dsm-supreme-modules-for-divi' ),
'priority' => 70,
),
'image' => array(
'title' => esc_html__( 'Image', 'dsm-supreme-modules-for-divi' ),
'priority' => 69,
),
),
),
);
}
public function get_fields() {
return array(
'title' => array(
'label' => esc_html__( 'Title', 'grdi-graphina-divi' ),
'type' => 'text',
'option_category' => 'basic_option',
'description' => esc_html__( 'Input your desired heading here.', 'simp-simple-extension' ),
'toggle_slug' => 'main_content',
),
'content' => array(
'label' => esc_html__( 'Description', 'grdi-graphina-divi' ),
'type' => 'tiny_mce',
'option_category' => 'basic_option',
'description' => esc_html__( 'Content entered here will appear inside the module.', 'grdi-graphina-divi' ),
'toggle_slug' => 'main_content',
),
);
}
public function get_advanced_fields_config() {
return array();
}
public function get_charts(){
echo "charts";
}
public function render( $attrs, $content = null, $render_slug ) {
wp_enqueue_script( 'graphina_apex_chart_script' );
wp_enqueue_style( 'graphina_apex_chart_style' );
wp_enqueue_style( 'graphina-public' );
echo "<pre/>";
$var = "<script>
var options = {
series: [{
name: 'Sales',
data: [4, 3, 10, 9, 29, 19, 22, 9, 12, 7, 19, 5, 13, 9, 17, 2, 7, 5]
}],
chart: {
type: 'bar',
height: 350
},
plotOptions: {
bar: {
borderRadius: 4,
horizontal: true,
}
},
dataLabels: {
enabled: false
},
xaxis: {
categories: ['South Korea', 'Canada', 'United Kingdom', 'Netherlands', 'Italy', 'France', 'Japan',
'United States', 'China', 'Germany'
],
}
};
var chart = new ApexCharts(document.querySelector('#charts'), options);
chart.render();
</script>" ;
$html = sprintf(
'<h1>%1$s</h1>
<p>%2$s</p>
<div id="charts"></div>',
$this->props['title'],
$this->props['content']
);
echo $html ;
echo $var ;
}
}
new GRDI_Barchart;
Child Modules::
<?php
class GRDI_BarchartChild extends ET_Builder_Module {
function init() {
$this->name = esc_html__( 'Bar Chart Items', 'et_builder' );
$this->plural = esc_html__( 'Bar Chart Items', 'et_builder' );
$this->slug = 'grdi_bar_chart_child';
$this->vb_support = 'on';
$this->type = 'child';
$this->child_title_var = 'title';
$this->no_render = true;
$this->settings_text = esc_html__( 'Bar Chart Settings', 'et_builder' );
$this->settings_modal_toggles = array(
'general' => array(
'toggles' => array(
'main_content' => et_builder_i18n( 'Text' ),
),
),
'advanced' => array(
'toggles' => array(
'icon' => esc_html__( 'Icon', 'et_builder' ),
'toggle_layout' => esc_html__( 'Toggle', 'et_builder' ),
'text' => array(
'title' => et_builder_i18n( 'Text' ),
'priority' => 49,
),
),
),
);
}
function get_fields() {
$fields = array(
'child_title' => array(
'label' => et_builder_i18n( 'Data Label' ),
'type' => 'text',
'option_category' => 'basic_option',
'description' => esc_html__( 'Data Label', 'et_builder' ),
'toggle_slug' => 'main_content',
'dynamic_content' => 'text',
'hover' => 'tabs',
'mobile_options' => true,
),
'child_content' => array(
'label' => et_builder_i18n( 'Data Value' ),
'type' => 'text',
'option_category' => 'basic_option',
'description' => esc_html__( 'Data Value', 'et_builder' ),
'toggle_slug' => 'main_content',
'dynamic_content' => 'text',
'hover' => 'tabs',
'mobile_options' => true,
),
);
return $fields;
}
function render($attrs, $content, $render_slug){
$output = sprintf(
'<h1>%1$s</h1>
<p>%2$s</p>',
$this->props['child_title'],
$this->props['child_content']
);
return $output;
}
}
if ( et_builder_should_load_all_module_data() ) {
new GRDI_BarchartChild();
}
I was having similar issue to Mikael, where the child's setting looked like:
Just in case anyone is having similar issue, i realised its because the child's module wasn't being loaded. Since i was using a custom extension, there was a file called loader.phpin my extension that was responsible for loading the module files and it was loading the parent module file but skipping the child because of the pesky if statement with preg_match.
$module_files = glob( __DIR__ . '/modules/**/*.php' );
foreach ( (array) $module_files as $module_file ) {
if ( $module_file && preg_match( "/\/modules\/\b([^\/]+)\/\\1\.php$/", $module_file ) ) {
require_once $module_file;
}
}
if you replace it with:
foreach ( (array) $module_files as $module_file ) {
// if ( $module_file && preg_match( "/\/modules\/\b([^\/]+)\/\\1\.php$/", $module_file ) ) {
require_once $module_file;
//}
}
then it worked for me :)
Really hope that saves someone the 3 hours of debugging i spent.
I need help in generating new shipping method in woocommerce version 3+. The name for new field is "Nextday delivery". Like the flat rate it also need to be there in the method but it was not displayed in the drop down select field.
The below is the code which I tried. But it's not working for me.
function request_a_shipping_quote_init() {
if ( ! class_exists( 'WC_Request_Shipping_Quote_Method' ) ) {
class WC_Request_Shipping_Quote_Method extends WC_Shipping_Method {
public function __construct() {
$this->id = 'request_a_shipping_quote'; // Id for your shipping method. Should be uunique.
$this->method_title = __( 'Request a Shipping Quote' ); // Title shown in admin
$this->method_description = __( 'Shipping method to be used where the exact shipping amount needs to be quoted' ); // Description shown in admin
$this->title = "Request a Shipping Quote"; // This can be added as an setting but for this example its forced.
$this->supports = array(
'shipping-zones'
);
$this->init();
}
function init() {
$this->init_form_fields(); // This is part of the settings API. Override the method to add your own settings
$this->init_settings(); // This is part of the settings API. Loads settings you previously init.
add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
}
function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => __( 'Enable', 'dc_raq' ),
'type' => 'checkbox',
'description' => __( 'Enable this shipping method.', 'dc_raq' ),
'default' => 'yes'
),
'title' => array(
'title' => __( 'Title', 'dc_raq' ),
'type' => 'text',
'description' => __( 'Title to be displayed on site', 'dc_raq' ),
'default' => __( 'Request a Quote', 'dc_raq' )
),
);
}
public function calculate_shipping( $packages = array() ) {
$rate = array(
'id' => $this->id,
'label' => $this->title,
'cost' => '0.00',
'calc_tax' => 'per_item'
);
$this->add_rate( $rate );
}
}
}
}
add_action( 'woocommerce_shipping_init', 'request_a_shipping_quote_init' );
function request_shipping_quote_shipping_method( $methods ) {
$methods['request_shipping_quote_shipping_method'] = 'WC_Request_Shipping_Quote_Method';
return $methods;
}
add_filter( 'woocommerce_shipping_methods', 'request_shipping_quote_shipping_method' );
I need it to come in the dropdown like flatrate free shipping etc but it was not coming in the dropdown.
There were some missing things and others unnecessary. The correct way to make it work is:
add_action('woocommerce_shipping_init', 'request_shipping_quote_method');
function request_shipping_quote_method() {
if ( ! class_exists( 'WC_Request_Shipping_Quote_Method' ) ) {
class WC_Request_Shipping_Quote_Method extends WC_Shipping_Method {
public function __construct( $instance_id = 0) {
$this->id = 'request_shipping_quote';
$this->instance_id = absint( $instance_id );
$this->domain = 'rasq';
$this->method_title = __( 'Request a Shipping Quote', $this->domain );
$this->method_description = __( 'Shipping method to be used where the exact shipping amount needs to be quoted', $this->domain );
$this->supports = array(
'shipping-zones',
'instance-settings',
'instance-settings-modal',
);
$this->init();
}
## Load the settings API
function init() {
$this->init_form_fields();
$this->init_settings();
$this->enabled = $this->get_option( 'enabled', $this->domain );
$this->title = $this->get_option( 'title', $this->domain );
$this->info = $this->get_option( 'info', $this->domain );
add_action('woocommerce_update_options_shipping_' . $this->id, array($this, 'process_admin_options'));
}
function init_form_fields() {
$this->instance_form_fields = array(
'title' => array(
'type' => 'text',
'title' => __('Title', $this->domain),
'description' => __( 'Title to be displayed on site.', $this->domain ),
'default' => __( 'Request a Quote ', $this->domain ),
),
'cost' => array(
'type' => 'text',
'title' => __('Coast', $this->domain),
'description' => __( 'Enter a cost', $this->domain ),
'default' => '',
),
);
}
public function calculate_shipping( $packages = array() ) {
$rate = array(
'id' => $this->id,
'label' => $this->title,
'cost' => '0',
'calc_tax' => 'per_item'
);
$this->add_rate( $rate );
}
}
}
}
add_filter('woocommerce_shipping_methods', 'add_request_shipping_quote');
function add_request_shipping_quote( $methods ) {
$methods['request_shipping_quote'] = 'WC_Request_Shipping_Quote_Method';
return $methods;
}
Code goes in function.php file of your active child theme (active theme).
Tested and works.
Here the shipping method selector now displays this "Request a shipping coast" method:
Once selected and added, it's created this time:
If you edit it:
Good afternoon, I want to make simple copy of Cash on Delivery (COD) payment method in my store and rename it to Coupon on Delivery.
How to implement it?
Up
I have tried this code, but it shows error 500 on WC settings page:
<?php
/**
* Plugin Name: My New WooCommerce Gateway
* Plugin URI:
* Description: WooCommerce gateway to ....
* Author: .....
* Version: 1.0
* Author URI: https://example.org/
* Text Domain: woocommerce-my-gateway
* Domain Path: /languages/
*/
add_action( 'plugins_loaded', 'init_my_gateway_class' );
function init_my_gateway_class() {
if ( !class_exists( 'WooCommerce' ) ) return;
class WC_Gateway_COD_Renamed extends WC_Payment_Gateway {
}
}
function add_my_gateway_class( $methods ) {
$methods[] = 'WC_Gateway_my_gateway';
return $methods;
}
add_filter( 'woocommerce_payment_gateways', 'add_my_gateway_class' );
function my_load_textdomain(){
load_plugin_textdomain( 'woocommerce-my-gateway', false, dirname( plugin_dir_path( __FILE__ ) . '/languages/' ) );
}
add_action('plugins_loaded', 'my_load_textdomain');
Source of code
In your main plugin file you can include the class and filter the gateways at the same time:
function add_my_gateway_class( $methods ) {
include( 'class-wc-gateway-cod-renamed.php');
$methods[] = 'WC_Gateway_COD_Renamed';
return $methods;
}
add_filter( 'woocommerce_payment_gateways', 'add_my_gateway_class' );
There's no real need to check if WooCommerce is active this way as woocommerce_payment_gateways only exists if WooCommerce is running.
Then in another file called class-wc-gateway-cod-renamed.php you can define your class:
class WC_Gateway_COD_Renamed extends WC_Gateway_COD {
/**
* Setup general properties for the gateway.
*/
protected function setup_properties() {
$this->id = 'coupon-on-delivery';
$this->icon = apply_filters( 'woocommerce_coupon-on-deliver_icon', '' );
$this->method_title = __( 'Coupon on delivery', 'your-plugin' );
$this->method_description = __( 'Have your customers pay with a coupon upon delivery.', 'your-plugin' );
$this->has_fields = false;
}
/**
* Initialise Gateway Settings Form Fields.
*/
public function init_form_fields() {
$shipping_methods = array();
foreach ( WC()->shipping()->load_shipping_methods() as $method ) {
$shipping_methods[ $method->id ] = $method->get_method_title();
}
$this->form_fields = array(
'enabled' => array(
'title' => __( 'Enable/Disable', 'your-plugin' ),
'label' => __( 'Enable coupon on delivery', 'your-plugin' ),
'type' => 'checkbox',
'description' => '',
'default' => 'no',
),
'title' => array(
'title' => __( 'Title', 'your-plugin' ),
'type' => 'text',
'description' => __( 'Payment method description that the customer will see on your checkout.', 'your-plugin' ),
'default' => __( 'coupon on delivery', 'your-plugin' ),
'desc_tip' => true,
),
'description' => array(
'title' => __( 'Description', 'your-plugin' ),
'type' => 'textarea',
'description' => __( 'Payment method description that the customer will see on your website.', 'your-plugin' ),
'default' => __( 'Pay with coupon upon delivery.', 'your-plugin' ),
'desc_tip' => true,
),
'instructions' => array(
'title' => __( 'Instructions', 'your-plugin' ),
'type' => 'textarea',
'description' => __( 'Instructions that will be added to the thank you page.', 'your-plugin' ),
'default' => __( 'Pay with coupon upon delivery.', 'your-plugin' ),
'desc_tip' => true,
),
'enable_for_methods' => array(
'title' => __( 'Enable for shipping methods', 'your-plugin' ),
'type' => 'multiselect',
'class' => 'wc-enhanced-select',
'css' => 'width: 400px;',
'default' => '',
'description' => __( 'If coupon upon delivery is only available for certain methods, set it up here. Leave blank to enable for all methods.', 'your-plugin' ),
'options' => $shipping_methods,
'desc_tip' => true,
'custom_attributes' => array(
'data-placeholder' => __( 'Select shipping methods', 'your-plugin' ),
),
),
'enable_for_virtual' => array(
'title' => __( 'Accept for virtual orders', 'your-plugin' ),
'label' => __( 'Accept coupon if the order is virtual', 'your-plugin' ),
'type' => 'checkbox',
'default' => 'yes',
),
);
}
}
Extend the WC_Gateway_COD class so that you can inherit methods from it and only override the methods that have to do with the naming of things.
In WooCommerce plugin, you can enable payment gateway COD from admin section:
Admin >> WooCommerce >> Settings >> Checkout >> Cash on delivery.
Check option for enable COD.
Please refer below link for create offline payment gateway.
How to Create A WooCommerce Payment gateway