how to dynamically remove all edit and delete functionality of a page - php

I have split up my code into part 1 , part 2, and part 3
part 1 and 2 are working just fine... they are checking post types and scanning for metadata
Its only Part 3 that I am completely missing the bill
/*remove Edit Trash, and quickedit of pages with specific metavalues for certain roles
*/
add_filter( 'page_row_actions', 'remove_page_row_actions', 10, 2 ); // 2, not 1
add_filter( 'post_row_actions', 'remove_page_row_actions', 10, 2 ); // 2, not 1
// pass $post object as second argument.
function remove_page_row_actions( $actions, $post ) {
//PART 1 SPECIFY USERS
global $current_user;
get_currentuserinfo();
if(
(
//specify roles except administrator (but you need to add child roles based off administrator ex. adminsub)
(
!current_user_can('administrator')
||
current_user_can('adminsub')
)
||
// specify a list of role(s)
(
current_user_can('adminsub')
||
current_user_can('author')
)
)
)
{
// PART 2 SEARCH WHICH TYPES OF POSTS TO GET A SPECIFIC METADATA FROM
$post_types_affected = array('page' , 'post'); // I ADDED POST HERE STILL WORKS
// print_r($post_types_affected); // use this to see which posts are affected
//only get post IDs for a metavalue which has ALL of the following EXACT values (I changed it to just 1)
//$array_of_values_to_match = array( '1', '1', '1' );
$array_of_values_to_match = array( 1 );
$metakey_to_match = 'checkboxmeta1';
$args = array(
'post_type' => get_post_types(),
'meta_query' => array(),
'numberposts' => -1,
);
// if there's more than 1 value, add the relation arg
if( 1 < count( $array_of_values_to_match ) ){
$args['meta_query']['relation'] = 'AND';
}
// for each of the array values, add a meta query for that value
foreach( $array_of_values_to_match as $val ){
$args['meta_query'][] = array(
'key' => $metakey_to_match,
'value' => $val,
'compare' => '='
);
}
$postlistarray = get_posts( $args );
//end of function which an array or post arrays which each contain a post ID and a metakey of 1
//must create an array column, becuase that is what $x = array(111,212) does
$post_ids_affected = array_column($postlistarray, 'ID');
//PART 3 check array_column for post IDs, and remove functionality below from posts which had the metadata
if ( in_array( $post->post_type, $post_types_affected )
&& in_array( $post->ID, $post_ids_affected ) ) {
unset( $actions['inline hide-if-no-js'] );
unset( $actions['edit'] );
unset( $actions['trash'] );
unset( $actions['pa_duplicator'] );
}
}
return $actions;
}
what I am trying to do is for these roles from 1 when interacting with posts from 2, I want to remove ALL EDIT and TRASH capabilities.
so obviously right now ive just removed some actions lol such as edit and quickedit.. but I just realized the user can just click on the page edit.php link, or even just change the url to soemthing like
https://mywebsite/wp-admin/post.php?post=2752&action=edit
or
remotely trash or edit it some other way through URL or other method..
how do I just completely remove the edit and trash capability of that role for part 3, so that its view only? and maybe view and comment moderation?
I hope I didnt waste alot of time by trying to hook into page_row_actions and post_row_actions lol... maybe I need to be putting this code into like admin_init or something but I am sort of a noob lol

after about 8 hours.. I realized a plugin call advanced access manager, which is free, has 2 toggle checkboxes on each page for this exactly lol.
why reinvent the wheel I Guess

Related

wpgridbuilder order by two fields

I'm using WP Grid Builder and I need to order my grid with two fields:
DATE (DESC) and PARENT (ASC).
So that I have the most recent posts AND the parent posts to show first.
That way, I push the child posts to the bottom
Is that possible?
For your reference: https://docs.wpgridbuilder.com/resources/filter-grid-query-args/
This is what I came up with, but it's not working:
<?php
function grid_query_sorting_date_parent( $query_args, $grid_id ) {
global $post;
// If it matches grid id 1.
if ( 1 === $grid_id ) {
$query_args['orderby'] = array('date' => 'DESC' , 'parent' => 'ASC');
}
return $query_args;
}
add_filter( 'wp_grid_builder/grid/query_args', 'grid_query_sorting_date_parent', 10, 2 );

Is there any way to have a wordpress multi domain setup with shared post and templates and so on?

