Why is the invoice page different for another user? - drupal

When I go to admin/store/orders/50457/invoice as the administrator, I see the following:
Notice how it has a payment method of "Free order" and the total at the bottom is $0.00.
When I go to the same page as a non-administrator, I see the following:
Notice how Payment Method is empty and the total for the order is $8.21.
The correct one is what the administrator sees, so what is going on that makes the two behave differently?
EDIT: It turns out in a module I created (a long time ago) called tf_store_credit.module, I have the following:
function tf_store_credit_line_item(){
global $user;
$total_credit= uc_store_credit_f_get_user_credit($user->uid);
if ($total_credit>0){
$items[] = array
(
'id' => 'store-credit', // You will use this ID in the javascript
'title' => t('Store Credit'), // This is the text that will be displayed on the line item in the subtotal
'callback' => 'tf_store_credit_line_item_callback', // This is the callback function
'stored' => TRUE,
'default' => FALSE,
'calculated' => TRUE,
'display_only' => FALSE,
'weight' => 15,
);
}
return $items;
}
The problem is that it is getting the currently logged in user's store credit instead of the user who placed the order. So how would I go about getting the correct user?

In tf_store_credit.module, I modified it like this:
function tf_store_credit_line_item(){
global $user;
$total_credit= uc_store_credit_f_get_user_credit($user->uid);
if ($total_credit>0 || in_array("view_orders", $user->roles)){
$items[] = array
(
'id' => 'store-credit', // You will use this ID in the javascript
'title' => t('Store Credit'), // This is the text that will be displayed on the line item in the subtotal
'callback' => 'tf_store_credit_line_item_callback', // This is the callback function
'stored' => TRUE,
'default' => FALSE,
'calculated' => TRUE,
'display_only' => FALSE,
'weight' => 15,
);
}
return $items;
}
In uc_free_order.module, I did a similar thing so that "Payment method" showed up:
function uc_free_order_payment_method() {
global $user;
if ($user->name=='blah' || $user->name=='blah2' || in_array("view_orders", $user->roles)){
$methods[] = array(
'id' => 'free_order',
'name' => t('Free order'),
'title' => t('Free order - payment not necessary.'),
'desc' => t('Allow customers with $0 order totals to checkout without paying.'),
'callback' => 'uc_payment_method_free_order',
'checkout' => TRUE,
'no_gateway' => TRUE,
'weight' => 10,
);
return $methods;
}
}

Related

WooCommerce Shipping Plugin - Checkout Shipping Cost Not Updating(AJAX)

I've searched to find any solution but nothing worked.
Here what I want to do:
Add new field in checkout page called Shipping show as selectbox filled with Preorder and Non-preorder
If preorder then would show Location field show as selectbox
If non-preorder then would show Location field same as step 2 but different list option.
When Shipping and Location filled correctly, shipping cost would show with correct shipping cost.
Problem
When I filled all required field and Shipping, Location shipping cost wound calculate again. It do AJAX request, but shipping cost keep the same.
But, when I change Name or Street Address shipping cost updated correctly, which is bad behavior. When user click Place Order immediately would POST wrong shipping cost.
Here my Youtube Video to make clear what I ask for help.
What I did to create my own plugin:
Create custom field using hook something like this
public function woocommerce_checkout_fields( $fields )
{
// var_dump(have_rows('location', 'option'));
// die('test');
$options = [];
$options[''] = 'Select Shipping';
$options['pre-order'] = 'Pre Order';
if (!$this->hasPreorderItem()) {
$options['non-pre-order'] = 'Non Pre Order';
}
// Add custom billing shipping
$fields['billing']['billing_shipping'] = array (
'type' => 'select',
'label' => 'Shipping',
'placeholder' => 'Select shipping',
'class' => array ('address-field', 'update_totals_on_change' ),
'required' => true,
'options' => $options
// 'options' => $this->getLocations()
);
$fields['billing']['billing_location_pre_order'] = array (
'type' => 'select',
'label' => 'Location(Pre Order)',
'placeholder' => 'Select Preorder Location',
'class' => array ('address-field', 'update_totals_on_change' ),
'required' => false,
'options' => $this->preorderLocations->getLocations()
// 'options' => $this->getLocations()
);
// Add custom billing location
$fields['billing']['billing_location'] = array (
'type' => 'select',
'label' => 'Location',
'placeholder' => 'Select location',
'class' => array ('address-field', 'update_totals_on_change' ),
'required' => false,
'options' => $this->locations->getLocations()
// 'options' => $this->getLocations()
);
return $fields;
}
Create class to help calculate cost based on Shipping and Location.
What I have tried
Using this answer but no luck. Click here for the question.
Tried to make field to required, as I saw someone said it only update when all required fields filled.
Tried to disable cache in wp-config.php
I found solution from this link
I might help someone that has similar problem. You just need to clear the session. So, WooCommerce would re-calculate and recall your calculate_shipping() function.
To do that add woocommerce_checkout_update_order_review hook. It would look something like this
add_action('woocommerce_checkout_update_order_review', 'action_woocommerce_checkout_update_order_review', 10, 1);
function action_woocommerce_checkout_update_order_review( $posted_data )
{
global $woocommerce;
$packages = $woocommerce->cart->get_shipping_packages();
foreach( $packages as $package_key => $package ) {
$session_key = 'shipping_for_package_'.$package_key;
$stored_rates = WC()->session->__unset( $session_key );
}
}

