Note
The General Public License, Version 2, License
Installing WordPress Plugins
Building Your Own Plugin
<?
php
/**
* Plugin Name: My Plugin
* Plugin URI: https://bwawwp.com/my-plugin/
* Description: This is my plugin description.
* Author: messenlehner, strangerstudios
* Version: 1.0.0
* Author URI: https://bwawwp.com
* License: GPL-2.0+
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
*/
?>
<?
php
function
my_plugin_wp_footer
()
{
echo
'I read Building Web Apps with WordPress
and now I am a WordPress Genius!'
;
}
add_action
(
'wp_footer'
,
'my_plugin_wp_footer'
);
?>
File Structure for an App Plugin
/plugins/schoolpress/adminpages/
/plugins/schoolpress/classes/
/plugins/schoolpress/css/
/plugins/schoolpress/css/admin.css
/plugins/schoolpress/css/frontend.css
/plugins/schoolpress/js/
/plugins/schoolpress/images/
/plugins/schoolpress/includes/
/plugins/schoolpress/includes/lib/
/plugins/schoolpress/includes/functions.php
/plugins/schoolpress/pages/
/plugins/schoolpress/services/
/plugins/schoolpress/scheduled/
/plugins/schoolpress/schoolpress.php
/adminpages/
<?
php
// add a SchoolPress menu with reports page
function
sp_admin_menu
()
{
add_menu_page
(
'SchoolPress'
,
'SchoolPress'
,
'manage_options'
,
'sp_reports'
,
'sp_reports_page'
);
}
add_action
(
'admin_menu'
,
'sp_admin_menu'
);
// function to load admin page
function
sp_reports_page
()
{
require_once
dirname
(
__FILE__
)
.
"/adminpages/reports.php"
;
}
?>
/classes/
/css/
<?
php
function
sp_load_admin_styles
()
{
wp_enqueue_style
(
'schoolpress-plugin-admin'
,
plugins_url
(
'css/admin.css'
,
__FILE__
),
array
(),
SCHOOLPRESS_VERSION
,
'screen'
);
}
add_action
(
'admin_enqueue_scripts'
,
'sp_load_admin_styles'
);
function
sp_load_frontend_styles
()
{
wp_enqueue_style
(
'schoolpress-plugin-frontend'
,
plugins_url
(
'css/frontend.css'
,
__FILE__
),
array
(),
SCHOOLPRESS_VERSION
,
'screen'
);
}
add_action
(
'wp_enqueue_scripts'
,
'sp_load_frontend_styles'
);
?>
/js/
<?
php
function
sp_load_admin_scripts
()
{
wp_enqueue_script
(
'schoolpress-plugin-admin'
,
plugins_url
(
'js/admin.js'
,
__FILE__
),
array
(
'jquery'
),
SCHOOLPRESS_VERSION
);
}
add_action
(
'admin_enqueue_scripts'
,
'sp_load_admin_scripts'
);
function
sp_load_frontend_scripts
()
{
wp_enqueue_script
(
'schoolpress-plugin-frontend'
,
plugins_url
(
'js/frontend.js'
,
__FILE__
),
array
(
'jquery'
),
SCHOOLPRESS_VERSION
);
}
add_action
(
'wp_enqueue_scripts'
,
'sp_load_frontend_scripts'
);
?>
Note
/images/
/includes/
/includes/lib/
/pages/
<?
php
// preheader
function
sp_stub_preheader
()
{
if
(
!
is_admin
()
)
{
global
$post
,
$current_user
;
if
(
!
empty
(
$post
->
post_content
)
&&
strpos
(
$post
->
post_content
,
'[sp_stub]'
)
!==
false
)
{
/*
Put your preheader code here.
*/
}
}
}
add_action
(
'wp'
,
'sp_stub_preheader'
,
1
);
// shortcode [sp_stub]
function
sp_stub_shortcode
()
{
ob_start
();
?>
Place your HTML/etc code here.
<?php
$temp_content
=
ob_get_contents
();
ob_end_clean
();
return
$temp_content
;
}
add_shortcode
(
'sp_stub'
,
'sp_stub_shortcode'
);
?>
/services/
/scheduled/
/schoolpress.php
Add-Ons to Existing Plugins
Use Cases and Examples
The WordPress Loop
index.php
archive.php
category.php
tag.php
single.php
page.php
<?
php
if
(
have_posts
()
)
{
while
(
have_posts
()
)
{
the_post
();
the_title
(
'<h2>'
,
'</h2>'
);
the_content
();
}
}
else
{
// show a message like sorry no posts!
}
?>
WordPress Global Variables
<?
php
echo
'<pre>'
;
print_r
(
$GLOBALS
);
echo
'</pre>'
;
?>
<?
php
global
$global_variable_name
;
?>
$post
An object that contains all post data from the
wp_posts
table for the current post that you are on within the WordPress loop.$authordata
An object with all author data of the current post that you are on within the WordPress loop.
$wpdb
Using custom database tables
Example 3-1. Database setup for SchoolPress
<?
php
// set up the database for the SchoolPress app
function
sp_setupDB
()
{
global
$wpdb
;
// shortcuts for SchoolPress DB tables
$wpdb
->
schoolpress_assignment_submissions
=
$wpdb
->
prefix
.
'schoolpress_assignment_submissions'
;
$db_version
=
get_option
(
'sp_db_version'
,
0
);
// create tables on new installs
if
(
empty
(
$db_version
)
)
{
global
$wpdb
;
$sqlQuery
=
"
CREATE TABLE '"
.
$wpdb
->
schoolpress_assignment_submissions
.
"' (
`assignment_id` bigint(11) unsigned NOT NULL,
`submission_id` bigint(11) unsigned NOT NULL,
UNIQUE KEY `assignment_submission` (`assignment_id`,`submission_id`),
UNIQUE KEY `submission_assignment` (`submission_id`,`assignment_id`)
)
"
;
require_once
ABSPATH
.
'wp-admin/includes/upgrade.php'
;
dbDelta
(
$sqlQuery
);
$db_version
=
'1.0'
;
update_option
(
'sp_db_version'
,
'1.0'
);
}
}
add_action
(
'init'
,
'sp_dbSetup'
,
0
);
?>
Put each field on its own line in your SQL statement.
Leave two spaces between the words
PRIMARY KEY
and the definition of your primary key.Use the keyword
KEY
rather than its synonymINDEX
, and include at least oneKEY
.Do not use any apostrophes or backticks around field names.
Running queries
$wpdb->result
Contains the raw result from your SQL query.
$wpdb->num_queries
Increments each time a query is run.
$wpdb->last_query
Contains the last SQL query run.
$wpdb->last_error
Contains a string with the last SQL error generated if there was one.
$wpdb->insert_id
Contains the ID created from the last successful
INSERT
query.$wpdb->rows_affected
Set to the number of affected rows.
$wpdb->num_rows
Set to the number of rows in a result for a
SELECT
query.$wpdb->last_result
Contains an array of row objects generated through the
mysql_fetch_object()
PHP function.
Returns false if the query failed. You can test for this by using code like
if($wpdb->query($query) === false) { wp_die("it failed!""); }
.The raw MySQL result is returned on
CREATE
,ALTER
,TRUNCATE
, andDROP
queries.The number of rows affected is returned for
INSERT
,UPDATE
,DELETE
, andREPLACE
queries.The number of rows affected is returned for
SELECT
queries.
Escaping in database queries
Example 3-2. Using the esc_sql() function
global
$wpdb
;
$user_query
=
$_REQUEST
[
'uq'
];
$sqlQuery
=
"SELECT user_login FROM
$wpdb->users
WHERE
user_login LIKE '%"
.
esc_sql
(
$user_query
)
.
"%' OR
user_email LIKE '%"
.
esc_sql
(
$user_query
)
.
"%' OR
display_name LIKE '%"
.
esc_sql
(
$user_query
)
.
"%'
"
;
$user_logins
=
$wpdb
->
get_col
(
$sqlQuery
);
if
(
!
empty
(
$user_logins
))
{
echo
"<ul>"
;
foreach
(
$user_logins
as
$user_login
)
{
echo
"<li>
$user_login
</li>"
;
}
echo
"</ul>"
;
}
$query
A string of your custom SQL statement with placeholders for each dynamic value.
$args
One or more additional parameters to be used to replace the placeholders in your SQL statement.
%d
(integer)%f
(float)%s
(string)%%
(literal percentage sign—no argument needed)
$sqlQuery
=
$wpdb
->
prepare
(
"SELECT user_login FROM
$wpdb->users
WHERE
user_login LIKE %%%s%% OR
user_email LIKE %%%s%% OR
display_name LIKE %%%s%%"
,
$user_query
,
$user_query
,
$user_query
);
$user_logins
=
$wpdb
->
get_col
(
$sqlQuery
);
Note
SELECT queries with $wpdb
OBJECT
Result will be output as a numerically indexed array of row objects.
OBJECT_K
Result will be output as an associative array of row objects, using the first column’s values as keys (duplicates will be discarded).
ARRAY_A
Result will be output as an numerically indexed array of associative arrays, using column names as keys.
ARRAY_N
Result will be output as a numerically indexed array of numerically indexed arrays.
<?
php
global
$wpdb
;
$sqlQuery
=
"SELECT * FROM
$wpdb->posts
WHERE post_type = 'assignment'
AND post_status = 'publish' LIMIT 10"
;
$assignments
=
$wpdb
->
get_results
(
$sqlQuery
);
// rows are stored in an array, use foreach to loop through them
foreach
(
$assignments
as
$assignment
)
{
// each item is an object with property names equal to the SQL column names?>
<
h3
><?
php
echo
$assignment
->
post_title
;
?>
</h3>
<?php
echo
apply_filters
(
"the_content"
,
$assignment
->
post_content
);
?>
<?php
}
?>
<?
php
global
$wpdb
;
$sqlQuery
=
"SELECT ID FROM
$wpdb->posts
WHERE post_type = 'assignment'
AND post_status = 'publish'
LIMIT 10"
;
// getting IDs
$assignment_ids
=
$wpdb
->
get_col
(
$sqlQuery
);
// result is an array, loop through them
foreach
(
$assignment_ids
as
$assignment_id
)
{
// we have the id, we can use get_post to get more data
$assignment
=
get_post
(
$assignment_id
);
?>
<h3>
<?php
echo
$assignment
->
post_title
;
?>
</h3>
<?php
echo
apply_filters
(
"the_content"
,
$assignment
->
post_content
);
?>
<?php
}
?>
Insert, replace, and update
<?
php
// processing new submissions for assignments
global
$wpdb
,
$current_user
;
// create submission
$assignment_id
=
intval
(
$_REQUEST
[
'assignment_id'
]
);
$submission_id
=
wp_insert_post
(
array
(
'post_type'
=>
'submission'
,
'post_author'
=>
$current_user
->
ID
,
'post_title'
=>
sanitize_title
(
$_REQUEST
[
'title'
]
),
'post_content'
=>
sanitize_text_field
(
$_POST
[
'submission'
]
)
)
);
// connect the submission to the assignment
$wpdb
->
insert
(
$wpdb
->
schoolpress_assignment_submissions
,
array
(
"assignment_id"
=>
$assignment_id
,
"submission_id"
=>
$submission_id
),
array
(
'%d'
,
'%d'
)
);
/*
This insert call will generate a SQL query like:
INSERT INTO
'wp_schoolpress_assignment_submissions'
('assignment_id','submission_id' VALUES (101,10)
*/
?>
<?
php
global
$wpdb
;
// just update the status
$wpdb
->
update
(
'ecommerce_orders'
,
//table name
array
(
'status'
=>
'paid'
),
//data fields
array
(
'id'
=>
$order_id
)
//where fields
);
// update more data about the order
$wpdb
->
update
(
'ecommerce_orders'
,
//table name
array
(
'status'
=>
'pending'
,
//data fields
'subtotal'
=>
'100.00'
,
'tax'
=>
'6.00'
,
'total'
=>
'106.00'
),
array
(
'id'
=>
$order_id
)
//where fields
);
?>
$wp_query
An object of the
WP_Query
class that can show you all of the post content returned by WordPress for any given page that you are on. We will talk more about theWP_Query
class and its methods in the next blog.$current_user
An object of all of the data associated with the currently logged-in user. Not only does this object return all of the data for the current user from the
wp_users
table, but it will also give you the roles and capabilities of the current user:<?
php
//welcome the logged-in user
global
$current_user
;
if
(
!
empty
(
$current_user
->
ID
)
)
{
echo
'Howdy, '
.
$current_user
->
display_name
;
}
?>
Free Plugins
Admin Columns
Advanced Custom Fields
- Repeater field
Allows you to create a set of subfields which can be repeated over and over again, as a way of adding a list of values.
- Gallery field
Provides a nice UI for managing multiple images.
- Options page
Provides functions for adding extra admin pages to update ACF fields.
- Flexible content field
Creates custom layouts with a content-layout UI.
BadgeOS
Posts 2 Posts
Column | Type | Collation | Null | Default | Extra |
---|---|---|---|---|---|
|
| No | None | AUTO_INCREMENT | |
|
| No | None | ||
|
| No | None | ||
|
| utf8_general_ci | No |
Column | Type | Collation | Null | Default | Extra |
---|---|---|---|---|---|
|
| No | None | AUTO_INCREMENT | |
|
| No | 0 | ||
|
| utf8_general_ci | Yes | NULL | |
|
| utf8_general_ci | Yes | NULL |
Members
W3 Total Cache
Yoast SEO
Premium Plugins
Gravity Forms
BackupBuddy
WP All Import
Community Plugins
BuddyPress
Database tables
Column | Type | Collation | Null | Default | Extra |
---|---|---|---|---|---|
|
| No | None | AUTO_INCREMENT | |
|
| No | None | ||
|
| utf8_general_ci | No | None | |
|
| utf8_general_ci | No | None | |
|
| utf8_general_ci | No | None | |
|
| utf8_general_ci | No | None | |
|
| utf8_general_ci | No | None | |
|
| No | None | ||
|
| Yes | NULL | ||
|
| No | None | ||
|
| Yes | 0 | ||
|
| No | 0 | ||
|
| No | 0 | ||
|
| No | 0 |
Column | Type | Collation | Null | Default | Extra |
---|---|---|---|---|---|
|
| No | None | AUTO_INCREMENT | |
|
| No | None | ||
|
| utf8_general_ci | Yes | NULL | |
|
| utf8_general_ci | Yes | NULL |
Column | Type | Collation | Null | Default | Extra |
---|---|---|---|---|---|
|
| No | None | AUTO_INCREMENT | |
|
| No | None | ||
|
| No | None | ||
|
| Yes | 0 | ||
|
| Yes | 0 | ||
|
| No | None |
Column | Type | Collation | Null | Default | Extra |
---|---|---|---|---|---|
|
| No | None | AUTO_INCREMENT | |
|
| No | None | ||
|
| utf8_general_ci | No | None | |
|
| utf8_general_ci | No | None | |
|
| utf8_general_ci | No | None | |
|
| utf8_general_ci | No | Public | |
|
| No | 1 | ||
|
| No | None |
Column | Type | Collation | Null | Default | Extra |
---|---|---|---|---|---|
|
| No | None | AUTO_INCREMENT | |
|
| No | None | ||
|
| utf8_general_ci | Yes | NULL | |
|
| utf8_general_ci | Yes | NULL |
Column | Type | Collation | Null | Default | Extra |
---|---|---|---|---|---|
|
| No | None | AUTO_INCREMENT | |
|
| No | None | ||
|
| No | None | ||
|
| No | None | ||
|
| No | 0 | ||
|
| No | 0 | ||
|
| utf8_general_ci | No | None | |
|
| No | None | ||
|
| utf8_general_ci | No | None | |
|
| No | 0 | ||
|
| No | 0 | ||
|
| No | 0 |
Column | Type | Collation | Null | Default | Extra |
---|---|---|---|---|---|
|
| No | None | AUTO_INCREMENT | |
|
| No | None | ||
|
| No | None | ||
|
| utf8_general_ci | No | None | |
|
| utf8_general_ci | No | None | |
|
| No | None |
Column | Type | Collation | Null | Default | Extra |
---|---|---|---|---|---|
|
| No | None | AUTO_INCREMENT | |
|
| utf8_general_ci | No | None | |
|
| utf8_general_ci | No | None | |
|
| No | None | ||
|
| No | 0 |
Column | Type | Collation | Null | Default | Extra |
---|---|---|---|---|---|
|
| No | None | AUTO_INCREMENT | |
|
| No | None | ||
|
| No | None | ||
|
| No | 0 | ||
|
| No | 0 | ||
|
| No | 0 |
Column | Type | Collation | Null | Default | Extra |
---|---|---|---|---|---|
|
| No | None | AUTO_INCREMENT | |
|
| No | None | ||
|
| No | None | ||
|
| Yes | NULL | ||
|
| utf8_general_ci | No | None | |
|
| utf8_general_ci | No | None | |
|
| No | None | ||
|
| No | 0 |
Column | Type | Collation | Null | Default | Extra |
---|---|---|---|---|---|
|
| No | None | AUTO_INCREMENT | |
|
| No | None | ||
|
| No | None |
Column | Type | Collation | Null | Default | Extra |
---|---|---|---|---|---|
|
| No | None | AUTO_INCREMENT | |
|
| No | None | ||
|
| utf8_general_ci | Yes | NULL | |
|
| utf8_general_ci | Yes | NULL |
Column | Type | Collation | Null | Default | Extra |
---|---|---|---|---|---|
|
| No | None | AUTO_INCREMENT | |
|
| No | None | ||
|
| No | None | ||
|
| utf8_general_ci | No | None | |
|
| No | None |
Column | Type | Collation | Null | Default | Extra |
---|---|---|---|---|---|
|
| No | None | AUTO_INCREMENT | |
|
| No | None | ||
|
| No | None | ||
|
| utf8_general_ci | No | None | |
|
| utf8_general_ci | No | None | |
|
| utf8_general_ci | No | None | |
|
| No | 0 | ||
|
| No | 0 | ||
|
| No | 0 | ||
|
| No | 0 | ||
|
| utf8_general_ci | No | ||
|
| No | 1 |
Column | Type | Collation | Null | Default | Extra |
---|---|---|---|---|---|
|
| No | None | AUTO_INCREMENT | |
|
| utf8_general_ci | No | None | |
|
| utf8_general_ci | No | None | |
|
| No | 0 | ||
|
| No | None |
Column | Type | Collation | Null | Default | Extra |
---|---|---|---|---|---|
|
| No | None | AUTO_INCREMENT | |
|
| No | None | ||
|
| utf8_general_ci | No | None | |
|
| utf8_general_ci | Yes | NULL | |
|
| utf8_general_ci | Yes | NULL |
Components
- Extended Profiles
Like any typical social network, BuddyPress has member profiles. A member has complete control of their profile. Out of the box, all members are listed in a members directory; when you click on a member’s name, you’re taken to their profile page.
- Account Settings
Members can update their email address, change their password, and even manage the email notifications they receive when other members interact with them.
- Friend Connections
Members can add one another as friends. Members ask other membere to be friends by sending and receiving friend requests. Think Facebook friends.
- Private Messaging
Members send private messages to one another and view their messages in one place, like an inbox for your social network. Members can reply, mark as read, delete, and perform other actions with messages as with any large social network.
- Activity Streams
Members can post activity updates to their profiles and groups, leave comments on other members’ or groups’ activity, and favorite activity posts. Sounds like Facebook, right? BuddyPress has an @mention feature similar to when someone mentions you on Twitter. @mentions automatically link to the mentioned member’s profile page, and if that member has their notifications turned off, they receive an email about it. Activity also comes standard with RSS feeds.
- User Groups
A powerful component of BuddyPress, groups can be created organically (or not) by network members. Each group appears on a Groups listing page, and clicking a group’s avatar brings you to its page. The group profile is set up like the member profile page, but with group-specific subpages such as group activity, members, admin settings, and invite friends. Groups can be public, private, or hidden, and members can be promoted to group administrators or group moderators.
- Site Tracking
New posts and comments on your site create BuddyPress activity posts. If you are running BuddyPress on a WordPress multisite network, posts and comments created on any site in your network will also create BuddyPress activity posts.
Pages
Note
Settings
- Toolbar
By default, BuddyPress shows the WordPress admin bar with Login and Register links for users who aren’t logged in. You can also turn off this feature here.
- Account Deletion
You can decide whether you will allow registered users to delete their accounts.
- Avatar Uploads
You can allow registered members to upload avatars.
- Profile Syncing
You can enable BuddyPress to WordPress profile syncing.
- Group Creation
You can allow your registered members to create their own groups. Site admins can still create groups if this setting is turned off.
- Blog & Forum Comments
You can allow activity stream commenting on blog and forum posts.
Profile fields
Note
BuddyPress plugins
- BuddyPress Media
This plugin allows your members to upload photos, music, and videos to their activity posts. It also allows for your members to organize all of their photos into photo albums on their profile page. There is mobile device support that includes automatic audio and video conversion.
- BuddyPress Registration Options
This is a great plugin for stopping spambots from registering on your BuddyPress website. This plugin allows for new member moderation; if moderation is turned on from the admin settings page, any new members will be blocked from interacting with any BuddyPress components (except editing their own profile and uploading their avatar) and will not be listed in any directory until an administrator approves or denies their account. If moderation is turned on, admins can create custom display messages and email alert messages for approved or denied accounts. When an admin approves or denies, custom emails are sent to new members informing them whether they were approved or denied.
- AppPresser Add-On
The AppPresser AppCommunity add-on allows AppPresser users to create a social mobile app for their WordPress website similar to Instagram or Facebook using BuddyPress. With AppCommunity, app users can post activity updates and photos, create friendships, send private messages, join groups, and more.
- BadgeOS Community Add-On
The BadgeOS Community Add-On integrates BadgeOS features into BuddyPress and bbPress. Site members complete achievements and earn badges based on a range of community activities and triggers. This add-on to BadgeOS also includes the ability to display badges and achievements on user profiles and activity feeds.
- bbPress
Got forums? bbPress can fulfill all your forum needs. Unlike BuddyPress, bbPress utilizes custom post types, so it does not create its own tables in the database like it used to in prior versions.
Using bbPress can require a bit of theme work if your theme isn’t already styled to support bbPress, but it is by far the easiest way to add forum functionality to a WordPress site.
1 In the context of the GPL, distribution means selling your source code or offering it for download on a website like the WordPress.org plugin repository. Code that you personally install for someone does not need to inherit the GPL license.
2 A synchronized entry in both the wp_usermeta
and wp_postmeta
tables would be needed to provide the same lookup ability of a single wp_schoolpress_assignment_submissions
table.