Birchpress – How Do I Export Client Appointments?

As of 2015, from what i’ve read on forums and the Birchpress documentation, you can’t — as of a few minutes ago, i have at least something working!

This is just a PHP script that you can put in a hook or whatever – but in my scenario I’m just going to the URL example.com/services/exportAppointments.php

First we want to include wordpress functionality in our service: (mine’s in a folder i made called “services”, so i need to go up a directory to the be in the root, thus the ‘../’)

<?php 
include '../wp-load.php'; 
?>

We’ll need two functions, one to find an appointment and one to find a client by an ID:

<?php
/***********************************
  Query Single Appointment Details
***********************************/ 
function getAppointment($postID){
  query_posts(array( 
    'post_type' => 'birs_appointment',
    'p' => $postID
  ));  
  while (have_posts()) : the_post(); 
    $data = get_post_meta(get_the_ID()); 
  endwhile;
  wp_reset_query();
  return $data;
}
?>
<?php
/***********************************
  Query Single Client Details
***********************************/ 
function getClient($postID){
  query_posts(array( 
    'post_type' => 'birs_client',
    'p' => $postID
  ));  
  while (have_posts()) : the_post(); 
    $data = get_post_meta(get_the_ID()); 
  endwhile;
  wp_reset_query();
  return $data;
}
?>

The post type that links these together is called “birs_appointment1on1”, so getting a query of those (you can apply your own filters here) will give me the list of all the appointments, which from there I can get the relevant info of the various clients and appointments. There may be a more sleek way to do this so you don’t re-query those, but this is just a quickie. (please note, i am using the client Zipcode as a zipcode for their private practice, and i create a custom field for their practice name, so there’s an example of custom data in there too!)

<?php
/*****************************************
  Query the Various Appointments
*****************************************/ 
$birchpress_appointments = query_posts(array( 
  'post_type' => 'birs_appointment1on1', 
  'showposts' => -1
)); 
foreach($birchpress_appointments as $birchpress_appointment): 
  $birchID = $birchpress_appointment->ID;
  $data = get_post_meta($birchID); 

  //CLIENT
  $clientID = $data['_birs_client_id'][0];
  $client = getClient($clientID);
  //APPOINTMENT
  $appointmentID = $data['_birs_appointment_id'][0];
  $appointment = getAppointment($appointmentID);
endforeach;
?>

So, let’s put it all together and export the data as a csv – hopefully this provides a good starting point for anyone that wants to take the last query and apply meta filters to the _birs_appointment_id and _birs_client_id fields

<?php 
include '../wp-load.php'; 

//OUTPUT HEADERS - makes browser download a CSV
header('Content-type: text/csv');
header('Content-Disposition: attachment; filename="appointments.csv"');
header('Pragma: no-cache');
header('Expires: 0');
$file = fopen('php://output', 'w');

// COLUMN HEADERS
fputcsv($file, array(
  'First Name', 
  'Last Name', 
  'Email', 
  'Phone', 
  'Practice Name', 
  'Practice Zip', 
  "Appointment"
));
$csvdata = array();

/*****************************************
  Query the Various Appointments
*****************************************/ 
$birchpress_appointments = query_posts(array( 
  'post_type' => 'birs_appointment1on1', //birs_appointment
  'showposts' => -1
)); 
foreach($birchpress_appointments as $birchpress_appointment): 
  $birchID = $birchpress_appointment->ID;
  $data = get_post_meta($birchID); 

  //CLIENT DATA
  $clientID = $data['_birs_client_id'][0];
  $client = getClient($clientID);
  $fname = $client['_birs_client_name_first'][0];
  $lname = $client['_birs_client_name_last'][0];
  $email = $client['_birs_client_email'][0];
  $phone = $client['_birs_client_phone'][0];
  $practiceName = $client['_birs_field_6'][0];
  $practiceZip = $client['_birs_client_zip'][0];

  //APPOINTMENT DATA
  $appointmentID = $data['_birs_appointment_id'][0];
  $appointment = getAppointment($appointmentID);
  $timestamp = $appointment['_birs_appointment_timestamp'][0];
  
  // COLUMN ROWS -- match COLUMN HEADERS array structure
  $csvdata[] = array(
    $fname,
    $lname,
    $email,
    $phone,
    $practiceName,
    $practiceZip,
    date('Y-m-d H:i:s', $timestamp)
  );

