Making use of var_dump on WordPress functions - php

I trying to get deep into WordPress development, I was wondering when we do var_dump($post->post_id), it gives a list of objects that, that function has. The reason I said objects, is I don't know what they are. While it gives you a comprehensive list of properties that you can access as the WordPress codex page state. My question is how can I access other function and its properties like:
`get_the_category();`, I might be naive to get a list of properties like
$category = get_the_category();
foreach ($category as $cat) {
echo $cat;
}
How can I access properties of a WordPress function, a example would be something like $category->ID() or other properties, other example might include
<?php
if ( have_posts() ) {
while ( have_posts() ) {
the_post();
?>
<?php
$test = get_cat_ID($post->ID);
var_dump($test)
?>
<?php }
}
?>
But in that example, I get a int(0), so how can I get different properties on a post, like its category, slug, taxonomies etc.

I think what you're trying to do is to get information about the API programmatically. The problem is that PHP is not well suited to do something like that, because there are not static types. In any case, Wordpress makes use of on-the-fly generated objects and associative arrays. If the template function would actually return objects of a certain type, you could definitely look up the properties of this type and have your answer.
However, as this is not the case, all you really can do is to call the function in question once and then take a look at the result. In your case for example:
$category = get_the_category();
var_dump($category);
Of course, you could also take a look at the code to figure out how the result value will look like. This is quite cumbersome though, because there are usually a myriad of other functions being called to assemble the result.
Note: This will not work with all functions. There are some that actually output the result rather than returning it. You don't really need to investigate these, however, because their result is only a single string. (You can recognize these functions usually by their prefix the_, but not get_the_ as in your example.)
If I totally missed your point, let me know and I'll try again. ;-)

Related

What is the -> (forward arrow) operator in Wordpress/PHP?

I have downloaded a WordPress theme and in many places in the code I see the operator ->. It could be for example to retrieve a post ID like this:
$postID = $post->ID
I can't find what the arrow actually does in the background. Does it make a database call? Or is it simply fetching the ID from the $post variable, similar to $postID = $post['ID']?
The arrow operator -> is for accessing properties or method of an object.
Overhead of accessing properties is neglectible, but it's sometimes more comfortable to assign a property to a temporary variable, just because it shortens the source code. Example
$oPropValue = $objWithSpeakingName->propertyWithLongName;
However, it's often a good practice to save the return value of an method call to a temporary variable to avoid to much overhead. For example if the method performs a database query (and has no build-in caching), it would cause massive overhead to call the method over and over instead of calling it once an then reuse the value, f.e. in a loop.
$propValue = $objWithSpeakingName->doSomeWork();
while( ..condition.. ) {
// work with $propValue
}
But it also depends on how a method is used and what it's doing. If it takes arguments, you might need to call it repeatedly with changing parameters, in order to get the job done.
while(..condition..) {
$arg = .. // might change in the loop
$propValue = $objWithSpeakingName->doMoreWork( $arg );
}
in PHP -> simply means it is accessing object properties, like how '.' works in other Object Oriented Languages like java.

OOP: Get method from same class to another method through anonymous function