I wonder if there is any way to have only one wordpress instant which has 2 different domains (one main domain and one subdomain). The content of the domains should be different but also share pages and templates and posts. E.g. a page "employees" should be the same for both domains.
I have already set up a WordPress network and so the multi-domain setup works but unfortunately pages and posts and templates are separated. There are plugins which mirror e.g. posts also on the other domain but here is then again the problem that I have saved the post 2 times.
Maybe you already have a plugin which can do this, without any coding, but i'm not familiar with them.
An idea would be to hook onto the save_post action and push the newly created post to the different blogs.
if ( ! function_exists( 'post_to_multiple_sites' ) ) {
add_action( 'save_post', 'post_to_multiple_sites', 20, 2 );
function post_to_multiple_sites($original_id, $original_post) {
// To prevent publishing revisions
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return $original_id;
}
// We only want to mess around with a post that has been published
if( 'publish' !== get_post_status( $original_post ) ) {
return $original_id;
}
// prevent "Fatal error: Maximum function nesting level reached"
remove_action( 'save_post', __FUNCTION__ );
/**
* If i'm correct, when creating a network, each site/blog receive an ID.
* You can set these hardcoded, or create a function that returns an array of the blog id's.
*
* If you only have a couple of sites, I would maintain this manually. Otherwise create a function to
* gather all the ID's and return it as an array (up to you).
*/
$blog_ids = [2, 3];
$post_data = [
'post_author' => $original_post->post_author,
'post_date' => $original_post->post_date,
'post_modified' => $original_post->post_modified,
'post_content' => $original_post->post_content,
'post_title' => $original_post->post_title,
'post_excerpt' => $original_post->post_excerpt,
'post_status' => 'publish', // new post will be set to published
'post_name' => $original_post->post_name,
'post_type' => $original_post->post_type,
];
// Gather the post meta & terms
$post_terms = wp_get_object_terms( $original_id, 'category', array( 'fields' => 'slugs' ) );
$post_meta = get_post_custom( $original_id );
foreach ($blog_ids as $blog_id) {
switch_to_blog($blog_id); // https://developer.wordpress.org/reference/functions/switch_to_blog/
// IN case a post with the same slug exists, don't do anything.
// Or maybe create a new post with slug-name-2...up to you.
if ( get_posts( [ 'name' => $post_data[ 'post_name' ], 'post_type' => $post_data[ 'post_type' ], 'post_status' => 'publish' ] ) ) {
restore_current_blog();
continue;
}
$inserted_post_id = wp_insert_post( $post_data );
wp_set_object_terms( $inserted_post_id, $post_terms, 'category', false );
foreach ( $post_meta as $meta_key => $meta_values) {
// we do not need these redirects
if( '_wp_old_slug' === $meta_key ) {
continue;
}
foreach ( $meta_values as $meta_value ) {
add_post_meta( $inserted_post_id, $meta_key, $meta_value );
}
}
restore_current_blog();
}
}
}
It became a bigger function than I expected and honestly don't know if you should go this route. Your safest bet is to try and find a plugin that handles this for you. But you can use this piece of code and extend it obviously to your needs
Make sure to read the comments I added. These are important!

I have a code that removes actions for specific users on certain pages depending on page metavalue... but it only makes an array of 5?

