Get the Official WPSaviour App Now!

BlogTutorials

Manage WordPress Posts with PHP – Create and Update

As promised, proper right here is the second half to my first submit, ‘Create WordPress Posts And Pages Using PHP – A 101 Tutorial’. Deal with WordPress Posts with PHP,On this text we will be having a look at how we are going to lengthen the important capabilities and idea I discussed in Half 1 to create a sturdy and at last reliable PHP Wrapper Class.

As always, I do sympathize with these of you who merely must dive straight into the code. You possibly can discover it in one amongst my Github repos (it was barely too prolonged to stay immediately into this textual content itself!).

ForkMeHBT2

What we have to acquire:

  • A very purposeful and reliable PHP production-grade framework.
  • Have the power to deal with not solely submit creation, however moreover to deal with and substitute pre-existing posts.
  • Have the power to hunt for and manipulate posts by their; ID; Title or Slug.

There shall be 2 sections to this textual content: Utilization Notes and a Step-by-Step Info.

With none extra ado, let’s begin!

USAGE

Initially, you should definitely have each included the class.postcontroller.php file from Github or have pasted the contents of that file into your PHP doc. This gained’t work with out it! We’ll have a look on the code on this file inside the second half of this tutorial.

Instantiate the class as follows;

$Poster = new PostController;

Submit Controller works like this; you set submit attributes using the associated capabilities. Then you definitely definately each create or substitute a submit. To interchange a submit, it’s advisable have first searched and situated one to switch. Sound straightforward enough?

SET ATTRIBUTES

Title
This models the submit’s title. No HTML is allowed proper right here, and is stripped out.

$Poster->set_title( 'The Title' );

Kind
This method models the submit type of the net web page. Enter the slug of the submit sort, eg. ‘submit’ and ‘internet web page’. Personalized submit types are supported.

$Poster->set_type( 'internet web page' );

Content material materials
This method models the submit’s content material materials. HTML is allowed.

