Hi I'm trying to expose the WordPress menus to the rest api, but I want to make it generic, so I can crate expose any menus with the same code, but something is wrong with my code, t always show Json.pase error, I don't know how to solve this.
here is my code.
//define all the menu positions I need
$menus = array(
'main-menu' => __( 'Main Menu' ),
'other-menu' => __( 'Other Menu' )
);
function register_menus() {
//register the menus in the backend
global $menus;
register_nav_menus($menus);
}
add_action( 'init', 'register_menus' );
add_action( 'rest_api_init', function () {
// create custom route to expose the menus
register_rest_route( 'wp_ang/v1', '/menu', array(
'methods' => 'GET',
'callback' => 'get_menu_items',
)
);
}
);
function get_menu_items() {
// callback to get menus and its items
global $menus;
$rest_menu = [];
foreach ($menus as $key => $value){
$menu_name = $key;
$menu_location = get_nav_menu_locations( );
$menu = wp_get_nav_menu_object( $menu_location[$menu_name] );
$menu_items = wp_get_nav_menu_items( $menu->term_id );
}
return $menus;
}
Then I have this error as a result:
SyntaxError: JSON.parse: unexpected character at line 1 column 1 of
the JSON data
Related
My custom post type "references" has a custom field called "references_count". It has a numeric value.
I have an custom taxonomy called "country" with a custom field called "country_count" for the terms.
Background:
The custom post type "references" saves cities with a number of clients in this city. This value is saved in the field "references_count". In the custom taxonomy there are countries. For each country, there is a total number of references.
Example:
In the city of "Berlin" there are 3 clients. In the city of "Munich" there are 2 clients. The taxonomy term "Germany" includes the sum of all cities in this country. So the value of "country_count" in this example for the taxonomy term "Germany" is 5, being the sum of the references of each city.
I wrote this code which is working, if I'm saving each individual taxonomy term.
add_action( 'edited_country', 'update_counter_for_countries', 10, 2 );
function update_counter_for_countries( $term_id ) {
// Get posts with term
$args = array(
'post_type' => 'reference',
'posts_per_page' => -1,
'tax_query' => array(
array(
'taxonomy' => 'country',
'field' => 'term_id',
'terms' => $term_id
)
)
);
$the_query = new WP_Query( $args );
// sum values in posts
$sumTerm = 0;
if ( $the_query->have_posts() ) {
while ( $the_query->have_posts() ) {
$the_query->the_post();
$number = get_field( 'references_count', get_the_ID() );
$sumTerm = $sumTerm + $number;
}
}
wp_reset_postdata();
// update field in term
update_field( 'country_count', $sumTerm, 'country'.'_'.$term_id );
}
Problem:
I have more than 100 countries (taxonomy terms), so I have to save each term individually to get things going.
What I am looking for: Is there a way to update / save all custom taxonomy terms at once, so I don't have to update each term seperately? I checked out a lot of plugins, but couldn't find any plugin which gives the possibility of "bulk edit" or "bulk save" taxonomy terms. I would prefer a solution without plugin if possible. I am very grateful for any hint, thank you very much.
You can use this code to update all terms in one go.
Just make sure to backup your database in case needed.
This code will loop through all the terms and will only run once. after that you can remove this code.
Just to make this code run only on your IP, change 111.111.111.111 to your IP ADDRESS.
if($_SERVER["REMOTE_ADDR"]=='111.111.111.111'){
//run only my ip
add_action("init","update_all_terms_in_one_go");
}
function update_all_terms_in_one_go(){
session_start();
if(isset($_SESSION['all_terms_updated']) && $_SESSION['all_terms_updated'] == "done"){
return;
}
$taxonomy = "country";
$terms = get_terms([
'taxonomy' => $taxonomy,
'hide_empty' => false,
]);
foreach ($terms as $term) {
update_counter_for_countries( $term->term_id );
}
$_SESSION['all_terms_updated'] = "done";
echo "ALL TAXONOMY TERMS UPDATED";
die();
}
function update_counter_for_countries( $term_id ) {
// Get posts with term
$args = array(
'post_type' => 'reference',
'posts_per_page' => -1,
'tax_query' => array(
array(
'taxonomy' => 'country',
'field' => 'term_id',
'terms' => $term_id
)
)
);
$the_query = new WP_Query( $args );
// sum values in posts
$sumTerm = 0;
if ( $the_query->have_posts() ) {
while ( $the_query->have_posts() ) {
$the_query->the_post();
$number = get_field( 'references_count', get_the_ID() );
$sumTerm = $sumTerm + $number;
}
}
wp_reset_postdata();
// update field in term
update_field( 'country_count', $sumTerm, 'country'.'_'.$term_id );
}
I wanted to have a neat admin page with a button to bulk update all my taxonomy terms. The process should work using AJAX so it can take a while without confusing the user. There should be status messages.
So in the first step I added a new admin page to the wordpress backend.
add_action( 'admin_menu', array( $this, 'my_admin_page' ) );
function my_admin_page() {
add_menu_page(
__('Bulk Terms'), // page title
__('Bulk Terms'), // menu title
'manage_options', // user capabilities
'options-page', // menu slug
'my_output_function', // output function
'dashicons-admin-generic', // menu icon
77 // menu position
);
}
In the output function I put a form with a button to bulk update terms. And some status messages.
function my_output_function() {
echo '<div class="wrap">';
echo '<form action="admin.php?page=options-page" method="post">';
wp_nonce_field( 'ajax_validation', 'nonce' ); // security feature
submit_button('Update Terms', 'primary', 'submitOptions', false);
echo '</form>';
echo '<div id="processing" style="display:none;">Please wait</div>';
echo '<div id="error" style="display:none;">Something went wrong</div>';
echo '<div id="success" style="display:none;">Done!</div>';
echo '</div>';
}
In the second step I had to enqueue script file for ajax calls:
add_action( 'admin_enqueue_scripts', 'my_ajax_scripts' );
function my_ajax_scripts() {
// Check if on specific admin page
global $pagenow;
if (( $pagenow == 'admin.php' ) && ($_GET['page'] == 'options-page')):
wp_enqueue_script( 'ajaxcalls', plugin_dir_url( __FILE__ ).'/js/ajax-calls.js', array('jquery'), '1.0.0', true );
wp_localize_script( 'ajaxcalls', 'ajax_object', array(
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'ajaxnonce' => wp_create_nonce( 'ajax_validation' )
) );
endif;
}
And create the function to bulk update all my taxnomy terms:
function options_page_action() {
$taxonomy = "country";
$terms = get_terms([
'taxonomy' => $taxonomy,
'hide_empty' => false,
]);
foreach ($terms as $term) {
$term_id = $term->term_id;
// Get posts with term
$args = array(
'post_type' => 'reference',
'posts_per_page' => -1,
'tax_query' => array(
array(
'taxonomy' => 'country',
'field' => 'term_id',
'terms' => $term_id
)
)
);
$the_query = new WP_Query( $args );
// sum values in posts
$sumTerm = 0;
if ( $the_query->have_posts() ) {
while ( $the_query->have_posts() ) {
$the_query->the_post();
$number = get_field( 'references_count', get_the_ID() );
$sumTerm = $sumTerm + $number;
}
}
wp_reset_postdata();
// update field in term
update_field( 'country_count', $sumTerm, 'country'.'_'.$term_id );
}
$result = array( 'status' => 'success' ); // create response
wp_send_json_success( $result ); // send response
wp_die(); // close ajax request
}
As the third step, in my ajax_calls.js file I take the click event to call the function for updating the taxonomy terms using ajax.
$( '#submitOptions' ).click( function(event) {
event.preventDefault();
$('#submitOptions').css('cssText','display:none;');
$('#processing').css('cssText','display: block;');
$.ajax({
type: 'POST',
url: ajax_object.ajaxurl,
data: {
action: 'options_page_action',
nonce: ajax_object.ajaxnonce
},
success: function( response ) {
if( response['data']['status'] == 'success' ) {
$('#processing').css('cssText','display:none;');
$('#success').css('cssText','display:block;');
}
},
error: function() {
$('#processing').css('cssText','display:none;');
$('#error').css('cssText','display:block;');
}
});
});
There are messages indicating that the function is running and it show messages when it's done or has an error. This way the user will always know what's going on when bulk updating terms.
*Context
I am new to WordPress plugin development and I have just started developing one. Which is basically a blog slider plugin. The concept is very simple. The user can use shortcodes with parameters to determine which posts and how many posts to be shown. There is no admin settings page for changing the appearance of the slider though, but I'll work on that. The user have to use shortcode whenever the slider is needed.
The development part is also simple. I am checking the parameters that the user passes through the shortcode. And then a query runs and returns an array of posts and then displays the structure. Very simple.
*Problem
Now I am trying to make the plugin options more dynamic (via shortcode) i.e. the user can control whether the slider should auto-play or not, loop should be enabled or not, pause on hover, dots/nav hide or show etc. I am using owl carousel for this slider. So that means I have to change the attributes of the slider in JavaScript file.
The basic idea is to take the parameters from function's $atts array, and pass it to the JavaScript file. I know this can be accomplished using wp_localize_script, but I cannot figure out how.
Here is my code to make things more clear.
mainfile.php
add_shortcode( 'sp-slider', 'sp_slider_get_posts');
function sp_slider_get_posts( $atts ) {
$values = shortcode_atts( array(
'number' => '-1',
'category-id' => '', //DEFAULT VALUE null, WILL BE REPLACED ONCE USER DECLARES IN SHORTCODE
'category-name' => '',
'orderby' => '',
'order' => '',
'include-posts' => '',
'exclude-posts' => '',
'author-id' => '',
'author-name' => '',
'autoplay' => ''
), $atts );
if( !empty($values['number']) ||
!empty($values['category-id']) ||
!empty($values['category-name']) ||
!empty($values['orderby']) ||
!empty($values['order']) ||
!empty($values['include-posts']) ||
!empty($values['exclude-posts']) ||
!empty($values['author-id']) ||
!empty($values['author-name']) ||
!empty($values['autoplay'])) {
$args = array(
'numberposts' => $values['number'],
'cat' => $values['category-id'],
'category_name' => $values['category-name'],
'orderby' => $values['orderby'],
'order' => $values['order'],
'include' => $values['include-posts'],
'exclude' => $values['exclude-posts'],
'meta_key' => '',
'meta_value' => '',
'post_parent' => '',
'author' => $values['author-id'],
'author_name' => $values['author-name'],
'post_status' => 'publish',
'suppress_filters' => true,
'fields' => '',
);
$autoplay = $values['autoplay']; //GET AUTOPLAY VALUE. NO IDEA HOW TO USE IT. SO I TRIED THE FOLLOWING
// THE FOLLOWING FUNCTION HOLDS THE wp_localize_script FUNCTION, WHICH IS DECLARED AT THE END OF THIS CURRENT FUNCTION sp_slider_get_posts.
sp_carousel_settings($autoplay); //PASSING THE USER INPUT
$posts_array = get_posts( $args );
if( !empty( $posts_array ) ) {
$output = "<div class='sp-slider-wrapper'>";
$output .= '<div class="owl-carousel owl-theme">';
foreach( $posts_array as $post ) {
include( "includes/inc_slider_section.php"); // ALL THE SLIDER STRUCTURE IS IN DIFFERENT FILE WHICH IS INCLUDED HERE
}
$output .="</div>";
$output .="</div>";
}
return $output;
}
}
// HERE IS sp_carousel_settings() DECLARATION
function sp_carousel_settings( $autoplay ) {
$carousel_settings = array( 'autoplay' => $autoplay);
wp_localize_script( 'sp_main_js', 'carousel_settings', $carousel_settings );
}
add_action( 'wp_enqueue_scripts', 'sp_carousel_settings' );
mainjs.js
$(document).ready(function() {
...
...
var autoplay= '';
if(typeof carousel_settings !== 'undefined') {
autoplay = carousel_settings.autoplay;
}
else {
autoplay = false;
}
$('.owl-carousel').owlCarousel({
loop:true,
autoplay:autoplay,
autoplayTimeout:2000,
autoplayHoverPause:true,
...
...
}
})
This doesn't work. Here I would like to mention that, in add_action() function, if i put wp_footer instead of wp_enqueue_scripts, it adds the script to the footer of the page (I have checked it by viewing the source) but the autoplay value is null.
Another thing i would mention is that, in sp_carousel_settings() function, instead of passing the $autoplay variable, if I write any static value like this $carousel_settings = array( 'autoplay' => true);, it works.
*I tried echoing out $autoplay inside sp_carousel_settings() and it prints the value! But does not get to the js file.
*I tried checking the value of $autoplay and pass a hardcore sting inside wp_localize_script like
function sp_carousel_settings( $autoplay ) {
if( $autoplay == "true" ) {
echo "Inside!!!";
$carousel_settings = array( 'autoplay' => true);
}
else {
echo "Outside!!!";
$carousel_settings = array( 'autoplay' => false);
}
wp_localize_script( 'sp_main_js', 'carousel_settings', $carousel_settings );
}
add_action( 'wp_footer', 'sp_carousel_settings' );
Does not work. EVEN it prints out "Inside!!!" but does not pass true in autoplay. The value is always false.
*I have registered the js file in the beginning of the plugin, where the plugin activates and gets initialized. Like this
function sp_slider_include_css_js() {
...
...
wp_register_script('sp_main_js', plugins_url('assets/js/main.js',__FILE__));
wp_enqueue_script('sp_main_js');
...
...
}
add_action( 'wp_footer','sp_slider_include_css_js');
*I have searched internet for help but was unable to find. Any reference will be appreciated.
*I know that I might be using the function in an improper way. I am clueless (and new to this).
Have to do some changes like,
Step 1:
function sp_carousel_settings() {
wp_register_script( 'sp_main_js', 'you/file/path/here', array( 'jquery' ), '1.0', true);
}
add_action( 'wp_enqueue_scripts', 'sp_carousel_settings' );
Step 2:
add_shortcode( 'sp-slider', 'sp_slider_get_posts');
function sp_slider_get_posts( $atts ) {
.....
$carousel_settings = array( 'autoplay' => $autoplay);
wp_localize_script( 'sp_main_js', 'carousel_settings', $carousel_settings );
wp_enqueue_script( 'sp_main_js' );
......
}
This question makes me crazy for almost 2 weeks. I know I am not expert in Wordpress, so I am seeking for help here.
I have create a href that when user click it will go to new page.
Add Class2
This href post the Post id. Url display:
[http://localhost/dev6/create-class/?post=289][1]
create-class page:
At create-class page,I am using GET method to display post id from url
$post = $_GET['post'];
I have acf form in create-class page for create new post. In this form, there have dynamic select field but the select field not display any data.
<?php acf_form(array(
'post_id' => 'new_post',
'field_groups' => array(150),
'post_title' => false,
'post_content' => false,
'new_post' => array(
'post_type' => 'classes',
'post_status' => 'publish',
),
'return' => '%post_url%',
'submit_value' => 'Submit',
//'updated_message' => 'Course Submit!',
)); ?>
in my function.php I create function for dynamic select:
function acf_load_t_first_name2_field_choices($field) {
global $post;
//$post = $_GET['post'];
// reset choices
$field['choices'] = array();
// get the textarea value from options page without any formatting
$choices = get_field('t_first_name',$post->ID);
// loop through array and add to field 'choices'
if( is_array($choices) ) {
foreach( $choices as $choice ) {
$field['choices'][ $choice ] = $choice;
}
}
// return the field
return $field;
}
add_filter('acf/load_field/name=t_first_name2', 'acf_load_t_first_name2_field_choices');
Is there something wrong with my code?
I don't believe this will work in your create-class template:
$post = $_GET['post'];
You will need to set something like this up in your functions.php file:
function custom_query_vars_filter($vars) {
$vars[] .= 'post';
return $vars;
}
add_filter( 'query_vars', 'custom_query_vars_filter' );
Then, in your create-class template you can get the variable from the URL like this:
$post = get_query_var('post');
See if that gets you going in the right direction.
How can I fetch only post title, excerpt of all the posts of my WordPress blog using JSON api.
Currently, I am using https://www.example.com/wp-json/wp/v2/posts, which returns a lot of data that slows down the whole process. Is there any url where I can fetch only selected fields?
Have you considered writing your own API endpoints? https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-custom-endpoints/
Something like this would probably work for you where your endpoint becomes http://example.com/wp-json/myplugin/v1/post-titles:
function my_awesome_func( $data ) {
$args = array(
'post_type' => 'post',
);
$query = new WP_Query( $args );
$arr = array();
while ( $query->have_posts() ) {
$query->the_post();
$titles = get_the_title();
array_push($arr, $titles);
}
return $arr;
}
add_action( 'rest_api_init', function () {
register_rest_route( 'myplugin/v1', '/post-titles', array(
'methods' => 'GET',
'callback' => 'my_awesome_func',
) );
} );
I created a gallery post type (as part of a plugin) that contains besides a title and some meta information also a wp_list_table that queries those attachments which have the current post as post_parent. I ran into a problem when suddenly my publish button stopped working. No matter if I'm creating a new gallery or if I'm editing an old one, once I click on update/publish my changes get lost and I end up on edit.php.
Anybody knows what that's all about?
I where able to figure out where the problem seems to be. It's in my list_table class which inherits from wp_list_table. after commenting out some unimportant functions i ended up with a different error but still no new or updated gallery. Now I get the are you sure you want to do this page.
Even the most basic class won't work...
if( ! class_exists( 'WP_List_Table' ) ) {
require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
}
class Yard_Attachment_Table extends WP_List_Table {
function __construct() {
global $status, $page;
parent::__construct( array(
'singular' => 'yard Attachment',
'plural' => 'yard Attachments',
'ajax' => false
) );
}
function column_default($item, $column_name) {
return 'default';
}
function get_columns(){
$columns = array(
'checkbox' => '<input type="checkbox" />', //for simplicity its not 'cb'
'thumb' => 'Thumbnail',
'title' => 'Titel',
'pos' => 'Position'
);
return $columns;
}
function prepare_items() {
global $wpdb;
$columns = $this->get_columns();
$hidden = array();
$sortable = $this->get_sortable_columns();
$this->_column_headers = array($columns, $hidden, $sortable);
if (isset($_REQUEST['post'])) {
$query = " SELECT *
FROM $wpdb->posts
WHERE post_type = 'attachment'
AND post_parent = {$_REQUEST['post']}";
$data = $wpdb->get_results($query, ARRAY_A);
} else {
$data = array();
}
$this->items = $data;
}
}
In the plugin class' constructor I use
add_action('add_meta_boxes_yard_gallery', array($this, 'yard_metaboxes'));.
In yard_metaboxes I use add_meta_box and in the function I have as a callback i'm creating a new instance of my table class and I call prepare_items() and display()
Turning error_reporting on my page dies with these messages:
Strict Standards: Only variables should be passed by reference in /Applications/MAMP/htdocs/Web/ChristophRokitta/wp v.1.0/wp-includes/pomo/mo.php on line 210
Warning: Cannot modify header information - headers already sent by (output started at /Applications/MAMP/htdocs/Web/ChristophRokitta/wp v.1.0/wp-includes/pomo/mo.php:210) in /Applications/MAMP/htdocs/Web/ChristophRokitta/wp v.1.0/wp-includes/pluggable.php on line 876
BTW I'm not localizing.
Please help! If i had more reputation I'd offer it.
Adding the meta box code
in my plugin file:
require_once( plugin_dir_path( __FILE__ ) . 'class-yard.php' );
Yard::get_instance();
in my class-yard file the meta box methods are at the bottom:
class Yard {
protected static $instance = null;
private function __construct() {
include_once('class-yard-attachments.php');
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_styles' ) );
add_action('after_setup_theme', array($this, 'yard_thumbnails'));
add_action('init', array($this, 'yard_post_type'));
add_action('init', array($this, 'yard_taxonomies'));
add_filter('manage_yard_gallery_posts_columns', array($this, 'yard_add_columns'));
add_action('manage_posts_custom_column', array($this, 'yard_fill_columns'));
add_action('add_meta_boxes_yard_gallery', array($this, 'yard_metaboxes'));
}
public static function get_instance() {// If the single instance hasn't been set, set it now.
if (null == self::$instance ) {
self::$instance = new self;
}
return self::$instance;
}
public function enqueue_admin_styles() {
$screen = get_current_screen();
if ($screen->post_type == 'yard_gallery') {
wp_register_style( 'yard-gallery-style', plugins_url('css/yard-gallery-style.css', __FILE__) );
wp_enqueue_style( 'yard-gallery-style' );
}
}
public function yard_thumbnails() {
//add_image_size('yard-thumbnail', 100, 100, true);
}
public function yard_post_type() {
$gallery_labels = array(
'name' => 'Galerien',
'singular_name' => 'Galerie',
'all_items' => 'Alle Galerien',
'add_new' => 'Erstellen',
'add_new_item' => 'Neue Galerie erstellen',
'edit_item' => 'Galerie bearbeiten',
'new_item' => 'Neue Galerie',
'view' => 'Galerie anzeigen',
'view_item' => 'Gallerie anzeigen',
'search_items' => 'Galerie durchsuchen',
'not_found' => 'Keine Galerien gefunden',
'not_found_in_trash' => 'Es befinden sich keine Galerien im Papierkorb',
'parent_item_colon' => ''
);
$gallery_args = array(
'labels' => $gallery_labels,
'public' => true,
// 'publicly_queryable' => true,
// 'show_ui' => true,
// 'show_in_menu' => true,
// 'query_var' => true,
'rewrite' => true,
// 'capability_type' => 'post',
// 'hierarchical' => false,
'menu_position' => 12,
'supports' => array(
'title'
)
// 'menu_icon' => plugin_dir_url(__FILE__) . '/assets/icon_16_grey.png'//16x16 png if you want an icon
);
register_post_type('yard_gallery', $gallery_args);
}
public function yard_taxonomies() {
register_taxonomy(
'yard_work_type',
'yard_gallery',
array(
'hierarchical' => true,
'label' => 'Art der Arbeit'
)
);
register_taxonomy(
'yard_subject',
'yard_gallery',
array(
'hierarchical' => true,
'label' => 'Motiv'
)
);
}
public function yard_add_columns( $columns ){
$columns = array(
'cb' => '<input type="checkbox">',
'yard_post_thumb' => 'Thumbnail',
'title' => 'Bezeichnung',
'yard_pos' => 'Position',
'date' => 'Datum'
);
return $columns;
}
public function yard_fill_columns( $column ) {
global $post;
switch ($column) {
case 'yard_post_thumb' :
echo the_post_thumbnail('admin-list-thumb');
break;
}
}
public function yard_metaboxes( $post ) {
global $wp_meta_boxes;
add_meta_box(
'yard-attachments',
'Bilder',
array($this, 'get_yard_attachment_table'),
'yard_gallery'
);
}
public function get_yard_attachment_table() {
$yard_list_table = new Yard_Attachment_Table();
$yard_list_table->prepare_items();
$yard_list_table->display();
}
}
Strict Standards: Only variables should be passed by reference in /Applications/MAMP/htdocs/Web/ChristophRokitta/wp v.1.0/wp-includes/pomo/mo.php on line 210
The error message tells it all. The ".../popo/mo.php" file has to do with (is related to) the Wordpress translation. (I bet you're using Wordpress with German language files).
I can't see what could be wrong in the code you've posted here, but something is interfering with translation. Looking at what the error message tells us, some variable that Wordpress tries to translate fails to be translated since it's not the correct type.
Warning: Cannot modify header information - headers already sent by (output started at /Applications/MAMP/htdocs/Web/ChristophRokitta/wp v.1.0/wp-includes/pomo/mo.php:210) in /Applications/MAMP/htdocs/Web/ChristophRokitta/wp v.1.0/wp-includes/pluggable.php on line 876
This is a logic result of the previous error message and the headers Wordpress tries to send to the browser.
What's happening: the first error message is being pushed to the client and flushed to the browser screen. Next, Wordpress tries to send it's usual headers and produces an error while doing so because headers have to be send before ANY content is being send to the client.
In other words: the "Cannot modify header information" error always comes up when you echo something to screen and then try to send "header(...)" information. In this case, the translation problem produces the first error message and then Wordpress tries to send headers, which fails and produces the second error message.
TIPS
Check everything you're doing which is related to translation (read: wherever you are passing "German" and/or "English" language strings)
and even more important
Make sure that you're actually passing the correct type(s)... looking at the error and your code, it could well be you're passing a class, a class reference, or another object somewhere instead of the expected variable.