Wordpress creating plugin for most viewed posts problem? - wordpress

I just want to create plugin that will when visitor(user,visitor,...) visit some post,remember what post,and to increment counter of that post,I wrote this code,but sometimes,counter is incremented,even post isn't viewed,or post with other Id is added to a table.Can someone help me with this,please.I know that there are plugins for this that I'm trying to do,but still want to write this plugin.
function IncrementPostCount($the_content) {
global $post;
global $wpdb;
if(($post->post_status == 'publish') && (int)$post->ID) {
if(is_single()) { // just for single post - not for page
$postID = (int)$post->ID;
$postTitle = urlencode($post->post_title);
$postLink = urlencode(get_permalink($post->ID));
$oneRow = $wpdb->get_row("SELECT * FROM wp_postovi WHERE postAjDi='$postID'");
if(empty ($oneRow)) {
$postCounter = 1;
$data_array = array(
'readnTimes' => $postCounter,
'linkPost'=>$postLink,
'TitlePost'=>$postTitle,
'postAjDi'=>$postID);
$wpdb->insert('wp_najcitaniji_postovi', $data_array);
}
else {
$postCounter = intval($oneRow->readnTimes) + 1;
$data_array = array('readnTimes' => $postCounter);
$where_array = array('postAjDi'=>intval($oneRow->postAjDi));
$wpdb->update('wp_postovi',$data_array,$where_array);
}
return $the_content;
}
return $the_content;
}
}
add_filter('the_content','IncrementPostCount');
Sorry on my bad english,tnx in advance.

Here's how to do that with the postmeta table.
function IncrementPostCount(){
if(is_single()){
global $wp_query;
$count = get_post_meta( $wp_query->post->ID, 'readnTimes', true );
$count = empty($count) ? 1 : $count + 1;
add_post_meta($wp_query->post->ID, 'readnTimes', $count, true) or update_post_meta($wp_query->post->ID, 'readnTimes', $count);
}
}
add_action( 'template_redirect', 'IncrementPostCount' );
Also, it's better to hook it in earlier. That way, the count is only incremented once per page load (the_content can be fired multiple times per page, even on a single page. template_redirect only fires once per request). Also, if you store the data at template_redirect, you can use the updated view count in the template, giving your visitors an even more accurate view count.
And you don't need to worry about database tables, custom SQL, or any of that.

Related

WordPress prevent delete taxonomy