$Poster->set_content( '<h1>That's my superior new submit!</h1>' );

Creator
This models the submit’s author. Merely specify the author ID of the model new author. This ought to be an integer.

$Poster->set_author_id( 12 );

Slug / ‘Title’
That’s the personalized url path of the submit (if enabled). Take care with this, as if the slug is already in use, it’d set off some errors. I’ve included validation to attempt to steer clear of this the least bit costs though. No specific characters or html allowed.

$Poster->set_post_slug( "new_slug" );

Template (Pages Solely)
This method allows you to set your internet web page’s template (ought to be an online web page). If utilized to a novel submit sort it will be ignored, and an error shall be added to the errors array. The format of the enter shall be ‘php_template_name.php’ and shall be distinctive to each theme.

$Poster->set_page_template( 'fullwidth_page.php' );

State
This method models the submit’s state. Obtainable selections;
[ ‘draft’ | ‘publish’ | ‘pending’| ‘future’ | ‘private’ | custom registered status ]

$Poster->set_post_state( "pending" );

CREATE

The minimal requisite for making a submit is having the title set. You’ll be able to do that by using the following code;

$Poster->set_title( "New Submit" );

After this has been set, merely run the create approach.

$Poster->create();

Discover: The tactic will look at if there’s one different submit with the equivalent establish (merely to be sure that it isn’t making duplicates). Subsequently a distinctive title is required.

SEARCH

Sooner than we are going to substitute an current submit, we first have to go looking out it with the Search function.

To try this, we use the search approach.

$Poster->search( 'SEARCH_BY' , 'DATA' );

This method accepts 2 parameters, the attribute to look by and the information to hunt for.

You’ll search by title;

$Poster->search( 'title' , 'DATA' );

You’ll search by ID;

$Poster->search( 'id' , 'DATA' );

And you will search by slug;

$Poster->search( 'slug' , 'DATA' );

The information parameter will accept each a string (if trying by title or slug) or an integer (if trying by ID). If a submit or internet web page cannot be found with the specified parameters, an error shall be added to the $errors array. You’ll identify and present this with the following code.

$error = $Poster->get_var( 'errors' );
$Poster->PrettyPrint( $error );

UPDATE

As quickly as a submit has been found, you probably can assign it new attributes. After the attributes have been set, merely identify the substitute approach.

$Poster->substitute();

As an example, within the occasion you wish to change the title of submit 1 (ID = 1), you may use the following code.

$Poster->search( 'id', 1 );
$Poster->set_title( 'New Title' );
$Poster->substitute();

All the attributes might be updated this way.

RETRIEVING VARIABLES

To retrieve outlined variables you need to make the most of the get_vars approach.

$Poster->get_var( 'title' );    // Returns the title (you in all probability have set it)
$Poster->get_var( 'sort' );     // Returns the submit sort (you in all probability have set it)
$Poster->get_var( 'content material materials' );  // Returns the content material materials (you in all probability have set it)
$Poster->get_var( 'class' ); // Returns the category as an array (if set)
$Poster->get_var( 'template' ); // Returns the template (you in all probability have set it)
$Poster->get_var( 'slug' );     // Returns the slug (you in all probability have set it)
$Poster->get_var( 'auth_id' );  // Returns the author id (you in all probability have set it)
$Poster->get_var( 'standing' );   // Returns the submit's standing (you in all probability have set it)
$Poster->get_var( 'errors' );   // Returns the errors array

/** AFTER YOU HAVE EITHER CREATED A POST OR SUCCESSFULLY SEARCHED FOR ONE YOU CAN USE THESE **/

	// Returns the a PHP Object of the submit. This may be utilized to look at if the search approach was worthwhile
	$Poster->get_var( 'current_post' );

	// Returns the chosen submit's ID (integer).
	$Poster->get_var( 'current_post_id' );

	// Returns the URL permalink of the chosen submit
	$Poster->get_var( 'current_post_permalink' );
That is that! You in all probability have any questions on utilization you probably can ask me inside the suggestions proper right here. In case you uncover a bug please inform me about it on Github.Ready for the second half?

BUILDING THE CLASS: STEP BY STEP GUIDE

Now now we’ve got seen learn how to make use of the class, let’s return to the beginning.
Our class shall be often called PostController;

class PostController {

. . . class capabilities go proper right here . . .

}

For these of you who aren’t properly versed with PHP Programs, a Class is printed as an object which includes a set of capabilities and variables which can be working collectively. Strive the PHP.internet Introduction for additional particulars in regards to the syntax and idea we will be using to create our framework. Subsequent on our to-do document is to declare all the variables we will be using.

// Variables for Submit Information
public $PC_title;
public $PC_type;
public $PC_content;
public $PC_category;
public $PC_template;
public $PC_slug;
public $PC_auth_id;
public $PC_status = "publish";

// Variables for Submit Updating
public $PC_current_post;
public $PC_current_post_id;
public $PC_current_post_permalink;

// Error Array
public $PC_errors;

Let’s break this down into three blocks.

The first block will keep the Submit Information which YOU have specified. This could be the data which shall be used to switch and create a submit (as soon as we come to it). Although you probably can probably guess by the variables names, this is a document of the information we want to have the power to retailer.

  1. Title
  2. Kind (Net web page/Submit and so forth.)
  3. Content material materials
  4. Class/Courses
  5. Net web page Template
  6. Slug
  7. Creator ID, and
  8. The Submit’s Standing (eg. printed/draft)

The second block will keep the exact WordPress submit data which our search query will return (or the information a few created submit after it has been created). The ‘$PC_current_post’ variable will keep an object of your complete submit. This holds your complete data in regards to the submit, along with (importantly) the information listed above. Equally, the Submit ID and Permalink variables will keep these things of information in regards to the current submit.

The third and shutting block solely has a single variable: the errors array. If a difficulty is encountered at a recognized ‘pinch’ stage, then a message in regards to the subject shall be added to this array to your reference. Please observe that I’ve included the ‘PC_’ merely out of superb habits: variable names must on no account be ambiguous. PC stands for ‘PostController’. In case you modify this be mindful to moreover change the prefix inside the get_var() function.

Correct, now that now we’ve got the whole thing organize, let’s dive into our first function.

// Creation capabilities
public function create() {

	if ( isset( $this->PC_title ) ) {

		if ( $this->PC_type == 'internet web page' ) {
			$submit = get_page_by_title( $this->PC_title, 'OBJECT', $this->PC_type );
		} else {
			$submit = get_page_by_title( $this->PC_title, 'OBJECT', $this->PC_type );
		}

		$post_data = array(
			'post_title'    => wp_strip_all_tags($this->PC_title),
			'post_name'     => $this->PC_slug,
			'post_content'  => $this->PC_content,
			'post_status'   => $this->PC_status,
			'post_type'     => $this->PC_type,
			'post_author'   => $this->PC_auth_id,
			'post_category' => $this->PC_category,
			'page_template' => $this->PC_template
		);

		if ( ! isset( $submit ) ) {
			$this->PC_current_post_id        = wp_insert_post( $post_data, $error_obj );
			$this->PC_current_post           = get_post( ( integer ) $this->PC_current_post_id, 'OBJECT' );
			$this->PC_current_post_permalink = get_permalink( ( integer ) $this->PC_current_post_id );
			return $error_obj;
		} else {
			$this->substitute();
			$this->errors[] = 'That internet web page already exists. Attempt updating instead. Administration handed to the substitute() function.';
			return FALSE;
		}

	} else {
		$this->errors[] = 'Title has not been set.';
		return FALSE;
	}
}

 

For these of you who’ve be taught Half 1 of this Sequence: Create WordPress Posts And Pages Using PHP – A 101 Tutorial, this function will look acquainted to you. That’s merely the finished function from that tutorial after being tailor-made to this new organize. To be taught the rationale of this particular function I’d recommend attempting out half 1. The one major distinction to the function itself is that instead of the together with the function to the WordPress head, it is run immediately.

As a quick run-through, the function checks {{that a}} title has been set (that’s the minimal requirement for submit creation). It then checks for an current submit (by title). If a submit is found, a message is added to the errors array and administration is handed to the substitute() function. If a submit isn’t found with this title, then the $post_data is used to create a model new submit. The Current Submit variable ( along with the other 2 data variables ) are updated to hold this new submit’s data. That’s good for checking the submit you’ll have merely made. If there are points, then a message is added to the $errors array.

Sorry if that was a bit fast: in case you’re a bit confused, I do recommend you attempt my 101 article on this.

For all of you proceed to with me, let’s proceed on.

// SET POST'S TITLE
public function set_title( $establish ) {
	$this->PC_title = $establish;
	return $this->PC_title;
}

// SET POST'S TYPE
public function set_type( $sort ) {
	$this->PC_type = $sort;
	return $this->PC_type;
}

// SET POST'S CONTENT
public function set_content( $content material materials ) {
	$this->PC_content = $content material materials;
	return $this->PC_content;
}

// SET POST'S AUTHOR ID
public function set_author_id( $auth_id ) {
	$this->PC_auth_id = $auth_id;
	return $this->PC_auth_id;
}

// SET POST'S STATE
public function set_post_state( $content material materials ) {
	$this->PC_status = $content material materials;
	return $this->PC_status;
} 

This bit is pretty straightforward. The create() and substitute() capabilities every use native variables as a result of the availability of their data. Subsequently we would like a method to set this data. The first 5 variables are set as you probably can see above. ‘What in regards to the totally different Three though?’, I hear you ask. Don’t fret, proper right here they’re, nevertheless you’ll discover that there is a little little bit of validation to substantiate their inputs (to maximise reliability).

// SET POST SLUG
public function set_post_slug( $slug ) {

	$args = array('establish' => $slug);
	$posts_query = get_posts( $args );

	if ( ! get_posts( $args ) && ! get_page_by_path( $this->PC_slug ) ) {

		$this->PC_slug = $slug;
		return $this->PC_slug;

	} else {
		$this->errors[] = 'Slug already in use.';
		return FALSE;
	}

}

// SET PAGE TEMPLATE
public function set_page_template( $content material materials ) {

	if ( $this->PC_type == 'internet web page' ) {
		$this->PC_template = $content material materials;
		return $this->PC_template;
	} else {
		$this->errors[] = 'You'll solely use template for pages.';
		return FALSE;
	}

}

// ADD CATEGORY IDs TO THE CATEGORIES ARRAY
public function add_category( $IDs ){

	if ( is_array( $IDs ) ) {
		foreach ( $IDs as $id ) {
			if ( is_int( $id ) ) {
				$this->PC_category[] = $id;
			} else {
				$this->errors[] = '<b>' .$id . '</b> should not be a sound integer enter.';
				return FALSE;
			}
		}
	} else {
		$this->errors[] = 'Enter specified by not a sound array.';
		return FALSE;

	}

}

These remaining three are a bit additional subtle, nevertheless essential to steer clear of horrible errors.

set_post_slug()

The set_post_slug() function is one factor it’s advisable be very cautious with. The submit slug is definitely the string added onto the highest of the underside URL to create the submit’s specific particular person sort out. That’s moreover used as a elementary submit identifier by WordPress. Eg. This submit’s slug is ‘manage-wordpress-posts-php-create-update’. That’s added on to the highest of the underside URL, http://wpsaviour.com/, to create this textual content’s distinctive URL: http://www.wpsaviour.com/manage-wordpress-posts-php-create-update/. I’m sure you probably can take into consideration the problems you’d run into if a few submit had the equivalent slug (and subsequently, URL). It is a really nasty mess biggest averted if the least bit potential.

The Submit Slug MUST be UNIQUE

That’s the rationale for the validation. What is going on is that the function searches for posts with the specified slug. If none are found AND there are usually not any pages with that as a path (primarily the equivalent as a result of the slug on this context), then good! Set the variable. If not, an error is added to the $errors array and the variable should not be set (the function returns a Boolean FALSE).

set_page_template() & add_category()

set_page_template() assigns an online web page template (inside the kind my_page_template.php) to a Net web page, and solely an online web page. The validation proper right here merely checks if the submit sort has been set to ‘internet web page’. If true, retailer the information. If not, don’t trouble.

add_category() allows you to add an array of integers to the submit’s courses (ought to nonetheless be in an array, even when solely together with 1 amount). The integers symbolize the category IDs. The validation merely loops by means of the array you specify, checking that each cell has an integer value. If the cell has an integer value, it is added to the grasp courses array. If not, then it is ignored and an error is added to the errors array. Good! Now we are going to assign all the variables we would like.

SEARCHING

Initially of this tutorial, we acknowledged that we wished to make a system which has the pliability to switch current WordPress posts. For this to be potential, we first wish to get hold of the submit we have to edit. For this we’ll use the search() function.

// Search for Submit function
public function search( $by, $data ) {

	swap ( $by ) {

	// SEARCH FOR POST USING IT'S ID
	case 'id' :
	
		if ( is_integer( $data ) && get_post( ( integer ) $data ) !== NULL ) {
			$this->PC_current_post           = get_post( ( integer ) $data, 'OBJECT' );
			$this->PC_current_post_id        = ( integer ) $data;
			$this->PC_current_post_permalink = get_permalink( (integer) $data );
			return TRUE;
		} else {
			$this->errors[] = 'No submit found with that ID.';
			return FALSE;
		}

	break;

	case 'title' :

		$submit = get_page_by_title( $data );

		if ( ! $submit ) {
			$submit = get_page_by_title( $data, OBJECT, 'submit' );
		}

		$id = $submit->ID;

		if ( is_integer($id) && get_post( (integer)$id) !== NULL ) {
			$this->PC_current_post           = get_post( (integer)$id, 'OBJECT' );
			$this->PC_current_post_id        = (integer) $id;
			$this->PC_current_post_permalink = get_permalink( (integer) $id );
			return TRUE;
		} else {
			$this->errors[] = 'No submit found with that title.';
			return FALSE;
		}

		break;

		// SEARCH FOR POST USING IT'S SLUG
		case 'slug' :
		$args = array(
			'establish'          => $data,
			'max_num_posts' => 1
		);
		$posts_query = get_posts( $args );
		if ( $posts_query ) {
			$id = $posts_query[0]->ID;
		} else {
			$this->errors[] = 'No submit found with that slug.';
		}

		if ( is_integer($id) && get_post( (integer)$id) !== NULL ) {
			$this->PC_current_post           = get_post( (integer)$id, 'OBJECT' );
			$this->PC_current_post_id        = (integer)$id;
			$this->PC_current_post_permalink = get_permalink((integer)$id);
			return TRUE;
		} else {
			$this->errors[] = 'No submit found with that slug.';
			return FALSE;
		}

		break;

		default:

		$this->errors[] = 'No submit found.';
		return FALSE;

		break;

	}
}

That’s the search() function. I am using the PHP Swap assertion (a novel kind of IF statements, which on this case shall be additional setting pleasant than quite a lot of nested Ifs. Uncover out additional about Swap on the PHP.internet Information The search() function accepts 2 parameters;

1. The ‘Search By’ Value
2. The Information to Search For

You’ll see from the code above that there are 3 ‘Search By’ selections; ‘id’, ‘title’ and ‘slug’. Let’s take a look at each slightly bit additional fastidiously.

SEARCH BY ID

That’s the finest search approach and merely requires you to know the submit’s integer ID. If the information specified is an integer, then the function will ship a query to your WordPress database (using the inbuilt get_post() function). If a submit with that integer exists,the submit object is returned and saved inside the PC_current_post variable (along with the ID and permalink being saved as properly). Simple!

SEARCH BY TITLE

I don’t assume this really desires so much rationalization: it’s simply in regards to the equivalent as trying by ID, nevertheless searches for the submit by its title instead. You in all probability have posts/pages which have the equivalent establish (one factor I do not recommend) then the submit with the smallest ID shall be chosen. If you happen to understand that you simply simply do have posts which have the equivalent names, don’t use this system to steer clear of confusion. Please Discover: You’ll word this code;

$submit = get_page_by_title( $data );

if ( ! $submit ) {
	$submit = get_page_by_title( $data, OBJECT, 'submit' );
}

The reason why now we’ve got to do it is as a result of although get_page_by_title() can return data for every posts and pages, it will solely return pages till the third parameter is specified as ‘submit’.

I don’t suggest to state the plain, nevertheless do perceive that in case you’re looking by title and altering the title on the equivalent time, the code will solely be succesful to run as quickly as (the first time). After that it will return a 404 Not Found error.

SEARCH BY SLUG

It’s a good and reliable strategy of discovering posts. There must be no ambiguity on account of, as I’ve acknowledged beforehand, the slug ought to be distinctive. Strive the SET_POST_SLUG() half within the occasion you aren’t clear what I suggest by ‘slug’. To try this, we merely needed to run a WordPress posts query to go looking out posts with the actual slug. We’ll retrieve the ID from this system and set the current submit variables within the equivalent method as the other 2 methods. Within the equivalent method as Searching by Title, on the lookout for and altering slug collectively will set off points. Beware!

UPDATE AND MANAGE

Correct! Now that trying is out of one of the simplest ways, we are going to switch on to the exact substitute() function.

// Substitute Submit
public function substitute(){
	if ( isset($this->PC_current_post_id ) ) {

		// Declare ID of Undergo be updated
		$PC_post['ID'] = $this->PC_current_post_id;

		// Declare Content material materials/Parameters of Undergo be updated
		if ( isset($this->PC_title ) && $this->PC_title !== $this->PC_current_post->post_title ) {
			$PC_post['post_title'] = $this->PC_title;
		}

		if ( isset( $this->PC_type ) && $this->PC_type !== $this->PC_current_post->post_type ) {
			$PC_post['post_type'] = $this->PC_type;
		}

		if ( isset($this->PC_auth_id) && $this->PC_auth_id !== $this->PC_current_post->post_type ) {
			$PC_post['post_author'] = $this->PC_auth_id;
		}

		if ( isset($this->PC_status) && $this->PC_status !== $this->PC_current_post->post_status ) {
			$PC_post['post_status'] = $this->PC_status;
		}

		if ( isset($this->PC_category) && $this->PC_category !== $this->PC_current_post->post_category ) {
			$PC_post['post_category'] = $this->PC_category;
		}

		if ( isset($this->PC_template )
			&& $this->PC_template !== $this->PC_current_post->page_template
			&& ( $PC_post['post_type'] == 'internet web page' || $this->PC_current_post->post_type == 'internet web page' )
		) {
			PC_post['page_template'] = $this->PC_template;
		}

		if ( isset( $this->PC_slug ) && $this->PC_slug !== $this->PC_current_post->post_name ) {
			$args = array('establish' => $this->PC_slug);
		}

		if ( ! get_posts( $args ) && !get_page_by_path( $this->PC_slug ) ) {
			$PC_post['post_name'] = $this->PC_slug;
		} else {
			$errors[] = 'Slug Outlined is Not Distinctive';
		}

		if ( isset($this->PC_content) && $this->PC_content !== $this->PC_status->post_content ) {
			$PC_post['post_content'] = $this->PC_content;
		}

		wp_update_post( $PC_post );

	}

	return( $errors );
}

I’m not going to lie, this bit is mainly pretty easy. Principally, the substitute function checks to see if any of the eight submit parameters have been set. In that case, it creates and populates an array which is suitable with the wp_update_post(). It runs wp_update_post() and hey presto! Job properly completed. For effectivity we’ll add a straightforward look at sooner than assigning each variable. It’s simply updated if it modified. Although I am a bit biased, I’ve to admit that that is gorgeous code!

The set values are in distinction in the direction of the values returned from WordPress itself. Solely a straightforward comparability is required then. You will uncover that the template and slug IF statements have slightly bit bit additional validation than the others. Although now we’ve got already included validation to filter out errors for these, there is not a harm in double checking! The online web page template look at (it checks to see if the submit sort is about to internet web page) is simply because trying to set an online web page template for a non-post is a bugbear of mine. Sorry in regards to the overkill! The slug look at nevertheless is a vital one! You REALLY don’t must have slug conflicts. On this case, there is not a such issue as overkill. That is nearly it for substitute(). Lastly, now we’ve got some useful frequent capabilities.

ADDITIONAL FUNCTIONS

it’s always a very good suggestion in order so as to add in a number of useful/time saving capabilities,Now that almost all of the class is written,. Have a look;

// Frequent capabilities
public function get_content() {

	if ( isset( $this->PC_current_post->post_content ) ) {
		return $this->PC_current_post->post_content;
	}

}

public function get_var( $establish ) {
	$establish = 'PC_'.$establish;
	if ( isset( $this->$establish ) ) {
		return $this->$establish;
	}
}

public function unset_all() {
	foreach ( get_class_vars(get_class($this)) as $establish => $default ) {
		$this->$establish = $default;
	}
}

public function __toString() {
	return 'Use the PrettyPrint function to return the contents of this Object. E.g;<pre>$my_post->PrettyPrintAll();</pre>';
}

public function PrettyPrint($data) {
	echo "<pre>";
	print_r( $data );
	echo "</pre>";
}

public function PrettyPrintAll() {
	echo "<pre>";
	print_r( $this );
	echo "</pre>";

}

Quick Explanations;

  • get_content() : This function returns the content material materials of the submit you’ll have appeared for (that’s provided by WordPress and by no means set by you). This doesn’t accept any parameters.
  • get_var( ‘var_name’ ) : Usually it might probably get difficult when you’ll have set a wide range of data. This accepts one parameter: a string of the variable establish you want. This is a document of the obtainable ‘var_name’s;
  • ‘title’ – The Submit Title you’ll have set.
  • ‘sort’ – The Submit Kind you’ll have set.
  • ‘content material materials’ – The Content material materials you’ll have set.
  • ‘class’ – The Courses you’ll have set (returns array).
  • ‘template’ – The Net web page Template you’ll have set.
  • ‘slug’ – The Slug you’ll have set.
  • ‘auth_id’ – The Creator ID you’ll have set.
  • ‘standing’ – The Submit Standing you’ll have set.
  • ‘current_post’ – The WP Submit Object returned after trying.
  • ‘current_post_id’ – The WP Submit ID returned after trying.
  • ‘current_post_permalink’ – The WP Submit’s permalink returned after trying.
  • ‘errors’ – The Errors Array (very useful).
  • unset_all() : No parameters. One job. Deletes all data saved inside the event of the class. Beware.
  • __toString() : That’s what’s run when the event of the class itself is printed. Error message printed. Use Use PrettyPrintAll()
// Start new class
$Poster = new PostController();

// Echoes error message
echo $Poster;
  • PrettyPrint() : That’s solely a helpful function which reveals objects and arrays correctly in ‘pre’ tags. Takes one parameter: the information is to ‘PrettyPrinted’.
  • PrettyPrintAll() : That is equivalent as PrettyPrint(), moreover ‘PrettyPrints’ your complete event of the class (along with all variables).

Download The WPSaviour App Now

Related posts
Beginner’s GuideBlogShowcase

7 Best Shopify Alternatives in 2020 (Cheaper and More Powerful)

Beginner’s GuideBest WordPress PluginsBlog

14 Best AI Chatbots Software for Your Website (Comparison)

Beginner’s GuideBlogTips

Magento vs WooCommerce – Which one is Better? (Comparison)

Beginner’s GuideBlogTips

12 Best Calculator Plugins for Your WordPress Site

Sign up for our Newsletter and
stay informed

Fear Of Missing Out?

Sign up with your email address to receive WordPress tips and updates
SUBSCRIBE NOW
Terms and Conditions apply
close-link
Click Me