I'm new to Object-Oriented PHP so I'm not entirely sure what my question really is, but here's the jam:
I created a WordPress plugin that adds a bunch of metaboxes on a certain custom post type created by another plugin. In my theme I need to get all the custom meta, but it's quite a lot that needs to be gotten, and usually with certain conditionals and so forth. So, I created a bunch of helper functions to simplify it. Problem is the names of all these functions are kind of a pain, so I put them inside a class in my plugin to simplify things, and my issue is that I'm having trouble combining them. Whether that's possible or not, hopefully you can help with...
So most of the helper functions (now class methods) look something like this:
public function metabox_wrapper( $code ) {
$info = get_post_meta( ID, 'blah', true);
if ( $info ) {
code( $info );
}
}
Then in my theme file I use:
global $Other_Plugins_Global // Created by the other plugin.
$class = new Class( $Other_Plugins_Global );
$class->metabox_wrapper( function( $info ) {
?>
<div>
<?php echo $info; ?>
</div>
<?php
});
The above is currently working - it displays the blah meta from the current post if the blah metadata exists. The other plugin's global variable contains the custom post type info (and therefore the meta), so I pass that through the class instance, use a method in the class to manage all the conditionals and other complicated stuff, and then use the method in the theme file, so that the conditional stuff is pre-arranged and able to be used in the same way elsewhere in the theme.
However, here's the rub: There are situations where I want something like
if (
Do this
if (
Also do this
)
)
But this (and everything like it that I've tried) does not work:
global $Other_Plugins_Global
$class = new Class( $Other_Plugins_Global );
$class->metabox_wrapper( function( $info ) {
?>
<div>
<?php echo $info; ?>
</div>
<?php
$class->other_metabox_wrapper( function( $stuff ) {
?>
<div>
<?php echo $stuff; ?>
</div>
<?php
});
});
So my question is... is there a way I can use these wrapper functions inside of each other? I've tried setting them as static and using :: in the theme, I've tried some fancy variable gymnastics that didn't work and would've been ugly af if it had, I almost raised a demon trying to call the global variable from inside the method... so at this point I'm not even sure what to Google.
Obviously for this particular example I could just use if(){}, but the conditional logic often has multiple conditions and other semi-complicated stuff, so it'd be helpful to keep that separate and able to be used in multiple places around the theme.
I will say that if this is a dumb question and you know of a completely different and more elegant way to accomplish what I'm describing, then I'm all ears.
Many thanks for the help.
The problem lies not in the realm of OOP, but rather in the realm of functions and function scopes. You see, when you create an anonymous function it has its own scope -- the scope of variables that are accessible. In most languages, anonymous function encloses the scope it was created in, creating a closure -- meaning it can access the copies of all variables from the parent scope. In PHP it is not the case, so in order to access $class variable from within the anonymous function you should use use: $class->metabox_wrapper(function($info) use ($class) {.
Another approach would be to bind the context to anonymous function with Closure::bind():
public function metabox_wrapper($code) {
$info = get_post_meta(ID, 'blah', true);
if ($info) {
$code = Closure::bind($code, $this);
$code($info);
}
}
Then you can use $this inside the anonymous function:
$class->metabox_wrapper(function($info) {
?>
<div>
<?php echo $info; ?>
</div>
<?php
$this->other_metabox_wrapper(function($stuff) {
?>
<div>
<?php echo $stuff; ?>
</div>
<?php
});
});
But to tell you the truth I agree with #CrisanLucian. Mixing the code with HTML in such a manner is not the best way to program.
First of all you have to read some Coding Standards articles
1. https://www.tutorialspoint.com/php/php_coding_standard.htm
Try to make separation between PHP code and HTML; Using Twig instead PHP make life much easy
https://aristath.github.io/blog/using-twig-in-wordpress
When you have a more help (hooks) functions better to group them into a class, or create a Helper dir structure and create a file for each scope. (e.g: Trim strings , Resize Images create different files)
After creating Helpers try to not put HTML inside; A helper suppose to return a value ( boolean ).
e.g showCampaign() => will return True;
HTML page/ TWIG page
{{ if(showCampaign()) }}
//HTML CODE IS HERE
{{ endif }}
When you have too many if/else statements is need refactor check the link above or another example: https://carlalexander.ca/mastering-php-conditionals/
happy codding!

Templating with anonymous functions and usage of output buffer in PHP

I figure I'd better ask than make a fool of myself some time when I get my code reviewed.
I am making a website, trying to follow MVC design architecture, although it might not even be MVC but I figured it works nice.
Currently, I am doing something like this;
I have a render() function that takes a string $template and array of arguments,
render($template, $vars=[]){
extract($vars);
ob_start();
include($template.'.php');
ob_flush();
}
and outputs the view. In a controller, I then do this,
Class WhicheverController
public static function defaultAction(){
$article=Article::getOneByID(array('id'=>$_GET['id'], 'user'=>User::currentUser())); //returns database result as object
render('_header', array('title'=>$article->title));
render('header', array('user'=>User::currentUser()));
render('sidebar', array('user'=>User::currentUser()));
$content=Comment::getByArticleID(array('article'=>$article->id)); //returns object
//of root comments, highest level in comment-replies tree
$comments=function() use ($content){
foreach($content as $comment){
$threads[]=function() use ($comment){
render('comment', array('comment'=>$comment));
}
}
render('pagination', array('content'=>$threads)); //pagination paginates based on number of
//items in content, and echoes it or runs it if it is_callable
}
render('article', array('article'=>$article, 'comments'=>$comments));
}
And finally in article.php;
//some html with echoing $article->variablethis or variablethat
<div class="comments">
<?= $comments(); ?>
</div>
Now, the way I figured it out, ob_flush() sends to client prematurely, so I get headers with styles and header and sidebar printed as I am getting the neccessary variables. That is good (if that's how it works).
Then, I want to do the same with the main content - article and comments. First I get the comments and article data, and pass it to article.php. But I have to do some pagination logic first before sending it away, and that would delay rendering of article.php. So I create an anonymous function which does that, and pass that as a variable function $comments(); which does it's logic when it is called.
This is only one example. In one controller I first get top rated articles of today, yesterday and current week, and create anonymous function for each one, before passing it to frontpage.php. Frontpage.php does this, essentialy;
//some html markup
<?= $articles24h(); ?>
//more html
<?= $articles48h(); ?>
//and so on
Now, when I thought of this I thought it was brilliant but as I started to add more variable functions I noticed my code was starting to become longer and I presume anyone other than me illegible.
My question is: is this bad practice; this usage of anonymous functions, variable functions and ob_flush() (more importanntly, does it do what I think it does)?
EDIT: The code itself works. In here I might've made some logical mistakes, but the point is to display the usage of functions.
EDIT 2: Okay, so I realized I can have one anonymous function display $articles24h and $articles48h any paginating content just by passing each as $content, like so function($content) use ($something_else, $but_common){ //yada yada }, which helps a lot, but I still don't know if this is desirable. i.e. there is a better way.
EDIT 3: I created 3 View classes, one View class with static render() method that just takes a template name and array with variables and prints out a template, and two others, PaginationView and PartialView; both have their own render() method and don't extend View class (even thought if I was a better programmer yadda yadda I' do it differently). Pagination paginates partial views that PartialView stores in a class variable and creats when constructed. If I don't need to paginate data, I just call PartialView->render()
Neat (IMO), but it looks kinda ugly in code, like so:
$content=Article::getByAuthorID(array('author'=>$profile->id), array('order'=>$order,'column'=>'time_submitted'));
$user_articles=new PartialView('_article', $content, array('length'=>60));
$user_articles=new PaginationView($user_articles->views, 10, 1);
$user_articles is then sent to
echo View::render('user_page', array('articles'=>$user_articles, 'profile'=>$profile, 'comments'=>$user_comments));
As you can see, I also do this for comments so the code gets lengthy. I don't want to change anything it I am not breaking anything, although I feel like this is a violation of DRY in some way (?)
Is there a better way to do this, without sacrificing clarity but making it more compact?

What would be the best way to showing nested comment(s)?

To implement this feature I had created a a column replyTo which relates to the comment_id in the same table. The original comments have this as 0. The problem I face is what could be the best way to show them.
In my model, I have created a function nested_comments() to get them and in my view I was doing like, this.
<? foreach( $comments as $comment ): ?>
....
<? foreach( $comment->nested_comments() as $comm): ?>
But that is only fine if I have one level of nested comments. Actually, I wish if there was a way to do this in the view. I don't wish to create another view file and controller for this purpose alone.
You can use function, Like below:
function getComments($comments){
if(!is_array($comments)){
return;
}
foreach($comments as $key => $value){
// do what you want with comments
getComments($nestedComments);
}
}
it's not ready to use function, but you can work in the same way.
You can achieve it with mptt modules, there are a few around:
https://github.com/spadefoot/kohana-orm-leap
https://github.com/rafi/orm-mptt
https://github.com/evopix/orm-mptt
I've been using third one but now its old and I suggest you to take a look at leap, it looks very promising.
And also take a look at http://kohana-modules.com/search?query=mptt

Drupal - How can I make an array globally accessible?

I'm using this code in a views field template (in this case views-view-field--all-members--uid.tpl.php):
<?php
$users_friends = flag_friend_get_friends($user->uid);
$users_friends_ids = array();
foreach ($users_friends as $id => $value) {
$users_friends_ids[] = $id;
}
?>
It basically gets the user ids of friends and puts them in an array so I can check if the field matches any of the user ids.
So my problem is that I don't want to have this within this template (for a few reasons), but if I don't I can't access the array. How can I make this array globally accessible?
Without knowing your "few reasons", I can't say if this is the answer for sure. My own reasons would probably be that I don't want the same code executing a bunch of times, and I'd rather not have the same exact code in multiple places.
I would then create a function with a static variable to hold the friends array.
function mymodule_get_friends_ids() {
// pull in the current global user variable
global $user;
// call up the static variable
static $users_friends_ids;
// return if this static var has already been set
if (is_array($users_friends_ids)) {
return $users_friends_ids;
}
// if we hit here, then this function has not been
// run yet for this page load.
// init array
$users_friends_ids = array();
// if user is anon, no need to go on
if (user_is_anonymous()) {
return $users_friends_ids;
}
// get friends array
$users_friends = flag_friend_get_friends($user->uid);
// build ids array
foreach ($users_friends as $id => $value) {
$users_friends_ids[] = $id;
}
return $users_friends_ids;
}
Now in your templates, you can call mymodule_get_friends_ids() in as many places as you want, and the working code below the first return will only get executed the first time it is called.
Coder1's advice is very good - it keeps you from populating your global variable namespace with a lot of junk. It's probably the most "elegant." It might not be the easiest to use if you are rather new to PHP (which I'm guessing might be the case if it's hard to get your head around returning arrays, but that's ok).
However, if this is really a priority, you probably don't care about having one extra global variable.
I suppose I may be stating the obvious here - but you can, at pretty much any point in execution (provided the information you need has already been generated - e.g., the $user variable has been populated), do this:
$GLOBALS['users_friends_ids'] = /* your code goes here */
Then in your template, you access this by ...
$friendsArray = $GLOBALS['users_friends_ids'];
Or you can simply use the construct
global $user_friends_ids;
when you want to initialize the variable, or access it inside a function or class (which is the case for your template files - they are called inside functions, so you need to globalize or use the $GLOBALS array, which is "automagically" all of the variables active in the global namespace).
The most "logical" place to do this would be inside a module using one of the many hooks available, to execute this code only once. hook_init() might do it for you, if the user object is already loaded at this point (not sure, you'll have to test). But you might not want to figure out making Drupal modules (it's not that difficult).
If you are doing this inside a template (and though it's not good practice, many Drupal site owners with a beginning knowledge of PHP put everything in templates), you'll want to know which template code is being executed when. Node template code tends to be executed before page template code - which is logical, since otherwise the variables for node content in the page template wouldn't be populated.
If you have listings of nodes, they'll be calling this code multiple times, so you'll end up doing something similar to what Coder1 is describing. If you don't want to create your own small module, you could put the function declaration he's written in your theme's template.php file, since it's called only once. You don't want to put function declarations in the tpl.php files, since they are sometimes called more than once (and you aren't allowed to declare functions more than once).
If you have a hard time understanding the function and the return, you can always do something like this in your code (which is very, very inelegant - but it's better to have inelegant code that you do understand, than elegant code that's you don't).
if(!isset($GLOBALS['users_friends_ids'])) {
$GLOBALS['users_friends_ids'] = /* your code here */
}

Categories