I would like to prevent that some categories are accidentally deleted. For this I use a meta entry for the category to be protected.
I use the following code for this:
// edit: wrong hook! ** add_action( 'delete_term_taxonomy', 'taxonomy_delete_protection', 10, 1 );
add_action( 'pre_delete_term', 'taxonomy_delete_protection', 10, 1 );
function taxonomy_delete_protection ( $term_id )
{
if (get_term_meta ($term_id, 'delete-protect', true) === true)
{
wp_die('Cannot delete this category');
}
}
Unfortunately, instead of my error message, only "Something went wrong" is displayed. Why?
Edit: The `delete_term_taxonomy` is the wrong hook for my code, because it deleted the meta before i can check the meta entry. `pre_delete_term` does fire before anything happens with the category.
The "Why" is because of the following JavaScript that ships with WordPress:
$.post(ajaxurl, data, function(r){
if ( '1' == r ) {
$('#ajax-response').empty();
tr.fadeOut('normal', function(){ tr.remove(); });
/**
* Removes the term from the parent box and the tag cloud.
*
* `data.match(/tag_ID=(\d+)/)[1]` matches the term ID from the data variable.
* This term ID is then used to select the relevant HTML elements:
* The parent box and the tag cloud.
*/
$('select#parent option[value="' + data.match(/tag_ID=(\d+)/)[1] + '"]').remove();
$('a.tag-link-' + data.match(/tag_ID=(\d+)/)[1]).remove();
} else if ( '-1' == r ) {
$('#ajax-response').empty().append('<div class="error"><p>' + wp.i18n.__( 'Sorry, you are not allowed to do that.' ) + '</p></div>');
tr.children().css('backgroundColor', '');
} else {
$('#ajax-response').empty().append('<div class="error"><p>' + wp.i18n.__( 'Something went wrong.' ) + '</p></div>');
tr.children().css('backgroundColor', '');
}
});
The expected response to this POST request is:
'1' if the term was deleted
'-1' if your user doesn't have permission to delete the term.
For all other cases, "Something went wrong" is displayed.
You are terminating the script early with wp_die, yielding an unexpected response, which comes under "other cases".
There isn't a way to provide a custom error message in the notice box here without writing some JavaScript of your own.
This is my current solution, not perfect but it works.
The "Something went wrong" message show up if you delete the taxonomy with the row action. So i unset the "delete" action so it couldn't be triggered this way.
add_filter ('category_row_actions', 'unset_taxonomy_row_actions', 10, 2);
function unset_taxonomy_row_actions ($actions, $term)
{
$delete_protected = get_term_meta ($term->term_id, 'delete-protect', true);
if ($delete_protected)
{
unset ($actions['delete']);
}
return $actions;
}
Then i hide the "Delete" Link in the taxonomy edit form with css. It's still could be triggered if you inspect the site and it's link, but there is no hook to remove this action otherwise.
add_action( 'category_edit_form', 'remove_delete_edit_term_form', 10, 2 );
function remove_delete_edit_term_form ($term, $taxonomy)
{
$delete_protected = get_term_meta ($term->term_id, 'delete-protect', true);
if ($delete_protected)
{
// insert css
echo '<style type="text/css">#delete-link {display: none !important;}</style>';
}
}
Finally the check before deleting the taxonomy. This should catch all other ways, like the bulk action "delete". I didn't found another way yet to stop the script from deleting the taxonomy.
add_action ('pre_delete_term', 'taxonomy_delete_protection', 10, 1 );
function taxonomy_delete_protection ( $term_id )
{
$delete_protected = get_term_meta ($term_id, 'delete-protect', true);
if ($delete_protected)
{
$term = get_term ($term_id);
$error = new WP_Error ();
$error->add (1, '<h2>Delete Protection Active!</h2>You cannot delete "' . $term->name . '"!');
wp_die ($error);
}
}
This solution provides a way to disable all categories from being deleted by a non Admin. This is for anyone like myself who's been searching.
function disable_delete_cat() {
global $wp_taxonomies;
if(!current_user_can('administrator')){
$wp_taxonomies[ 'category' ]->cap->delete_terms = 'do_not_allow';
}
}
add_action('init','disable_delete_cat');
The easiest solution (that will automatically take care of all different places where you can possibly delete the category/term) and in my opinion the most flexible one is using the user_has_cap hook:
function maybeDoNotAllowDeletion($allcaps, $caps, array $args, $user)
{
if ($args[0] !== 'delete_term') return $allcaps;
// you can skip protection for any user here
// let's say that for the default admin with id === 1
if ($args[1] === 1) return $allcaps;
$termId = $args[2];
$term = get_term($termId);
// you can skip protection for all taxonomies except
// some special one - let's say it is called 'sections'
if ($term->taxonomy !== 'sections') return $allcaps;
// you can protect only selected set of terms from
// the 'sections' taxonomy here
$protectedTermIds = [23, 122, 3234];
if (in_array($termId, $protectedTermIds )) {
$allcaps['delete_categories'] = false;
// if you have some custom caps set
$allcaps['delete_sections'] = false;
}
return $allcaps;
}
add_filter('user_has_cap', 'maybeDoNotAllowDeletion', 10, 4);

Wordpress REST API V2 return all posts