endforeach;
wp_reset_query();

// output each row of the data
foreach ($csvdata as $row){
  fputcsv($file, $row);
}
exit();


/***********************************
  Query Single Appointment Details
***********************************/ 
function getAppointment($postID){
  query_posts(array( 
    'post_type' => 'birs_appointment',
    'p' => $postID
  ));  
  while (have_posts()) : the_post(); 
    $data = get_post_meta(get_the_ID()); 
  endwhile;
  wp_reset_query();
  return $data;
}


/***********************************
  Query Single Client Details
***********************************/ 
function getClient($postID){
  query_posts(array( 
    'post_type' => 'birs_client',
    'p' => $postID
  ));  
  while (have_posts()) : the_post(); 
    $data = get_post_meta(get_the_ID()); 
  endwhile;
  wp_reset_query();
  return $data;
}

?>

Formidable: Populate select field with a post type

Setting up options in formidable is easy if you know what your options are.  There are times tho that the list is dynamic and we want to keep it up to date as the site updates. For example, I have a careers post type of available job offerings and I have an application form that they are able to apply for them.  I wanted a select field for the user to find the position they want to apply for and have it hooked up to the list of careers.

Here’s a little something to add into your functions.php file.  Things to know would be:

  • ID of the field set up in formidable
    in this example it is “73”
  • Post Type to query
    this is an example to create a select field filled with job positions available from my “Career” post type.
add_filter('frm_setup_new_fields_vars', 'add_a_field_function', 20, 2);
add_filter('frm_setup_edit_fields_vars', 'add_a_field_function', 20, 2);

function add_a_field_function($values, $field){

	if($field->id == 73){
		$arrayPositions = array();
		$pushobj = array(
			value => "",
			label => "Select a position..."
		);
		array_push($arrayPositions, $pushobj);
		$positionQuery = new WP_Query( array( 'post_type' => 'career', 'posts_per_page' => -1, 'orderby' => "menu_order", 'order' => "ASC") );
		if ( $positionQuery->have_posts() ) {
			while ( $positionQuery->have_posts() ) {
				$positionQuery->the_post();
				$pushobj = array(
					value => get_the_title(),
					label => get_the_title()
				);
				array_push($arrayPositions, $pushobj);
			}
			wp_reset_postdata();
		}

	   	$values['options'] = $arrayPositions;
	}
	return $values;
}

Visual Composer: vc_map field examples

There’s a few things missing to the documentation for Visual composer, like samples of how to use each field type.  Some of these are probably pretty intuitive, but we figured we’d make some example for each as more of a library of snippets to pick for the vc_map function. Sometimes just an example of something that works for a type is all you need to feel more confident — Enjoy!  [VC Documentation]

textarea_html
Text area with default WordPress WYSIWYG Editor. Important: only one html textarea is permitted per shortcode and it should have “content” as a param_name

array(
  "type" => "textarea_html",
  "class" => "",
  "heading" => __( "Field Label", "my-text-domain" ),
  "param_name" => "field_name",
  "value" => '', 
  "description" => __( "Enter description.", "my-text-domain" )
)

textfield/textarea
Simple input / textarea field

array(
  "type" => "textfield",
  "class" => "",
  "heading" => __( "Field Label", "my-text-domain" ),
  "param_name" => "field_name",
  "value" => __( "", "my-text-domain" ),
  "description" => __( "Enter description.", "my-text-domain" )
)
array(
  "type" => "textarea",
  "class" => "",
  "heading" => __( "Field Label", "my-text-domain" ),
  "param_name" => "field_name",
  "value" => __( "", "my-text-domain" ),
  "description" => __( "Enter description.", "my-text-domain" )
)

