WordPress/PHP get all navigation links - php

I am working on a small plugin and am wondering how can I get all links in primary navigation? Wondering if it's possible without knowing the name or slug of the menu in a particular theme.
Below I was trying to get all menu links and return them in a script tag but it didn't work out too well. It ended up returning a bunch of metadata and on one site it broke the site completely.
For now, the script tag is only for testing purposes, where I am going to use the navigation links in an unordered list later on.
function get_nav_menu_items_by_location( $location, $args = [] ) {
?>
<script type = "application/ld+json" alt="hejtest" >
<?
// Get all locations
$locations = get_nav_menu_locations();
// Get object id by location
$object = wp_get_nav_menu_object( $locations[$location] );
// Get menu items by menu name
$menu_items = wp_get_nav_menu_items( $object->name, $args );
// Return menu post objects
return $menu_items;
?>
</script>
<?
}
add_action('wp_head', 'get_nav_menu_items_by_location');
```

You can't "return" data from PHP to JS. The return keyword tells PHP that you've finished the get_nav_menu_items_by_location function, and to give that value to the calling PHP code.
To run JavaScript, you need to output some code that the browser will then execute when it receives the HTML.
If you want to output some data in a way that's easy for JS to read, you can abuse the fact that JSON format is valid JS code, and write echo json_encode($menu_items);. You also need to output code to assign it to a variable, or pass it to a function.
If the function you're writing is expected to return some HTML, you don't want to use echo, and also don't want to use ?>. Instead, you want to build up a PHP string containing the HTML and return that.
So you might end up with this:
function get_nav_menu_items_by_location( $location, $args = [] ) {
$html = '<script type="application/ld+json" alt="hejtest">';
// Get all locations
$locations = get_nav_menu_locations();
// Get object id by location
$object = wp_get_nav_menu_object( $locations[$location] );
// Get menu items by menu name
$menu_items = wp_get_nav_menu_items( $object->name, $args );
$html .= "var my_menu_items = " . json_encode($menu_items) . ";";
$html .= "</script>";
return $html;
}
add_action('wp_head', 'get_nav_menu_items_by_location');

Related

How to use PHP variable with a Wordpress Shortcode of AAWP Plugin

I use Wordpress with the GeneratePress Theme. A feature of this theme called "Elements" let you write php code which will be executed on a specific hook. These Hooks can be found here: https://docs.generatepress.com/article/hooks-visual-guide/
I use the AAWP plugin to show an amazon bestseller list. I want to get the Wordpress category and place it into the bestseller parameter of the aawp shortcode to get Products for the respective categories.
I already read posts here about using php variables in wordpress shortcodes but it seems that something other than the syntax is the problem.
I have this code
<?php
$categories = get_the_category();
if ( ! empty($categories ) ) {
$category = $categories[0];
$name = $category->name;
$bestseller = 'bestseller="'.$name.'"';
$shortCode = '[aawp grid="3" '.$bestseller.' items="3" filter_items="20" orderby="percentage_saved" order="desc"]';
echo do_shortcode($shortCode);
}
?>
The amazon list doesnt appear on my page. It seems that the "bestseller" parameter is neccesarry in order to get shown.
The variable doesnt really get recognized.
When I remove the variable and replace it with a hardcoded bestseller parameter its working fine.
When I use this code:
<?php
$categories = get_the_category();
if ( ! empty($categories ) ) {
$category = $categories[0];
$name = $category->name;
$bestseller = 'bestseller="'.$name.'"';
$shortCode = '[aawp template="angebot-vertical" grid="3" bestseller="'.$name.'" items="3" filter_items="20" orderby="percentage_saved" order="desc"]';
echo do_shortcode($shortCode);
}
?>
It seems that the bestseller value doesnt get read but the "empty" bestseller parameter is enough to show the amazon list, so it just shows random products.
How can I make this work? I just want to place a variable as a value into the "bestseller" parameter. Should be the easiest thing but it doesnt work in the scope of this GeneratePress Elements Hook whith the AAWP shortcode
You're possibly not getting what you believe you need back from get_the_category(). Assuming you're able to get the category id you can use get_cat_name() function to return the category name.
<?php
$cat_name = get_cat_name($category_id);
if ( ! empty($cat_name) ) {
$shortCode = '[aawp template="angebot-vertical" grid="3" bestseller="'.$cat_name.'" items="3" filter_items="20" orderby="percentage_saved" order="desc"]';
echo do_shortcode($shortCode);
}
?>

Create WordPress gallery shortcode from Advanced Custom Fields

I am following the instructions set out in the ACF Gallery page at https://www.advancedcustomfields.com/resources/gallery/ in how to create a native Wordpress gallery using the shortcode and dynamically populating the item IDs from the data in the ACF Gallery field.
Example:
EDIT: I have slightly modified the code to include definition for $image_ids
<?php
// Load value (array of ids).
$images = get_field('product_images');
$image_ids = get_field('product_images', false, false);
if( $images ) {
// Generate string of ids ("123,456,789").
$images_string = implode( ',', $image_ids );
// Generate and do shortcode.
$shortcode = sprintf( '', $images_string );
echo do_shortcode( $shortcode );
}
Now my problem is that the an error returns saying that the value for $image_ids is undefined, and rightly so, can't see where that gets defined at all.
I've got some older code that I used to use:
<?php
// different product sizes (gallery)
if(get_field('product_images')) : ?>
<h3>Product Images</h3>
<?php
$image_ids = get_field('product_images', false, false);
$shortcode = '[' . 'gallery ids="' . implode(',', $image_ids) . '"]';
echo do_shortcode( $shortcode );
endif;
?>
This code does work but returns an error php notice array to string conversion in jetpack-carousel. Yes I am using the 'Tiled Galleries Carousel Without Jetpack' plugin.
https://wordpress.org/support/topic/php-notice-array-to-string-conversion-in-jetpack-carousel/page/2/
I really want to follow the recommended way set out in the ACF documentation but it does not work for me. What am I doing wrong?
I don't have ACF installed but after reading their manual, I see a few issues with your code.
Problem one: you are using both $images and $images_ids. Ultimately, both of them are doing the same job and that is to get back the ids array for you. Their data can be different from the last two arguments.
Nonetheless, when you check to see if there is something, you check and evaluation with $images, but then you use $images_ids for your short_code string composition. For the error, I think that is because the version without the optional arguments returned a value while the one($images_ids) that utilized the optional arguments did not return a value but was being utilized anyway by the if clause.
I think you kind of have to figure out, which get_field version you want to use. The one with 3 args or the one with 1 arg.
This was edited after I noticed something, for why you are not getting anything, you may want to contact ACF to update their manual. That sprintf() statement will not do anything. It just going to generate a blank string that all. You may need to alter that sprintf() like the below to follow your old statement, if it still shows array to string conversion error, you would need to debug that.
$image_ids = get_field('product_images', false, false);
if( $image_ids ) {
// Generate string of ids ("123,456,789").
$images_string = implode( ',', $image_ids );
// Generate and do shortcode.
$shortcode = sprintf( '[gallery ids="%s"]', $images_string );
echo do_shortcode( $shortcode );
}
As far as I've tried, the example on the ACF website (https://www.advancedcustomfields.com/resources/gallery/) isn't correct. Here's a less elegant method that worked for me.
<?php
// Get the Gallery Array created by ACF
$galleryarray = get_sub_field('gallery');
// Create an empty array to input the ID's in to
$galleryids = array();
// Loop through the Gallery array
foreach ( $galleryarray as $image ) {
// Grab the image ID
$imageid = $image['id'];
// Put the image ID in to the empty array
array_push($galleryids, $imageid);
}
// Convert the new array into a string, values separated by a comma
$images = implode(',', $galleryids);
// Run the default WordPress Gallery shortcode
echo do_shortcode( '[gallery ids="'.$images.'"]' );
?>

Change/filter text of link of navigation menu

What I have:
I have a log-in/log-out link in a standard WordPress navigation menu. So far, I've conditionally filtered the URL to either the necessary log-on or log-out urls.
What I need:
I also need to conditionally change the textual value of a link (menu item) in the navigation menu.
My code:
add_filter( 'nav_menu_link_attributes', 'menu_override_b', 10, 3 );
function menu_override_b( $atts, $item, $args ) {
if ( is_user_logged_in() ) {
$url = wp_logout_url();
$newlink = str_replace("http://--loginout--", $url, $atts[href]);
$atts[href] = $newlink;
//None of the following work...
/*
$title ="Logout";
$atts[title] = $title;
$atts[post_excerpt] = $title;
$atts[description] = $title;
$atts[attr_title] = $title;
$atts[post_title] = $title;
$atts[post_content] = $title;
*/
}
else{
$url = "/somewhere/else";
$newlink = str_replace("http://--loginout--", $url, $atts[href]);
$atts[href] = $newlink;
//None of the following work...
/*
$title ="Login";
$atts[title] = $title;
$atts[post_excerpt] = $title;
$atts[description] = $title;
$atts[attr_title] = $title;
$atts[post_title] = $title;
$atts[post_content] = $title;
*/
}
return $atts;
}
List of WordPress menu item attributes
I know it's an old post but in case anyone's looking...
You need to replace $atts[href] with $atts['href'] in your code.
I use this really nice plugin from here
https://wordpress.org/plugins/menu-items-visibility-control/
This allows you to set a call back to conditionally hide menu items, what I would do is have a menu item for when they are logged in and another for when they are logged out, and just swap them.
I'd have to look up the exact code you would need for your callback, but It should go in the theme functions file, then you just run that function on the navigation items, as per the plugins instructions.
It's a bit of a different approach then you are currently doing, but it might be a bit cleaner to keep the navigation items separate and fully functional ( not reliant on external code for their content, only their visibility )
It's also very easy to expand this to other links,
Hope it helps.
--update looking at it, it might have the functionality you need already built in. I use it for product subscriptions from a third party app etc.. but same idea really.

How pull in other pages' templates and content and output those on a "combining" page?

Imagine I have the following setup:
* Combining Page (Template: Combine Template)
* Sub Page 1 (Template: Basic Template)
* Sub Page 2 (Template: Other Template)
* Sub Page 3 (Template: Basic Template)
So I have three sub pages, two of which have the same template (which uses custom fields as well as regular content). I want the parent page's template to be able to work like this:
PSEUDO-CODE:
//Show the content for this combine page (e.g. a title)
if ( have_posts() ) : while ...this is the main loop...
$wp_query = new WP_Query();
$all_pages = $wp_query->query( array( "post_type" => "page", "posts_per_page" => -1 ) );
//Get child pages
$child_pages = get_page_children( $post->ID, $all_pages );
//Loop through child pages so we can add their HTML (made from applying their content to their templates)
foreach( $child_pages as $child_page )
{
/** WHAT DO I DO HERE? **/
//Pseudo code
$child_page_template = get_page_template( $child_page->page_name );
$child_output = apply_to( $child_page_template, get_page_content( $child_page->content ) );
}
EDIT
In addition, on the child page, I get a custom field and loop through it:
$values = get_post_custom_values( "mycustomfield" );
foreach ( $values as $value ) echo $value . "<br>";
END EDIT
How would I do this?
Is there anything built in to do this? Or would I need to use output buffers to isolate everything and print each to a buffer from within a function?
It seems like your perspective is just incorrect for the goal you're trying to reach.
Your pseudo code is reminiscent of a funky iframe style approach. Simply breaking your children pages into what WordPress calls "Template Parts" (basically PHP includes) would be the way to solve this (assuming I understand you correctly). Since Template Parts can be recycled and also have some WordPress-specific benefits when it comes to looping and passing arguments and stuff.

Changing wp_title from inside my Wordpress Plugin

nearly finished my wp plugin for an estate agent,
I spidered the site for 404's etc, i noticed that my property details pages were spider'd in which all 45 page titles were : ( details | sitename ) (page titles are shown dynamicly from an ID being passed via querystring)
now I've got my nice urls fixed, urls look like this...
wpsite.com/details/20043/property+for+sale+in+this+area
In Which...
propid = 20043
propname = property+for+sale+in+this+area
both of these are querystring values which are used to re-write the urls.
'query_vars' => array('propid', 'propname'),
'rules' =>
array( '(.+?)/([^/]+)/([^/]+)/?$' => 'index.php?pagename=$matches[1]&propid=$matches[2]&propname=$matches[3]' )
);
Now when the property details page is loaded im trying to hook into the wordpress filter
wp_title but this isnt working the way i expected..
this is the code im using to generate the titles
function wp_myplugin_property_title()
{
$wp_acquaint_id = get_option("wp_system_id");
$propid = get_query_var('propid');
if(isset($propid)){
$seotitle = wp_myplugin_seo_title($propid);
}else{
$seotitle = "TEST Title";
}
return $seotitle;
}
if( is_page('details') ){
add_filter('wp_title', wp_myplugin_property_title, 100);
}
the function used within that function: wp_myplugin_seo_title($propid) generates the actual title i want to use...
function wp_myplugin_seo_title($propid)
{
$wp_acquaint_id = get_option("wp_acquaint_id");
$xml = wp_myplugin_get_property($propid);
foreach($xml->PropertiesDataSet->Properties as $node) {
include('xml_loop.php');
if($bedrooms==0){ }else{ $seo_title.= $bedrooms." bedroom "; }
$seo_title.= wp_myplugin_get_property_type($type_id)." "; //ie:flat
$seo_title.= str_replace("(","",$street);
$seo_title.= " ".$town." | ".get_bloginfo('name');
}
return $seo_title;
}
Im finding that with the if(is_page()) in place around the filter the page title dosnt change and if i remove the is_page, the prop details page title works fine but!!!
while on the property listing page the page title is looping through all the properties on that page and producing a page title around 1000 char long..!
I have been hunting around for a better way to deal with this but any help would be great..
Cheers
Marty
ps: currently running wordpress seo by Yoast!
thats why ive set the priority as 100 in the add_filter just to see if it would overwrite the title..
Using is_page in functions.php doesn't work, as it runs before wp knows what page it's going to render, or even if it's a page to begin with. Stick the is_page() inside the function, and it should work. Like:
function wp_myplugin_property_title()
{
if( is_page('details') ){
$wp_acquaint_id = get_option("wp_system_id");
$propid = get_query_var('propid');
if(isset($propid)){
$seotitle = wp_myplugin_seo_title($propid);
}else{
$seotitle = "TEST Title";
}
return $seotitle;
}
}
add_filter('wp_title', wp_myplugin_property_title, 100);

Categories