I am missing the function to get ALL the posts (or CPT) by using
example.com/wp-json/wp/v2/country/?per_page=-1
or any similiar. The documentation gives as much info as this:
per_page: Maximum number of items to be returned in result set.
Default: 10
And in another question about the per_page we learn that the allowed range is 1 to 100.
In my case there will be a limited number of posts I need to get, but it will be around 200-300. Are there any workarounds to get them all other than fetching everything page per page and stitching it together?
Additional info if it does matter: I am using angular.js
Try this instead for pagination. It returns all the posts on my site.
http://example.com/wp-json/wp/v2/posts/?filter[category_name]=country&filter[posts_per_page]=-1
I get returns above 100 when entered like that and can cap them at 111 etc.
http://example.com/wp-json/wp/v2/posts/?filter[category_name]=country&filter[posts_per_page]=111
For the modern WP scenarios the following function will allow you to give returns great than 99.
add_filter( 'rest_post_collection_params', 'big_json_change_post_per_page', 10, 1 );
function big_json_change_post_per_page( $params ) {
if ( isset( $params['per_page'] ) ) {
$params['per_page']['maximum'] = 200;
}
return $params;
}
As of WP 4.7 you can increase the upper limit of WP REST API requests by hooking into the following filter:
rest_{$this->post_type}_collection_params
This snippet should do the trick for posts:
add_filter( 'rest_post_query', 'se35728943_change_post_per_page', 10, 2 );
function se35728943_change_post_per_page( $args, $request ) {
$max = max( (int) $request->get_param( 'custom_per_page' ), 200 );
$args['posts_per_page'] = $max;
return $args;
}
Note: you can not use standard per_page argument (with value more then 100) in request - wp api will respond with error immediately (so the hook will not help). That's in the above code wee use custom_per_page (you can use any another word).
Similar filter for taxonomies: rest_{$this->taxonomy}_query
Example:
add_filter( 'rest_tags_query', 'se35728943_change_terms_per_page', 2, 10 );
function se35728943_change_terms_per_page( $prepared_args, $request ){
$max = max( 200, (int) $request->get_param( 'custom_per_page' ) );
$prepared_args['number'] = $max;
return $prepared_args;
}
Couldn't get more than 10 with that syntax. Tried http://example.com/wp-json/wp/v2/posts?per_page=100 and worked up to 100.
The bellow approch worked for me. I was able to retrieve posts from a site with 79 246 posts. I used pagination parameters . Within a loop, from 1 to TotalPages available. See the link for doc.
http://mydomain/wp-json/wp/v2/posts?_embed&per_page=100&page=793
per_page = 100 : means 100 posts max to be retrieved per page
page = 793 : means i have 793 pages with 100 posts per page. the last page had only 46 posts
A loop can then be used in a language of your choice.
A simpler way that comply with protocol is to collect all responses, in sequence,
and perform single setState() call. As follows: (error handling omitted for readability)
componentDidMount() {
var uri = "http://your-server";
var totalPages = 0;
var allResults = [];
fetch(uri)
.then(response => {
totalPages = response.headers.get('X-WP-TotalPages');
return response.json()})
.then(results => {
allResults = results;
//console.log('Got results from server', results.length);
for (let i = 2; i <= totalPages ; i++){
fetch(uri + "?page=" + i)
.then(response => {return response.json()})
.then( moreresults => {
allResults = allResults.concat( moreresults );
});
}
this.setState({responses: allResults });
});
}
In WordPress 4.9.6, I had to use rest_{$this->post_type}_query
/* change amount of posts returned by REST API to 100 */
function rest_posts_per_page( $args, $request ) {
$max = max( (int)$request->get_param( 'per_page' ), 100 );
$args['posts_per_page'] = $max;
return $args;
}
add_filter( 'rest_post_query', 'rest_posts_per_page', 10, 2 );
I hope this help, I'm using axios but is the same other
async multipleRequests() {
let npage = 1;
let url = `/sites/mysite.com/wp-json/wp/v2/posts?page=${npage}&per_page=10`;
let { data } = await axios.get(url);
let tempdata = data;
while (tempdata.length > 0) {
npage++;
let url = `/sites/mysyte.com/wp-json/wp/v2/media?page=${npage}&per_page=10`;
let { data } = await axios.get(url);
tempdata = data;
}
}
If you are planning on doing this with other parameters, you can also add categories etc as well. EG:
https://www.website.com/wp-json/wp/v2/posts?categories=61&per_page=100
It's really possible to get more then 100 posts or terms (tags, categories).
You should use rest_{$this->post_type}_query hook (for posts) or rest_{$this->taxonomy}_query hook for terms.
But you have to know, that it's impossible to pass a per_page arg in your GET request with more then 100 value. WP API will throw an error immediately (the hook will not help): per_page must be between 1 (inclusive) and 100 (inclusive) (with 400 http status).
To get around this problem you should pass a per page value in another get argument. And after this to trace this value in your hook.
So the code is:
For posts
add_filter( 'rest_post_query', 's976_rest_post_per_page', 2, 10 );
function s976_rest_post_per_page( array $args, WP_REST_Request $request ) {
$post_per_page = $request->get_param('s976_per_page') ? $request->get_param('s976_per_page') : 10;
$args['posts_per_page'] = $post_per_page;
return $args;
}
For terms
add_filter( 'rest_category_query', 's976_rest_cats_per_page', 2, 10 );
function s976_rest_cats_per_page( array $prepared_args, WP_REST_Request $request ){
$cats_per_page = $request->get_param('s976_per_page') ? $request->get_param('s976_per_page') : 10;
$prepared_args['number'] = $cats_per_page;
return $prepared_args;
}
Of course, for this to work, you have to pass s976_per_page (with any value like 500, 99999) argument in GET request.
I have been using this 's976_per_page' bit of code successfully so many thanks,but It only returns the 'publish' tagged posts,..
How could I get this to grab ALL statuses, or, alternatively, only a set / subset of statuses
Many Thanks
JMB
This solution with javascript worked for me.
According to documents, 100 is maximum to get. If you want more, use offsets and multiple requests. Example:
$i = 0;
$check_for_more = true;
while ( $check_for_more ) {
$offset = $i * 100;
$url = network_site_url( "/wp-json/wp/v2/office?order=asc&orderby=title&per_page=100&offset={$offset}" );
$offices = json_decode( wp_remote_retrieve_body( wp_remote_get( $url ) ) );
if ( $offices ) {
if ( count( $offices ) < 100 ) {
$check_for_more = false;
}
foreach ( $offices as $key => $office ) {
// Do what you want
}
} else {
$check_for_more = false;
}
$i ++;
}
Try this, this works fine (WP 5.8.1)
add_filter( 'rest_{YOU_CPT}_collection_params', function ( $params, WP_Post_Type $post_type ) {
if ( '{YOU_CPT}' === $post_type->name && isset( $params['per_page'] ) ) {
$params['per_page']['maximum'] = PHP_INT_MAX;
}
return $params;
}, 10, 2 );