dropdown
Dropdown input field with set of available options. Array containing the drop down values (either should be a normal array, or an associative array)

array(
  'type' => 'dropdown',
  'heading' => __( 'Field Label',  "my-text-domain" ),
  'param_name' => 'field_name',
  'value' => array(
    __( 'Option 1 Label',  "my-text-domain"  ) => 'option1value',
    __( 'Option 2 Label',  "my-text-domain"  ) => 'option2value',
    __( 'Option 3 Label',  "my-text-domain"  ) => 'option3value',
  ),
  "description" => __( "Enter description.", "my-text-domain" )
)

attach_imageattach_images
Single image selection/Multiple images selection

array(
  "type" => "attach_image",
  "class" => "",
  "heading" => __( "Field Label", "my-text-domain" ),
  "param_name" => "field_name",
  "value" => '',
  "description" => __( "Enter description.", "my-text-domain" )
)
array(
  "type" => "attach_images",
  "class" => "",
  "heading" => __( "Field Label", "my-text-domain" ),
  "param_name" => "field_name",
  "value" => '',
  "description" => __( "Enter description.", "my-text-domain" )
)

posttypes
Checkboxes with available post types (automatically finds all post types)

array(
  "type" => "posttypes",
  "class" => "",
  "heading" => __( "Field Label", "my-text-domain" ),
  "param_name" => "field_name",
  "value" => __( "", "my-text-domain" ),
  "description" => __( "Enter description.", "my-text-domain" )
)	

colorpicker
Color picker

array(
  "type" => "colorpicker",
  "class" => "",
  "heading" => __( "Field Label", "my-text-domain" ),
  "param_name" => "field_name",
  "value" => '', 
  "description" => __( "Enter description.", "my-text-domain" )
)

exploded_textarea
Text area, where each line will be imploded with comma (,)

array(
  "type" => "exploded_textarea",
  "class" => "",
  "heading" => __( "Field Label", "my-text-domain" ),
  "param_name" => "field_name",
  "value" => '', 
  "description" => __( "Enter description.", "my-text-domain" )
)

widgetised_sidebars
Dropdown element with set of available widget regions, that are registered in the active wp theme

array(
  "type" => "widgetised_sidebars",
  "class" => "",
  "heading" => __( "Field Label", "my-text-domain" ),
  "param_name" => "field_name",
  "value" => '', 
  "description" => __( "Enter description.", "my-text-domain" )
)

textarea_raw_html
Text area, its content will be coded into base64 (this allows you to store raw js or raw html code)

array(
  "type" => "textarea_raw_html",
  "class" => "",
  "heading" => __( "Field Label", "my-text-domain" ),
  "param_name" => "field_name",
  "value" => '', 
  "description" => __( "Enter description.", "my-text-domain" )
)

vc_link
Link selection. Then in shortcodes html output, use $href = vc_build_link( $href ); to parse link attribute

array(
  "type" => "vc_link",
  "class" => "",
  "heading" => __( "Field Label", "my-text-domain" ),
  "param_name" => "field_name",
  "value" => '', 
  "description" => __( "Enter description.", "my-text-domain" )
)

checkbox
Creates checkboxes, can have 1 or multiple checkboxes within one attribute

array(
  "type" => "checkbox",
  "class" => "",
  "heading" => __( "Field Label", "my-text-domain" ),
  "param_name" => "field_name",
  "value" => __( "", "my-text-domain" ),
  "description" => __( "Enter description.", "my-text-domain" )
)

loop
Loop builder. Lets your users to construct loop which can later be used during the shortcode’s output

array(
  "type" => "loop",
  "class" => "",
  "heading" => __( "Field Label", "my-text-domain" ),
  "param_name" => "field_name",
  "value" => '', 
  "description" => __( "Enter description.", "my-text-domain" )
)

css
Basic CSS style editor for your content element. Check “Add “Design Options” Tab with CSS Editor to Your Element” page for more details

