does votingapi_set_votes handles voting and unvoting. I will try to use the same logic as this Drupal Creating Votes in Voting API Through Code to create a vote. What i am asking is how to handle voting and unvoting.
Generally you add votes using votingapi_set_votes and delete votes using votingapi_delete_votes.
For both these functions you need a base criteria, something like this.
$criteria = array(
'entity_type' => 'node',
'entity_id' => $node->nid,
'uid' => $user->uid,
'value_type' => 'points',
'tag' => 'vote',
);
For setting vote you need its value, which usually differs from criteria only by value field.
$votes = $copy_of_criteria;
$votes['value'] = 666;
Then votingapi_set_votes($votes, $criteria) will delete all votes matching $criteria, and then add new votes (specified by $votes). This function also takes care of recalculating votes cache (i.e. aggregated values).
For deleting votes ("unvote") you firstly need to select required votes and then pass them into the votingapi_delete_votes function:
$votes = votingapi_select_votes($criteria);
votingapi_delete_votes($votes);
This function does not recalculates voting cache, so you need to call votingapi_recalculate_results('node', $node->nid).
Related
I'm trying to setup a bbpress with extended user capabilities.
The problem
My goal is that users need to have different capabilities in each forum, i.e:
UserA can't access ForumW
UserA can only read topics and replies in ForumX
UserA can create topics and write replies in ForumY
UserA can moderate ForumZ
Plugins
These are the plugins I tried so far, but without success:
Ultimate Member, official 1.7 and the new 2.0 version
https://ultimatemember.com/
They claim that they're working on a groups extension for UltimateMember v2, which somehow looks promising, but as of now there's no release date and I still don't know if this extension is going to solve my problem.
itthinx Groups plugin
http://docs.itthinx.com/document/groups/
Allows me to assign multiple groups to users and forums, but there's still a catch.
First attempt
Since itthinx Groups plugin allows me to assign multiple groups to UserA, which is great, it's still not solving my issue.
So, I tried something like this:
ForumX has the following groups assigned: ForumX_readers, ForumX_writers, ForumX_moderators
UserA has the following groups assigned: ForumX_readers, ForumY_writers, ForumZ_moderators
But the problem is, since UserA belongs to groups that have publish_replies and moderate capabilities, he has full access to ForumX.
So what I need is an intersection of the forum-groups and the user-groups - which in this example is ForumX_readers.
The promising part, but...
I digged into the code of the plugin and found the line that handles the capabilities of the user based on his assigned groups and quickly tried to get the current forum groups, to implement the intersection.
Unfortunatelly I was not able to access the global $post, the $_GLOBALS['post'] nor the $_REQUEST[] variables in this part of code. Neither directly nor with an apply_filters() function, that I implemented into the part of the code myself.
UPDATE:
I was able to get the ID with get_posts() and the slug of the current forum/topic.
So, my question
Is there any solution to my first attempt, which I may have overseen?
If not, is there maybe any other plugin that can solve my problem that I'm not aware of?
Or is something like that even impossible in bbpress?
After some further research and trial & error, I finally figured it out.
First step to do is to set up the capabilities, which in my case look something like this.
In the plugins directory, there is the file core/class-groups-user.php. The init_cache() function retrieves the assigned groups to the user, and sets the according capabilities.
To not mess around to much with the core-plugin, I applied a filter to the $group_ids variable which can be found in line: 415.
foreach( $user_groups as $user_group ) {
$group_ids[] = Groups_Utility::id( $user_group->group_id );
}
// added this line
$group_ids = apply_filters('filter_user_group_ids', $group_ids);`
I then created a new plugin, which hooks into this filter.
add_filter('filter_user_group_ids', 'dnmc_filter_groups', 10, 1);
function dnmc_filter_groups($user_group_ids) {
$forum_id = dnmc_get_forum_id();
if(!$forum_id) return $user_group_ids;
$forum_group_ids = Groups_Post_Access::get_read_group_ids( $forum_id);
$user_restricted_forum_group_ids = array_intersect($user_group_ids, $forum_group_ids);
return $user_restricted_forum_group_ids;
}
function dnmc_get_forum_id() {
$args_topic = array(
'name' => basename( untrailingslashit( rtrim($_SERVER['REQUEST_URI'], '/') ) ),
'post_type' => 'topic',
'post_status' => 'publish',
'numberposts' => 1
);
if($topic = get_posts($args_topic)) {
return $topic[0]->post_parent;
}
$args_forum = array(
'name' => basename( untrailingslashit( rtrim($_SERVER['REQUEST_URI'], '/') ) ),
'post_type' => 'forum',
'post_status' => 'publish',
'numberposts' => 1
);
if($forum = get_posts($args_forum)) {
return $forum[0]->ID;
}
return false;
}
Let's consider a scenario like below:
Entity Car has Many To Many CarType which is a list of different types and each type can be active or inactive.
Car Form:
$builder->add('type', 'entity', array(
'label' => 'Car Type',
'class' => 'SomeBundle:CarType',
'query_builder' => function (EntityRepository $er) {
$qb = $er->createQueryBuilder('type')
->where('type.status = :status')
->setParameter('status', 'active')
;
return $qb;
}
));
In create phase, a user create a Car with an active Type. Assume I have an admin page to mark Type active/inactive.
What is the best way to handle the Car edit phase that has a relationship to an inactive Type? In other word if a Car has a relationship to any Type that was active at some point and not active any more, the choice would not show up in the dropdown.
What is the best way to handle a use case like this which dropdwon items can have different status in different time frame but query only returns the active ones?
One way would be to alert the user that Car is using some inactive Type but is there any other better way?
You ca deal with the problem in the admin level
(like you can't make inactive a carType if he's still used)
Or you deal it with user level:
You propose only choices of active car + the inactive current user choice.
This way the user can only choose to change to an active type of car or keep it's outdated type
$qb = $er->createQueryBuilder('type')
->where('type.status = :status')
->orWhere('id = :currentTypeId')
->setParameter('currentTypeId', $someId)
->setParameter('status', 'active')
;
How would detailsAction() have to be called in the example provided in the documentation for JMSPaymentCoreBundle?
It makes use of an order object, which in the function definition is passed as an argument.
public function detailsAction(Order $order)
{
$form = $this->getFormFactory()->create('jms_choose_payment_method', null, array(
'amount' => $order->getAmount(),
[...]
Am I right in assuming that the function can only work when passing an order object at the time it is being called? Are there any other ways of achieving this other than doing something like
return $this->forward('MyBundle:Payment:details', array(
'order' => $order,
));
Yes, you are right. The detailsAction requires an Order object in order to work. So, you will have to have one created by the time you get to this action, otherwise it will throw a 404 error (because the route without an order does not exists).
You should create your own Order entity, which then you can persist to the database (once it's started, that is, the submitted form is correct).
Good luck.
I have an entity that has multiple keys, how would I go about finding the proper object based on multiple ids?
$product = $em->getRepository('AcmeStoreBundle:Product')->find($id);
It's a little confusing what you're asking here. It sounds as though you have an entity with a compound key (primary key relates to multiple columns) and want to find it based on it's primary key values, yes?
If so, the find method will require an array containing values for each of the fields that make up the key:
$product = $em->getRepository('AcmeStoreBundle:Product')->find(array(
'key1' => 'value1',
'key2' => 'value2'
));
Alternatively, you could use findOneBy method. This would be useful for when the combination of the provided fields are not unique as you're able to provide a second argument to define the ordering.
$product = $em->getRepository('AcmeStoreBundle:Product')->findOneBy(array(
'key1' => 'value1',
'key2' => 'value2'
), array('updated_at' => 'DESC'));
See http://symfony.com/doc/2.0/book/doctrine.html#fetching-objects-from-the-database
$product = $em->getRepository('AcmeStoreBundle:Product')->findBy(
array('key1' => 'value1', 'key2'=>'value2')
);
Is there a way to list only the users that has a specific capability, such us "publish_posts" ?
To select users with certain capabilities you can use WP_User_Query with meta_query parameter, because WP stores capabilities as a serialized string in user_meta table.
Also remember that due to availability to have multisite installation capabilities name in user meta looks like wp_table_prefix_capabilities.
global $wpdb;
// meta-key name
$capabilities_field_name=$wpdb->prefix.'capabilities';
//array as argument for our query
$qargs=[
'role' => ['Customer'], // use this if you need to query by role at the same time
'meta_query'=>
[
'relation' => 'OR', // optional if you'll need to select more than
// one capability just add this and create same array
// as down below describing what are you looking for
[
'key' => $capabilities_field_name,
'value' => 'your_role_name',
'compare' => 'LIKE',
],
// here could be same array [key,value,compare]... as above with another capability
// but you'll need to add extra argument showing relationship between them see above 'relation parameter'
],
'number'=> -1 // to select all users
];
$usersQuery=new WP_User_Query($qargs); // instantiate UserQuery with $qargs
$users=$usersQuery->get_results(); // get all results as array of WPUser objects
Hope it helps somebody:)
Note [vars] could be substituted to array(vars), I like [] short syntax but it's supported only since php 5.4.
You can just retrieve all users. Then loop through them in a foreach. Check if the user has a specific capability then push the users to another array and use that array to list them.
$all_users = get_users();
$specific_users = array();
foreach($all_users as $user){
if($user->has_cap('specific_capability')){
$specific_users[] = $user;
}
}
NOTE:
It seemed a nice quick and dirty solution at the time, but now I would recommend writing a query. I do not have the time to investigate this for you, so if the one downvoting this would be so kind to answer this question instead of downvoting an answer which was an actual help to the inquirer, that would be nice.
You can list users with WP_User_Query, but afaik you can only return different roles, not permissions, maybe that's already what you want! There's also a site where you can see the different roles in the wordpress documentation.
You will first need to get all the roles that contain that capability. Then you can search users based on the roles that contain that capability.
$roles = array();
foreach ( wp_roles()->roles as $role_name => $role_obj ) {
if ( ! empty( $role_obj['capabilities']['my_capability_name'] ) ) {
$roles[] = $role_name;
}
}
$users = get_users( array( 'role__in' => $roles ) );
This does not account for if another role has "Deny" on that capability and your users can contain multiple roles. If so then you will also need to add a "user_can()" condition when looping through your Users. https://developer.wordpress.org/reference/functions/user_can/