WordPress running code from template

I have discovered that WordPress is executing code from a template that is in my theme, but when it is not actually on a page using the template.
Although this template will not be used in a live state (since it only runs a loop to create data) I was wondering if anyone else had come across this - and besides shoving everything in functions.php, how to get WP to stop including/running the template when the site load?
I am presuming the reason the code is run, is when WP loads and is looking for templates etc is actual includes(); the template file at some point? which causes the loop to run? if this is the case, does this mean any php in any template file is run?
Here is the code from a the template that is being included (excluding the WP template header) The this code is being run on any page that hasn't got the template set. get_base_question_meta is a function which returns an pre-built array.
$users = get_users( array() );
$base_meta = get_base_question_meta();
$new_meta = array();
foreach ($users as $user ){
if($user->data->ID == 1){
continue;
}
foreach ($base_meta as $question_group_id => $question_groups){
foreach ( $question_groups as $group_id => $sets ){
foreach ($sets as $set_id => $set ){
foreach ($set as $question_id => $question ){
$new_meta[ $group_id ][ $set_id ][ $question_id ] = (string)rand(1, 5);
}
}
}
}
update_user_meta($user->data->ID, 'saved_answers', $new_meta);
}

Get gravity forms fields

I am using the gravity form on my site. I am working on create the custom report for this I have need gravity form fields name and id based on specific form id.Please let me know how I can do it.
I am using the following function but it is showing all forms info based on it. it is looking very hard to parse it. Please let me know any function so I can get fields name easily.
$forms = RGFormsModel::get_forms_by_id(13);
try this
function get_all_form_fields($form_id){
$form = RGFormsModel::get_form_meta($form_id);
$fields = array();
if(is_array($form["fields"])){
foreach($form["fields"] as $field){
if(isset($field["inputs"]) && is_array($field["inputs"])){
foreach($field["inputs"] as $input)
$fields[] = array($input["id"], GFCommon::get_label($field, $input["id"]));
}
else if(!rgar($field, 'displayOnly')){
$fields[] = array($field["id"], GFCommon::get_label($field));
}
}
}
//echo "<pre>";
//print_r($fields);
//echo "</pre>";
return $fields;
}
It's not that hard to parse:
$fields=array();
foreach ( $forms['fields'] as $field ) {
$fields[]=array($field['id'] => $field['inputName']);
}
P.S. I'm assuming you use Gravity Forms < 1.7 as RGFormsModel::get_forms_by_id is a deprecated function since 1.7
// Get the Form fields
$form = RGFormsModel::get_form_meta($form_id);
// Run through the fields to grab an object of the desired field
$field = RGFormsModel::get_field( $form, $field_id );
I use the above to get a specific field I want to filter the value of. The $field contains an object with all the properties you want.
echo $field->label // Gets the label
echo $field->inputName // Gets the name
echo $field->type // Gets the type
echo $field->cssClass // Gets the CSS Classes as a string
You are able to get the entered value/content of a field by using rgpost() and by referencing the id ($field->id).
// Check the entered value of every field
foreach( $form['fields'] as &$field ) {
// Get the content for the specific field
$fieldContent = rgpost( "input_".$field->id );
// Check the content
if ( $fieldContent == ... ){}
}