array(
  "type" => "css",
  "class" => "",
  "heading" => __( "Field Label", "my-text-domain" ),
  "param_name" => "field_name",
  "value" => '', 
  "description" => __( "Enter description.", "my-text-domain" )
)

… attribute types can be extended with new custom types.
Create Your Own 

Ajax requests in WordPress

There are many reasons to use Ajax on a website as it allows the content to load into the page as needed.  In the past i’ve always made a separate file for handling all these things, and performance wise they may be about the same. However, there is a built in way to do these things the official WordPress way that was actually easier to work with than creating new services.

WordPress Documentation
Demo example

Summarizing, there is a “wp_ajax_[ACTION]” hook that allows server side processing of the ajax request.

add_action( 'wp_ajax_nopriv_[ACTION]', 'ajax_process_function' );
add_action( 'wp_ajax_[ACTION]', 'ajax_process_function' );
function ajax_process_function() {
	$filterpage = $_REQUEST['page'];
	$filterformat = $_REQUEST['format'];
	echo "Page:".$filterpage." Format:".$filterformat;
	die();
}

This is accompanied by a jQuery ajax request that looks like:

$.ajax({
	url: "/wp-admin/admin-ajax.php",
	type: 'post',
	data: {
		action: '[ACTION]',
		filterpage : 1,
		filterformat : "format"
	},
	success: function( html ) {
		if(html){
			$('#container').html( html );
		}else{
			alert("no content");
		}
	}
});

How do I iterate through recently modified posts in WordPress?

I have a client who has a WordPress installation with thousands of pages. There are a couple things wrong with this, mainly relating to speed and editing practicality. It’s also an issue to find pages because they are ordered hierarchically. There are a few pages I modify fairly regularly and wanted a convenient way to find them. In order to do so, I needed to iterate through recently modified pages. Here’s what I came up with:

function recently_modified_dashboard_widget_function() {
	global $wpdb;
	
	$querystr = "
		SELECT $wpdb->posts.* 
		FROM $wpdb->posts
		WHERE $wpdb->posts.post_type = 'page'
		ORDER BY $wpdb->posts.post_modified DESC
		LIMIT 0,25
	";

	echo "
    \n"; foreach($wpdb->get_results($querystr, OBJECT) as $post) { echo '
  • '.edit_post_link( str_replace( site_url(), '', get_permalink( $post->ID ) ), '', '', $post->ID )."
  • \n"; } echo "
\n"; }

The query gets the last 25 posts of type page ordered by post_modified. From there, a foreach loop through the result yields individual posts in object form. The I used the post’s permalink, stripping off the site_url() as the text for the edit_post_link() text. All is well. I’ll soon publish the plugin which adds the list to the admin dashboard.

How do I change domains with wordpress plugin cforms installed

During development, I always use different domains for development and production.  Typically my deployment process goes like this

  1. Backup development filesystem and move to production
  2. Backup development database and restore on production
  3. Update table wp_options setting option_values for records with option_name siteurl and home to new url
  4. Install find and replace plugin
  5. Search for old url and replace with new URI (this updates paths that might be written hard into posts and pages)

I’d never used the cforms plugin before but was brought into the middle of a project using it and upon deploying to production, it stopped working.  After some digging, I found out that cforms had cached the development URI in two places in its settings:

  • cforms_root
  • tinyURI

My initial thought was just to update these values, but the serialized data was getting corrupted after updates.  So, I dug a little deeper into where the URI was being set.  I found it in lib_activate.php lines 8 and 9 (and saved via update_options() on line 184).  Realizing this was running during plugin activation, I deactivated the plugin, then activated it again and it corrected the URI issue.

In the future, if using cforms, my migration process will be

  1. Deactivate cforms
  2. Backup development filesystem and move to production
  3. Backup development database and restore on production
  4. Update table wp_options setting option_values for records with option_name siteurl and home to new url
  5. Install find and replace plugin
  6. Search for old url and replace with new URI (this updates paths that might be written hard into posts and pages)
  7. Activate cforms