Update! Read to the bottom for solve!
/*remove Edit Trash, and quickedit of pages with specific metavalues for certain roles
*/
add_filter( 'page_row_actions', 'remove_page_row_actions', 10, 2 ); // 2, not 1
// pass $post object as second argument.
function remove_page_row_actions( $actions, $post ) {
global $current_user;
get_currentuserinfo();
//specify roles except administrator (but you need to add child roles based off administrator ex. adminsub)
if(
( (!current_user_can('administrator') || current_user_can('adminsub') )
||
// specify a list of role(s)
( current_user_can('adminsub') || current_user_can('author') )
) )
{
//search which type of $post
$post_types_affected = array('page');
//Dynamically get 1 post ID's in an array for a post that matches multiple values (im repeating 1 pointlessly)
//$array_of_values_to_match = array( '1', '1', '1' );
$array_of_values_to_match = array( 1 );
$metakey_to_match = 'checkboxmeta1';
// set some initial args
$args = array(
'post_type' => 'page',
'meta_query' => array(),
);
// if there's more than 1 value, add the relation arg
if( 1 < count( $array_of_values_to_match ) ){
$args['meta_query']['relation'] = 'AND';
}
// for each of the array values, add a meta query for that value
foreach( $array_of_values_to_match as $val ){
$args['meta_query'][] = array(
'key' => $metakey_to_match,
'value' => $val,
'compare' => '='
);
}
$postlistarray = get_posts( $args );
//end of function which an array or post arrays which each contain a post ID and a metakey of 1
//must create an array column, becuase that is what $x = array(111,212) does
$post_ids_affected = array_column($postlistarray, 'ID');
//check array_column for post IDs, and remove functionality below
if ( in_array( $post->post_type, $post_types_affected )
&& in_array( $post->ID, $post_ids_affected ) )
{
unset( $actions['inline hide-if-no-js'] );
unset( $actions['edit'] );
unset( $actions['trash'] );
unset( $actions['pa_duplicator'] );
}
}
return $actions;
}
$post_ids_affected ends up being something like
array(0=>1000 , 1=> 1023, ... 4 => 524)
but it only goes up to 4, when there are like 10 pages atleast that have metabox value of 1. and the post ID list is from most recently created to oldest... but 0 to 4 is only 5 pages...not sure why I cant pull more into my array?
chris Haas was able to see the issue so I changed
//set some initial args
$args = array(
'post_type' => 'page',
'meta_query' => array(),
);
to this instead
$args = array(
'post_type' => get_post_types(),
'meta_query' => array(),
'numberposts' => -1,
);
and it works! My next concern however is trying to get this to apply also to posts and to custom posts types.. since it only affects pages right now?
SOLVED:
I just made the above adjustment
and the 2 following
changed
//search which type of $post
$post_types_affected = array('page');
to
//search which type of $post
$post_types_affected = array('page' , 'post');
and the duplicated the filter for posts!
/*remove Edit Trash, and quickedit of pages with specific metavalues for certain roles
*/
add_filter( 'page_row_actions', 'remove_page_row_actions', 10, 2 ); // 2, not 1
// pass $post object as second argument.
function remove_page_row_actions( $actions, $post ) {
to this
/*remove Edit Trash, and quickedit of pages with specific metavalues for certain roles
*/
add_filter( 'page_row_actions', 'remove_page_row_actions', 10, 2 ); // 2, not 1
add_filter( 'post_row_actions', 'remove_page_row_actions', 10, 2 ); // 2, not 1
// pass $post object as second argument.
function remove_page_row_actions( $actions, $post ) {

WooCommerce: How can I share an order between two customers?

a week ago I've started to build a WooCommerce store which should have the option to share orders between two customers. Here is a little diagram I've made for you so you can understand how it should be (Please take a look at it):
So here is what I did step for step
User B clicks a button -> (Save second user id to the order):
$related_order = $_POST['related_order'];
$current_user = wp_get_current_user();
$userID = $current_user->ID;
update_post_meta($related_order, 'second_user_id', $userID);
User B clicks another button -> (Remove second user id from the order)
$related_order = $_POST['related_order'];
$current_user = wp_get_current_user();
$user_id = $current_user->ID;
delete_post_meta($related_order , 'second_user_id');
These two steps (show and hide the order for user B) are working fine - I've tested it. The field gets set and unset.
Now it's getting worse:
I've searched a lot and asked some people to find the function in WooCommerce which gets all orders for a customer. After I found it I've tried to change it so that the second_user_id field gets checked to. I simply thought that I can show the order from customer A to B this way:
function woocommerce_account_orders( $current_page ) {
$current_page = empty( $current_page ) ? 1 : absint( $current_page );
$customer_orders = wc_get_orders( apply_filters( 'woocommerce_my_account_my_orders_query', array(
'customer' => get_current_user_id(),
'second_user_id' => get_current_user_id(),
'page' => $current_page,
'paginate' => true,
) ) );
wc_get_template(
'myaccount/orders.php',
array(
'current_page' => absint( $current_page ),
'customer_orders' => $customer_orders,
'has_orders' => 0 < $customer_orders->total,
)
);
}
The method is located in: https://docs.woocommerce.com/wc-apidocs/source-function-woocommerce_account_orders.html#2465-2486
As you can see I've tried to add the second_user_id to the query which returns the orders for a customer. This is my custom field saved in each order:
[5] => WC_Meta_Data Object (
[current_data:protected] => Array (
[id] => 3477
[key] => second_user_id
[value] => 2
)
After that did not worked I've got help from a friendly guy which told me, that this can't work the way I did it. There are permission which must be given to the user B to view the order from A and a lot of other stuff... So is there someone who can help me with this part? What is wrong with my implementation and how can I change the functionality the way I need it?
if we take look at the responsbile function which WooCommerce use to query the customer you will WooCommerceselect all orders which related to the user based on the user id.
Functions source code:
function woocommerce_account_orders( $current_page ) {
$current_page = empty( $current_page ) ? 1 : absint( $current_page );
$customer_orders = wc_get_orders( apply_filters( 'woocommerce_my_account_my_orders_query', array(
'customer' => get_current_user_id(),
'page' => $current_page,
'paginate' => true,
) ) );
wc_get_template(
'myaccount/orders.php',
array(
'current_page' => absint( $current_page ),
'customer_orders' => $customer_orders,
'has_orders' => 0 < $customer_orders->total,
)
);
}
}
If you want to alter this query and add specific order id's which is not belong to this user beside the default orders we need to do some sort of hack to this query and the possible option i can think of now is by using post__in instead of getting the orders by customer id.
we are going to use the woocommerce_my_account_my_orders_query filter to alter the query.
i will assume the additional orders for that user is stored in wp_usermeta table
The Solution will be:
add_filter( 'woocommerce_my_account_my_orders_query', 'modify_my_order_query' , 20, 1 );
function modify_my_order_query( $q ) {
global $wpdb;
$current_user_id = get_current_user_id();
//Check if the user have addtional orders
$secondary_post_ids = get_user_meta( $current_user_id, 'additional_orders', false );
if ( ! empty( $secondary_post_ids ) ) {
// Get All Orders ID for the main customers
$prepare_query = $wpdb->prepare(
" SELECT post_id FROM {$wpdb->postmeta}
WHERE meta_key LIKE %s and meta_value LIKE %d ",
'_customer_user',
$current_user_id
);
$results = $wpdb->get_results( $prepare_query, ARRAY_A );
$main_post_ids = wp_list_pluck( $results, 'post_id' );
// Merge All Orders IDs
$all_posts_ids = ( isset( $secondary_post_ids[0] ) ) ? array_merge( $main_post_ids, $secondary_post_ids[0] ) : $main_post_ids;
//Modify the my Order Query to include all orders ID including the additional ones
unset( $q['customer'] );
$q['post__in'] = $all_posts_ids;
}
return $q;
}
you will see in the above solution first we check if the current user have additional order if yes then we select all his default orders id and merge the array with his additional order is and then we modified the query so we can get all those orders.
Now the only things left is to allow the user to see his additional orders and to do so we need to use user_has_cap hook.
add_filter( 'user_has_cap', 'give_permissions' , 10, 3 );
function give_permissions( $allcaps, $cap, $args ) {
if ( isset( $cap[0] ) && $cap[0] == 'view_order' ) {
$get_additional_ids = get_user_meta( get_current_user_id(), 'additional_orders', false );
if ( isset( $get_additional_ids[0] ) && in_array( $args[2], $get_additional_ids[0] ) ) {
$allcaps[ $cap[0] ] = true;
}
}
return ( $allcaps );
}
i believe this solution will achieve your target goal.

WooCommerce: How can I get orders with a custom ID in order meta data object?

Because of a project I need help from you. I've searched a lot but I can't find a solution.
I'm trying to edit a WooCommerce function named
woocommerce_account_orders
I've added the field
mycustom_id
to the the orders meta-data object because I need to get all orders which has the current logged in user in the field mycustom_id:
(mycustom_id = current_user_id())
The check for the customer should stay. I just need to add this other current_user_id check.
This sould stay as it is:
'customer' => get_current_user_id()
. This is my not working code snippet:
function woocommerce_account_orders( $current_page ) {
$current_page = empty( $current_page ) ? 1 : absint( $current_page );
$customer_orders = wc_get_orders( apply_filters( 'woocommerce_my_account_my_orders_query', array(
'customer' => get_current_user_id(),
'mycustom_id' => get_current_user_id(),
'page' => $current_page,
'paginate' => true,
) ) );
wc_get_template(
'myaccount/orders.php',
array(
'current_page' => absint( $current_page ),
'customer_orders' => $customer_orders,
'has_orders' => 0 < $customer_orders->total,
)
);
}
The method is located in: https://docs.woocommerce.com/wc-apidocs/source-function-woocommerce_account_orders.html#2465-2486
How can I add this feature to the function a smart way like a filter and how can I pass my custom parameter the right way to the function? I've saved the parameter as an order_meta attribute:
[5] => WC_Meta_Data Object (
[current_data:protected] => Array (
[id] => 3477
[key] => mycustom_id
[value] => 2
)
Thank you for your help. I've tried so much but I'm new in PHP and must lurn a lot..
if you want to change this query you can do it by calling the woocommerce_my_account_my_orders_query filter instead of modifying the core function so you can achieve the required desired as follow:
add_filter( 'woocommerce_my_account_my_orders_query', 'modify_my_order_query', 10, 1 );
function modify_my_order_query( $q ) {
$q['customer'] = [ 1, 3 ]; // you customers ids here
return $q;
}
but this function above will display the order in the list only and if the customer click on that order to see the details he will got an error message as he doesn't have the permission to view the order and you need to modify the view_order capability
for example you can give the user with ID 1 permission to view user ID 3 orders as follow:
function give_permissions( $allcaps, $cap, $args ) {
$user = 3; //user id
if ( $cap[0] == 'view_order' ) {
$allcaps[ $cap[0] ] = true;
}
return ( $allcaps );
}
add_filter( 'user_has_cap', 'give_permissions', 10, 3 );

Categories