Nested relations in Drupal

I have a D7 website where users can make content (obviously...). So every node has it's own author. Every author is a member of an organization. But he can be a member of more then one organization. So far the facts.
I would like to create a view where the content is filtered on Author. Very easy, set the relation of the view on "Content's Author" and select the current user as filter.
But what I would like is to filter on the author's organization. So in fact it's a nested relation. Filter the nodes on the current logged in user (that's easy), but how can I filter on the current logged in user's organization?
Ok, the panels didn't work out, so I wrote my own hook :-)
function mymodule_views_pre_view (&$view, &$display_id, &$args) {
// Only execute this script when the view 'fiches_my_thema' is called
if ('fiches_my_thema' == $view->name) {
// Get users thema
global $user;
$userRoles = $user->roles;
$user_themas = array();
// Filter roles so you end up with the "Thema's".
foreach ($userRoles as $key) {
if(strpos($key,'edacteur')) {
$key = str_replace('Redacteur - ','', $key);
$key = str_replace('Eindredacteur - ','', $key);
$user_themas[] = $key;
}
}
// Resolve tid
$terms = taxonomy_get_tree(5);
$allRoles = array();
$arguments = array();
// Assign the 'tid' to a variable
foreach ($terms as $key) {
$singleRoles = $key->name;
$allRoles[] = $singleRoles;
if(in_array($singleRoles, $user_themas)) {
$arguments[] = $key->tid;
}
}
// Only when the arguments are NOT empty, set the arguments
if(!empty($arguments)) {
$finalArguments = implode("+", $arguments);
$args[] = "$finalArguments";
$view->set_arguments($args);
}
}
}

Resources