I added this class to my plugin directory, but when I refresh my dashboard, the admin page doesn't show up and I do not get any errors. Am I doing something wrong in the __construct() method?
class AA_Admin_Page {
/**
* Title of the page.
*/
public $page_title;
/**
* Text to be used for the menu.
*/
public $menu_title;
/**
* Unique slug for the menu page.
*/
public $slug;
function __construct() {
$this->$page_title = __( 'AA Plugin Page', 'AA-plugin' );
$this->$menu_title = __( 'AA Plugin Page', 'AA-plugin' );
$this->slug = 'aa_admin_page';
$this->render_page();
}
public function render_page() {
add_action( 'admin_init', [ $this, 'aa_admin_page' ] );
}
public function aa_admin_page() {
add_menu_page(
$this->$page_title,
$this->$menu_title,
'manage_options',
$this->$slug,
[ $this, 'admin_page_callback' ],
);
}
public function admin_page_callback() {
echo "This page works!";
}
}
new AA_Admin_Page();
Related
I have created 2 basic shipping methods in 2 different plugins, each plugin are below, one is Royal Mail the other is Courier. They both show up in the drop down in the shipping zone:
I can then add say Royal Mail to the zone, but if i now come to add Courier as well, Royal Mail disappears and vice versa, it's only letting me add one of my custom methods at a time and i'm stumped as to why.
The next problem is, when i delete one of my custom methods and hit save, i'm getting this fatal error and it doesn't remove, as far as i can see both of these classes are done correctly to the point they are at:
[14-Dec-2021 13:54:59 UTC] PHP Fatal error: Uncaught Error: Call to a
member function get_instance_option_key() on bool in
/Volumes/Work/project/public_html/wp-content/plugins/woocommerce/includes/class-wc-ajax.php:2923
add_action( 'woocommerce_shipping_init', function() : void {
/**
* Class Utterly_Courier_Shipping_Method
*/
class Utterly_Courier_Shipping_Method extends WC_Shipping_Method
{
/**
* Utterly_Royal_Mail_Shipping_Method constructor.
*/
public function __construct()
{
$this->id = 'utterly_courier';
$this->method_title = 'Courier delivery (Tracked & Signed)';
$this->method_description = 'Shipping via Courier';
$this->supports = [
'shipping-zones'
];
$this->init();
$this->enabled = 'yes';
$this->title = 'Courier delivery (Tracked & Signed)';
}
/**
*
*/
public function init() : void
{
$this->init_form_fields();
$this->init_settings();
// Save settings in admin if you have any defined
add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
}
/**
*
*/
public function init_form_fields() : void
{
parent::init_form_fields();
}
/**
* #param array $package
*/
public function calculate_shipping($package = [])
{
$rate = array(
'id' => $this->id,
'label' => $this->title,
'cost' => 10
);
$this->add_rate( $rate );
}
}
});
add_filter( 'woocommerce_shipping_methods', function( array $methods ) : array {
$methods['utterly_courier'] = 'Utterly_Courier_Shipping_Method';
return $methods;
});
add_action( 'woocommerce_shipping_init', function() : void {
/**
* Class Utterly_Royal_Mail_Shipping_Method
*/
class Utterly_Royal_Mail_Shipping_Method extends WC_Shipping_Method
{
/**
* Utterly_Royal_Mail_Shipping_Method constructor.
*/
public function __construct()
{
$this->id = 'utterly_royal_mail';
$this->method_title = 'Royal Mail 1st Class (Tracked)';
$this->method_description = 'Shipping via Royal Mail';
$this->supports = [
'shipping-zones'
];
$this->init();
$this->enabled = 'yes';
$this->title = 'Royal Mail 1st Class (Tracked)';
}
/**
*
*/
public function init() : void
{
$this->init_form_fields();
$this->init_settings();
// Save settings in admin if you have any defined
add_action( 'woocommerce_update_options_shipping_' . $this->id, [ $this, 'process_admin_options' ] );
}
/**
*
*/
public function init_form_fields() : void
{
parent::init_form_fields();
}
/**
* #param array $package
*/
public function calculate_shipping($package = [])
{
$rate = array(
'id' => $this->id,
'label' => $this->title,
'cost' => 10
);
$this->add_rate( $rate );
}
}
});
add_filter( 'woocommerce_shipping_methods', function( array $methods ) : array {
$methods['utterly_royal_mail'] = 'Utterly_Royal_Mail_Shipping_Method';
return $methods;
});
I'm currently working on a custom shipping method for WooCommerce. The goal is to calculate the shipping based on the adress the customer enters in the order process. We currently have an API that receives a storeId and the adress of a customer and returns back the exact amount of shipping we need to apply to the order.
For this, I've started to write a new custom shipping order plugin. I am already receiving the $packages array with the order, however I can't seem to find a way to receive the customers adress in the calculate_shipping method. There also will be a useraction required to select the prefered warehouse on the reviewOrderBeforePayment page and I am not quite sure how to access that data yet.
<?php
/*
* Plugin Name: Warehouses Integration
* Description: WooCommerce integration of the Warehouses API
* Version: 1.1.0
* Author: -
* Author URI: -
* Developer: Laura Heimann
* Developer URI: -
* Text Domain: woocommerce-extension
* WC requires at least: 4.0.1
* WC tested up to: 4.0.1
*/
// Security Measure
if (!defined('ABSPATH')) {
exit;
}
// Check if WooCommerce is installed
if (!in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option( 'active_plugins')))) {
alert("WooCommerce is not installed!");
}
// Main Render Function
// This will be hooked into the WooCommerce Order Page
function wcfw_render() {
// TODO: Show List of possible stores, let user select and save selected store somehow
echo "WCFWRENDER";
}
function wcfw_renderThankYou() {
echo "WCFWTHANKYOU";
}
function wcfw_renderReviewOrder() {
// TODO: Show warning if items from different stores
echo "WCFWREVIEWORDER";
}
function wcfw_shippingMethodInit() {
if ( ! class_exists( 'WC_WCFW_Shipping_Method' ) ) {
class WC_WCFW_Shipping_Method extends WC_Shipping_Method {
/**
* Constructor for your shipping class
*
* #access public
* #return void
*/
public function __construct() {
$this->id = 'wcfw_shipping_method';
$this->title = __( 'Warehouses Shipping' );
$this->method_description = __( 'Shipping Method through the Warehouse' );
$this->enabled = "yes";
$this->init();
}
/**
* Init your settings
*
* #access public
* #return void
*/
function init() {
// Load the settings API
$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.
// Save settings in admin if you have any defined
add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
}
/**
* Settings
*/
function init_form_fields() {
$this->form_fields = array(
'apiBase' => array(
'title' => __('Api Base'),
'type' => 'text',
'description' => __('The base URL for API-Calls.'),
'default' => __('---')
),
);
}
/**
* calculate_shipping function.
*
* #access public
* #param mixed $package
* #return void
*/
public function calculate_shipping( $package = array() ) {
var_dump( $package );
// TODO: Get Customers Adress and selected store
// TODO: Send data to API and apply provided shipping
$rate = array(
'label' => __('Shipping by Truck'),
'cost' => '10.99',
'calc_tax' => 'per_item'
);
// Register the rate
$this->add_rate( $rate );
}
}
}
}
function add_wcfw_shipping_method( $methods ) {
$methods[] = 'WC_WCFW_Shipping_Method';
return $methods;
}
// Hooks
add_action('woocommerce_review_order_before_payment', 'wcfw_render', 10);
add_action('woocommerce_thankyou', 'wcfw_renderThankYou', 10);
add_action('woocommerce_after_cart_contents', 'wcfw_renderReviewOrder', 10);
add_action('woocommerce_shipping_init', 'wcfw_shippingMethodInit');
add_filter('woocommerce_shipping_methods', 'add_wcfw_shipping_method');
Now I'm developing a new WebSite using WordPress.
I don't know how to use widgets.
I tried to search on google so I found some answer.
Here is my code.
class WP_Widget_Home extends WP_Widget {
/**
* Sets up the widgets name etc
*/
public function __construct()
{
parent::__construct('id_widget_home',
__('(TrueLove) [PAGE] Home', 'TrueLove'),
array('description' => __('Intro page.', 'TrueLove')));
}
/**
* Outputs the content of the widget
*
* #param array $args
* #param array $instance
*/
public function widget( $args, $instance ) {
// outputs the content of the widget
echo "<h1>I like U!</h1>";
the_content();
}
...
function registerHomeWidgetFunc()
{
return register_widget("WP_Widget_Home");
}
add_action('widgets_init', 'registerHomeWidgetFunc');
I can insert (TrueLove) [Page] Home widget on WidgetPage('wp-admin/widgets.php').
That's all.
How can I use this?
I used the code below (as provided by woocommerce API) to add custom Shipping Method and it is working but now I want to add another shipping method I tried copy pasting same code with different class name but it doesn't work actually the second method is replacing the first one
I want to know how can I create another Shipping method?
Thank you
function your_shipping_method_init() {
if ( ! class_exists( 'WC_Your_Shipping_Method' ) ) {
class WC_Your_Shipping_Method extends WC_Shipping_Method {
/**
* Constructor for your shipping class
*
* #access public
* #return void
*/
public function __construct() {
$this->id = 'vip_rate'; // Id for your shipping method. Should be uunique.
$this->method_title = __( 'VIP Shipping Rate' ); // Title shown in admin
$this->method_description = __( '$35 flate rate' ); // Description shown in admin
$this->enabled = "yes"; // This can be added as an setting but for this example its forced enabled
$this->title = "VIP Shipping rate"; // This can be added as an setting but for this example its forced.
$this->init();
}
/**
* Init your settings
*
* #access public
* #return void
*/
function init() {
// Load the settings API
$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.
// Save settings in admin if you have any defined
add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
}
/**
* calculate_shipping function.
*
* #access public
* #param mixed $package
* #return void
*/
public function calculate_shipping( $package ) {
$cost=35;
$rate = array(
'id' => $this->id,
'label' => $this->title,
'cost' => round($cost,2),
'calc_tax' => 'per_item'
);
// Register the rate
$this->add_rate( $rate );
}
}
}
}
add_action( 'woocommerce_shipping_init', 'your_shipping_method_init' );
function add_your_shipping_method( $methods ) {
$methods[] = 'WC_Your_Shipping_Method';
return $methods;
}
add_filter( 'woocommerce_shipping_methods', 'add_your_shipping_method' );
I'm having the same issue , my solution was made a new class who extends from WC_Shipping_Method and keep all the same code there and i made 3 new classes extending the new one , any one with their own ID and mothod type
Its not the best solution but its more legant than duplicate N times the same code of the class
OK I have succeeded in adding another Shipping method by renaming Class name.Previously I may be doing something wrong
However I would like to know if there was some better way of doing it because I have copy pasted whole chunk of code twice , My background is not in OOP however I think it is not the proper way of doing this thing
I have this relationship in my SS3 project:
Restaurant many_many Cuisine
Cuisine many_many SubCuisine
Seems simple enough but I can't seem to find any way to administer it. Tried GridField and Listbox. Is this a limitation of SilverStripe perhaps?
Thanks for any leads!
Wilson
After our conversation on IRC we came up with the following alternative solution, which I will post here for the record.
This solution is quiet similar to the original answer, with the difference, that there is an additional object that handles the relation between Restaurant and Cuisine.
File: Restaurant.php
/**
* #method ManyManyList RestaurantCuisines
*/
class Restaurant extends Page {
private static $many_many = array(
'RestaurantCuisines' => 'RestaurantCuisine',
);
/**
* #return FieldList
*/
public function getCMSFields() {
$return = parent::getCMSFields();
$return->addFieldToTab('Root', Tab::create('Cuisines', 'The Cuisines'));
$return->addFieldToTab(
'Root.Cuisines',
GridField::create(
'RestaurantCuisines',
'The Cuisines this Restaurant offers',
$this->RestaurantCuisines(),
GridFieldConfig_RecordEditor::create()
)
);
return $return;
}
}
class Restaurant_Controller extends Page_Controller {
}
File: RestaurantCuisine.php
/**
* #property int CuisineID
* #method Cuisine Cuisine
* #method ManyManyList SubCuisines
*/
class RestaurantCuisine extends DataObject {
private static $has_one = array(
'Cuisine' => 'Cuisine',
);
private static $many_many = array(
'SubCuisines' => 'SubCuisine',
);
private static $summary_fields = array(
'getTitle' => 'Title'
);
public function getCMSFields() {
if ($this->isInDB()) {
$grid = GridField::create(
'SubCuisines',
'The Sub Cuisines of this Cuisines',
$this->SubCuisines(),
GridFieldConfig_RelationEditor::create()
);
} else {
// because this record is not saved to the DB yet, we have no ID, without ID there can be no many_many relation
$grid = ReadonlyField::create('SubCuisines', '', 'Sub Cuisines can be added after creating');
}
return FieldList::create(array(
DropdownField::create('CuisineID', 'Select a Cuisine', Cuisine::get()->map()),
$grid
));
}
/**
* overwrite getTitle and return title of Cuisine to have a nice text to display instead of the ID when displaying the save message
*/
public function getTitle() {
return $this->Cuisine() && $this->Cuisine()->exists() ? $this->Cuisine()->Title : parent::getTitle();
}
}
File: Cuisine.php
/**
* #property string Title
*/
class Cuisine extends DataObject {
private static $db = array(
'Title' => 'Varchar(255)',
);
/**
* #return FieldList
*/
public function getCMSFields() {
return FieldList::create(array(
TextField::create('Title', 'Name of Cuisine'),
));
}
}
File: SubCuisine.php
/**
* #property string Title
*/
class SubCuisine extends DataObject {
private static $db = array(
'Title' => 'Varchar(255)',
);
/**
* #return FieldList
*/
public function getCMSFields() {
return FieldList::create(array(
TextField::create('Title', 'Name of Cuisine'),
));
}
}
GridField is the perfect tool to manage this kind of data structure, I do it on a daily bases.
Because of your topic I feel the need to also mention this: it doesn't join here (ok, yes the ORM does joins, but not Restaurant & Cuisine & SubCuisine).
What the below example will do:
on a single Restaurant it will display a list (GridField) of Cuisines, where you can create new ones or attach existing ones.
on a single Cuisine it will display a list (GridField) of SubCuisines, where you can create new ones or attach existing ones.
(I am assuming that Restaurant is a Page, but it works just as well if its a normal DataObject)
File Restaurant.php:
/**
* #method ManyManyList Cuisines
*/
class Restaurant extends Page {
private static $many_many = array(
'Cuisines' => 'Cuisine',
);
/**
* #return FieldList
*/
public function getCMSFields() {
$return = parent::getCMSFields();
$return->addFieldToTab('Root', Tab::create('Cuisines', 'The Cuisines'));
$return->addFieldToTab(
'Root.Cuisines',
GridField::create(
'Cuisines',
'The Cuisines this Restaurant offers',
$this->Cuisines(),
GridFieldConfig_RelationEditor::create()
)
);
return $return;
}
}
class Restaurant_Controller extends Page_Controller {
}
File Cuisine.php:
/**
* #property string Title
* #method ManyManyList SubCuisines
*/
class Cuisine extends DataObject {
private static $db = array(
'Title' => 'Varchar(255)',
);
private static $many_many = array(
'SubCuisines' => 'SubCuisine',
);
/**
* #return FieldList
*/
public function getCMSFields() {
if ($this->isInDB()) {
$grid = GridField::create(
'SubCuisines',
'The Sub Cuisines of this Cuisines',
$this->SubCuisines(),
GridFieldConfig_RelationEditor::create()
);
} else {
// because this record is not saved to the DB yet, we have no ID, without ID there can be no many_many relation
$grid = ReadonlyField::create('SubCuisines', '', 'Sub Cuisines can be added after creating');
}
return FieldList::create(array(
TextField::create('Title', 'Name of Cuisine'),
$grid,
));
}
}
File SubCuisine.php:
/**
* #property string Title
*/
class SubCuisine extends DataObject {
private static $db = array(
'Title' => 'Varchar(255)',
);
/**
* #return FieldList
*/
public function getCMSFields() {
return FieldList::create(array(
TextField::create('Title', 'Name of Cuisine'),
));
}
}
File Restaurant.ss (template):
<h1>Restaurant: $Title</h1>
<% if $Cuisines %>
<h2>Cuisines</h2>
<ol>
<% loop $Cuisines %>
<li>
<h3>$Title</h3>
<% if $SubCuisines %>
<h4>Sub Cuisines:</h4>
<ul>
<% loop $SubCuisines %>
<li>
<h5>$Title</h5>
</li>
<% end_loop %>
</ul>
<% end_if %>
</li>
<% end_loop %>
</ol>
<% end_if %>