Wordpress REST API, how to get /post schema?

I have created a custom endpoint, that basically just grabs a few different posts from each category and returns it. This endpoint works fine, but the schema of each post being returned is not the same as when you just hit the default, built-in /posts endpoint. What do I have to do to keep the schemas consistent?
I have a feeling get_posts is the problem, but I have been doc crawling, and I cant seem to find anything that uses the same schema as /posts does.
// How the endpoint is built.
function anon_content_api_posts($category) {
$posts = get_posts(
array(
'posts_per_page' => 3,
'tax_query' => array(
array(
'taxonomy' => 'content_category',
'field' => 'term_id',
'terms' => $category->term_id,
)
)
)
);
$posts = array_map('get_extra_post_data', $posts); // just me appending more data to each post.
return $posts;
}
function anon_content_api_resources() {
$data = array();
$categories = get_categories(
array(
'taxonomy' => 'content_category',
)
);
foreach($categories as $category) {
$category->posts = anon_content_api_posts($category);
array_push($data, $category);
}
return $data;
}
Custom endpoint schema
ID:
author:
comment_count:
comment_status:
featured_image_url:
filter:
guid:
menu_order:
ping_status:
pinged:
post_author:
post_content:
post_content_filtered:
post_date:
post_date_gmt:
post_excerpt:
post_mime_type:
post_modified:
post_modified_gmt:
post_name:
post_parent:
post_password:
post_status:
post_title:
post_type:
to_ping:
Default /posts schema
_links:
author:
categories:
comment_status:
content:
date:
date_gmt:
excerpt:
featured_image_url:
featured_media:
format:
guid:
id:
link:
meta:
modified:
modified_gmt:
ping_status:
slug:
status:
sticky:
task_category:
template:
title:
type:
Any help would be appreciated!
Although this question is older, I had a difficult time finding the answer to getting the schema myself, so I wanted to share what I found.
Short Answer (to getting the schema information back): Use OPTIONS method on the route request
You are dealing with an endpoint that already exists /wp/v2/posts, so you probably want to modify the response of the existing route which you can do with register_rest_field() (this should keep the appropriate schema for all exposed post columns / fields, but allows you to modify the schema for the fields you are now exposing as well):
Something like this:
function demo_plugin_extend_route_rest_api()
{
register_rest_field(
'post',
'unexposed_column_in_wp_posts_table',
array(
'get_callback' => function( $post_arr ) {
$post_obj = get_post( $post_arr['id'] );
return $post_obj->unexposed_column_in_wp_posts_table;
},
'update_callback' => function( $unexposed_column_in_wp_posts_table, $post_obj ) {
$ret = wp_update_post(
array(
// ID is the name of the column in the posts table
// unexposed_column_in_wp_posts_table should be replaced throughout with the unexposed column in the posts table
'ID' => $post_obj->ID,
'unexposed_column_in_wp_posts_table' => $unexposed_column_in_wp_posts_table
)
);
if ( false === $ret )
{
return new WP_Error(
'rest_post_unexposed_column_in_wp_posts_table_failed',
__( 'Failed to update unexposed_column_in_wp_posts_table.' ),
array( 'status' => 500 )
);
}
return true;
},
'schema' => array(
'description' => __( 'Post unexposed_column_in_wp_posts_table' ),
'type' => 'integer'
),
)
);
}
// Not-in-class call (use only this add_action or the one below, but not both)
add_action( 'rest_api_init', 'demo_plugin_extend_route_rest_api' );
// In-class call
add_action( 'rest_api_init', array($this, 'demo_plugin_extend_route_rest_api') );
If what you are really wanting is to create a new route and endpoint with custom tables (or another endpoint to the posts table), something like this should work:
function demo_plugin_custom_rest_api()
{
// Adding Custom Endpoints (add tables and fields not currently exposed)
// register_rest_route()
// $namespace (string) (Required) The first URL segment after core prefix.
// Should be unique to your package/plugin.
// $route (string) (Required) The base URL for route you are adding.
// $args (array) (Optional) Either an array of options for the endpoint, or an
// array of arrays for multiple methods. Default value: array()
// array: If using schema element to define the schema, or multiple methods,
// then wrap the 'methods', 'args', and 'permission_callback' in an array,
// otherwise they do not need to be wrapped in an array. Best practice
// would be to wrap them in an array though
// 'methods' (array | string): GET, POST, DELETE, PUT, PATCH, etc.
// 'args' (array)
// '<schema property name>' (array) (ie. parameter name - if not including a schema
// then can include field names as valid parameters as a way to
// describe them):
// 'default': Used as the default value for the argument, if none is supplied
// Note: (if defined, then it will validate and sanitize regardless of if
// the parameter is passed in query).
// 'required': If defined as true, and no value is passed for that argument, an
// error will be returned. No effect if a default value is set, as the argument
// will always have a value.
// 'description': Field Description
// 'type': Data Type
// 'validate_callback' (function): Used to pass a function that will be passed the
// value of the argument. That function should return true if the value is valid,
// and false if not.
// 'sanitize_callback' (function): Used to pass a function that is used to sanitize
// the value of the argument before passing it to the main callback.
// 'permission_callback' (function): Checks if the user can perform the
// action (reading, updating, etc) before the real callback is called
// 'schema' (callback function) (optional): Defines the schema.
// NOTE: Can view this schema information by making OPTIONS method request.
// $override (bool) (Optional) If the route already exists, should we override it? True overrides,
// false merges (with newer overriding if duplicate keys exist). Default value: false
//
// View your describe page at: /wp-json/demo-plugin/v1
// View your JSON data at: /wp-json/demo-plugin/v1/demo-plugin_options
// View your schema at (with OPTIONS method) at: /wp-json/demo-plugin/v1/demo-plugin_options
// Note: For a browser method to see OPTIONS Request in Firefox:
// Inspect the JSON data endpoint (goto endpoint and click F12)
// > goto Network
// > find a GET request
// > click it
// > goto headers section
// > click Edit and Resend
// > change Method to OPTIONS
// > click Send
// > double click on last OPTIONS request
// > goto Response (the JSON data returned shows your schema)
register_rest_route(
'demo-plugin/v1',
'/demo-plugin_options/',
array(
// GET array options
array(
'methods' => array('GET'),
'callback' => function ( WP_REST_Request $request ){
// Get Data (here we are getting from options, but could be any data retrieval)
$options_data = get_option('demo_option_name');
// Set $param
$param = $request->get_params();
// Do Other things based upon Params
return $options_data;
},
'args' => array(
// Valid Parameters
'element_1' => array(
'description'=> 'Element text field',
'type'=> 'string',
),
'element_color' => array(
'description'=> 'Element color select box',
'type'=> 'string',
)
)
),
// POST array options
array(
'methods' => array('POST'),
'callback' => function ( WP_REST_Request $request ){
// Get Data (here we are getting from options, but could be any data retrieval)
$options_data = get_option('demo_option_name');
// Set $param
$param = $request->get_params();
// Do Other things based upon Params
if (is_array($param) && isset($param))
{
foreach ($param as $k=>$v)
{
// $param is in an array($key => array($key => $value), ...)
if (is_array($v) && array_key_exists($k, $options_data) && array_key_exists($k, $v))
{
$options_data[$k] = $v;
}
}
}
update_option('demo_option_name', $options_data);
return $options_data;
},
'args' => array(
'element_1' => array(
'default' => '',
'required' => false,
'description'=> 'Element text field',
'type'=> 'string',
'validate_callback' => function($param, $request, $key) { //validation function },
'sanitize_callback' => function($param, $request, $key) { //sanitization function }
),
'element_color' => array(
'default' => 'red',
'required' => true,
'description'=> 'Element color select box',
'type'=> 'integer',
'validate_callback' => function($param, $request, $key) {
$colors = array('red', 'blue');
return in_array($param, $colors);
},
'sanitize_callback' => function($param, $request, $key) {
// If it includes a default, and sanitize callback for other properties above are set, it seems to need it here as well
return true;
})
),
'permission_callback' => function () {
// See Capabilities here: https://wordpress.org/support/article/roles-and-capabilities/
$approved = current_user_can( 'activate_plugins' );
return $approved;
}
),
'schema' => function() {
$schema = array(
// This tells the spec of JSON Schema we are using which is draft 4.
'$schema' => 'http://json-schema.org/draft-04/schema#',
// The title property marks the identity of the resource.
'title' => 'demo-plugin_options',
'type' => 'object',
// In JSON Schema you can specify object properties in the properties attribute.
'properties' => array(
'element_1' => array(
'description' => esc_html__( 'Element text field', 'demo-plugin' ),
'type' => 'string',
'context' => array( 'view', 'edit', 'embed' ),
'readonly' => false,
),
'element_color' => array(
'description' => esc_html__( 'Element color select box', 'demo-plugin' ),
'type' => 'string',
'readonly' => false,
),
),
);
return $schema;
})
);
}
// Not-in-class call (use only this add_action or the one below, but not both)
add_action( 'rest_api_init', 'demo_plugin_custom_rest_api' );
// In-class call
add_action( 'rest_api_init', array($this, 'demo_plugin_custom_rest_api') );
Of course, this is just a basic outline. Here is a caveat:
According to the documentation listed below, it is best to use a Controller Pattern class extension method (rather than the method I outlined above): https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-custom-endpoints/#the-controller-pattern
These were very helpful links in finally putting this all together for myself:
REST API Handbook: https://developer.wordpress.org/rest-api/
See Sub-Pages:
REST API Modifying Responses,
REST API Adding Custom Endpoints,
REST API Schema
Register REST Field Function: https://developer.wordpress.org/reference/functions/register_rest_field/
Register REST Route Function: https://developer.wordpress.org/reference/functions/register_rest_route/

cannot get checkboxes value using drupal form api

i have form in drupal which uploads images and has got few checkboxes in it.
Here is the form:
$form['checklist_fieldset'] = array(
'#type' => 'fieldset',
'#title' => t('Check List'),
'#collapsible' => FALSE,
'#collapsed' => FALSE,
);
$form['checklist_fieldset']['heating'] = array(
'#type' => 'checkboxes',
'#title' => t('Heating options'),
'#options' => array(
'0' => t('Yes'),
'1' => t('No')
),
'#description' => t('Heating details.')
);
and here is my submit function where i am processing image upload and grabbing the checkboxes value as well. I am getting the success message and image is getting uploaded but not getting the value of check boxes.
function property_add_view_submit($form,&$form_state){
$validators = array();
if($file = file_save_upload('p_file1',$validators,file_direcotry_path)){
$heating = array_keys($form_state['values']['heating']);
drupal_set_message(t('Property Saved! '.$heating));
dpm( $form_state['values']['heating']);
}
When you use #options on a FAPI element the value passed to the $form_state is the array key, so you don't need to use array_keys().
I'm not sure why you're using checkboxes for a yes/no, usually one would use a simple checkbox element. However if that's really what you want to do:
Your #options can't contain on option with 0 as the array key, it will be automatically filtered out and you'll never know if that option has been checked.
You should use $heating_options_chosen = array_filter($form_state['values']['heating'] to get the selected checkbox options.
I honestly think your code should look like this though:
$form['checklist_fieldset']['heating'] = array(
'#type' => 'checkbox',
'#title' => t('Heating options'),
'#options' => array(
'1' => t('Yes'),
'0' => t('No')
),
'#description' => t('Heating details.')
);
$heating_checked = $form_state['values']['heating'] == 1;
If I have checkbox Friends and options are like
[ ] abc
[ ] def
[ ] ghi
[ ] jkl
And I want to know which options user have marked, then use below function.
if ($form_state->getValue('friends') != NULL) {
foreach ($form_state->getValue('friends') as $key => $value) {
if ($value != 0) {
$friends = $friends . ", " . $key;
$friends = substr_replace($friends, "", 0, 1);
}
}
}
If user has chosen abc and ghi then you will get 1,3 as result in $friends
If you wanted to know the value then use $friends = $friends.", ".$value;
it worked for me..hope it will help you as well :)

Drupal Block not showing on the page

$blocks['onemore'] = array(
'info' => t('onemore'),
'status' => TRUE,
'region' => 'content',
'weight' => 0,
'cache' => DRUPAL_NO_CACHE,
'visibility' => BLOCK_VISIBILITY_LISTED,
'pages' => 'admin/structure/nodequeue/1/view/1',
);
Problem - The above block shows up and works perfectly and as expected at 'admin/structure/nodequeue/1/view/1'
My problem is that I need to declare dynamic amounts of blocks based on the users inputs. So I wrote a db fetch and for each loop.
If I do this then the block shows up in 'admin/modules' but the it is not in 'content' region for the seven theme. As I want to show it there.
I have double checked the values and even the admin/structure/block/manage/xdmp/onemore/configure has the value but the region is not selected.
I am assuming there is some conflict in the for each loop or the db query. Please advice your thoughts on it.
function xdmp_block_info() {
$blocks = array();
// Here we are going to do a db query so that I can get a list of
// block ids to declare
$resultxdmp = db_query("
SELECT * FROM xdmp_container_list ");
foreach($resultxdmp as $resultRecords)
{
$xdmp_nodeque_id_to_display =(int)$resultRecords->xdmp_nodequeue_id;
$xdmp_nodeque_id_to_display = intval($xdmp_nodeque_id_to_display);
$xdmp_path_to_show_block = 'admin/structure/nodequeue/'.$xdmp_nodeque_id_to_display.'
/view/'.$xdmp_nodeque_id_to_display.'';
$xdmp_machinenameofblock=(string)$resultRecords->xdmp_container_machine_name;
$xdmp_nameofblock=(string)$resultRecords->xdmp_container_name;
$blocks[$xdmp_machinenameofblock] = array(
'info' => t($xdmp_nameofblock),
'status' => TRUE,
'region' => 'content',
'weight' => 0,
'cache' => DRUPAL_NO_CACHE,
'visibility' => BLOCK_VISIBILITY_LISTED,
'pages' => $xdmp_path_to_show_block,
);
} // end for for each
return $blocks;
}
cheers,
Vishal
Are you sure the 'content' region is valid? If it's not, it of course can't show up :)

Drupal: Fivestar Block with voting axis

I'm using fivestar 1.19 with voting axis. I believe the default fivestar block/fivestar function uses only the default 'vote' tag.
fivestar_widget_form($node)
I need to pass my custom fivestar tag to the function.
Attempting to follow the answer below:
For me $object is $node.
<?php
function custom_fivestar_widget ($object) {
global $user;
$star_display = variable_get('fivestar_style_'. $object->type, 'average');
$text_display = variable_get('fivestar_text_'. $object->type, 'dual');
if ($star_display == 'average' && ($text_display == 'average' || $text_display == 'none')) {
// Save a query and don't retrieve the user vote unnecessarily.
$votes = fivestar_get_votes($object->type, $object->nid, 'score', 0);
}
else {
$votes = fivestar_get_votes($object->type, $object->nid);
}
$values = array(
'user' => isset($votes['user']['value']) ? $votes['user']['value'] : 0,
'average' => isset($votes['average']['value']) ? $votes['average']['value'] : 0,
'count' => isset($votes['count']['value']) ? $votes['count']['value'] : 0,
);
$settings = array(
'stars' => variable_get('fivestar_stars_'. $object->type, 10),
'allow_clear' => variable_get('fivestar_unvote_'. $object->type, FALSE),
'style' => $star_display,
'text' => $text_display,
'content_type' => $object->type,
'content_id' => $object->nid,
'tag' => 'score',
'autosubmit' => TRUE,
'title' => variable_get('fivestar_title_'. $object->type, 1) ? NULL : FALSE,
'feedback_enable' => variable_get('fivestar_feedback_'. $object->type, 1),
'labels_enable' => variable_get('fivestar_labels_enable_'. $object->type, 1),
'labels' => variable_get('fivestar_labels_'. $object->type, array()),
);
return fivestar_custom_widget($form_state, $values, $settings);
}
print drupal_get_form('custom_fivestar_widget', $object);
?>
This prints me the widget, I believe using my score. However the text display is all wrong, as is the average score. And it gives everything a permanent 10 stars. :(
You can reproduce fivestar_form function in fivestar.module. See there $settings variable.
So just copy inner of this function, remove some variables checking and set manually some variables. In $settings array set to 'tag' value as you want.

Resources