This is my complete Wordpress plugin file:
<?php
function wp_create_table_install()
{
global $wpdb;
$table_name = $wpdb->prefix.'createtable';
$sql = 'CREATE TABLE '.$table_name.'(
id INT(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(75)
);';
require_once(ABSPATH.'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
function wp_create_table_insert_data()
{
global $wpdb;
$table_name = $wpdb->prefix.'createtable';
$id = 1;
$name = 'WP Create Table!';
$wpdb->insert($table_name, array('id' => $id, 'name' => $name));
}
register_activation_hook(__FILE__, 'wp_create_table_install');
register_activation_hook(__FILE__, 'wp_create_table_insert_data');
?>
When I activate the plugin, it always tries to create a table and insert data. How could I do it once, just in the first plugin activation?
Thank you.
A quicker way would be to add [IF NOT EXISTS] in your CREATE statement so that you don't get an error if your table already exists.
Before running CREATE TABLE, you could query information_schema.tables to check to see whether or not the table already exists.
Unfortunately, there's no way to run something on "install" - surprisingly, WordPress doesn't provide any hooks for install as opposed to activation!
The way people cope with this is to set and test an option - if the option is not set, then create the tables, and if it is set do nothing or do a DB upgrade. Options are read in and cached so there is no performance penalty to doing this.
$opt = get_option(MYPLUGIN_OPTIONS);
$opt['dbversion'] = 100;
...
update_option(MYPLUGIN_OPTIONS, $opt);
Related
I am trying to create table on plugin activation, I tried making the same function inside the class and calling it from the constructor, and I tried calling it outside the class and finally i tried to make another php file for calling it using the register_activation_hook, but nothing worked
plugin-code:
<?php
/**
*#package pageauthors
**/
/**
* Plugin Name: Page Authors
* Plugin URI: https://www.localhost.com/plugin
* Description: Allows you to add multiple authors to your wordpress post.
* Version: 1.0.0
* Author: Raphael Eid.
* Author URI: https://www.localhost.com/
* License: GPL v2 or Later
* Text Domain: PageAuthors
*/
$db = mysqli_connect('localhost','x','x','x');
//We can use require_once('../../../wp-config.php');
//mysql_connect(DB_HOST, DB_USER, DB_PASSWORD);
defined('ABSPATH') or die('Error my friend');
class pageauthors{
function register(){
//Call the Scripts
add_action('admin_enqueue_scripts', array($this, 'enqueue'));
//Create in the admin function
add_action('admin_menu', array($this, 'add_admin_pages'));
}
public function add_admin_pages(){
//add_menu_page( string $page_title, string $menu_title, string $capability, string $menu_slug, callable $function = '', string $icon_url = '', int $position = null )
add_menu_page('Add Author', 'Add Author', 'manage_options', 'raphaelprefix_plugin', array($this, 'admin_index'), 'dashicons-insert', 110);
}
public function admin_index(){
define( 'MY_PLUGIN_PATH', plugin_dir_path( __FILE__ ) );
include( MY_PLUGIN_PATH . 'templates/index.php');
// include( MY_PLUGIN_PATH . 'index.php');
include( MY_PLUGIN_PATH . 'templates/showAuthors.php');
// require_once plugin_dir_path(__FILE__) . 'templates/index.php';
}
function deactivate(){
global $wpdb;
$table_name = $wpdb->prefix . 'postsauthors';
$sql = "DROP TABLE IF EXISTS $table_name";
$wpdb->query($sql);
delete_option("my_plugin_db_version");
}
function enqueue(){
//Here we can enqueue and we should create the assets (css and js)
wp_enqueue_style('mypluginstyle', plugins_url('/assets/mystyle.css', __FILE__) );
wp_enqueue_script('mypluginstyle', plugins_url('/assets/mystyle.js', __FILE__) );
}
}
if(class_exists('pageauthors')){
$raphplugin = new pageauthors();
$raphplugin->register();
// $raphplugin->activate();
$raphplugin->deactivate();
}
function installer(){
include('installer.php');
}
//Activate - Register Activation Hook(__FILE__, array($instance, function))
register_activation_hook(__FILE__, 'installer');
//Deactivate - Register Deactivation Hook(__FILE__, array($instance, function))
register_deactivation_hook(__FILE__, array($raphplugin, 'deactivate') );
?>
installer.php
<?php
$db = mysqli_connect('localhost','x','x','x');
global $wpdb;
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
if (count($wpdb->get_var('SHOW TABLES LIKE "wp_postsauthors"')) == 0){
$sql = "CREATE TABLE `wp_postsauthors`
( `ID` INT(200) NOT NULL AUTO_INCREMENT , `post_ID` INT(200) NOT NULL ,
`author_name` VARCHAR(200) NOT NULL , `title` VARCHAR(200) NOT NULL ,
`description` VARCHAR(200) NOT NULL , PRIMARY KEY (`ID`)) ENGINE = InnoDB;";
dbDelta($sql);
}
Nothing is working even tho I am typing everything correctly
I'm going to simplify things as much as possible. Activation hooks are always frustrating to debug because of their async-like behavior.
First, you actually don't need to if check on whether the table exists, that's what dbDelta does for you already. You can actually change your schema that's defined in $sql later and dbDelta will attempt to figure that out and handle things automatically for you, too. In the real world, however, I have found that semi-complex table logic doesn't always make it through to an ALTER TABLE. Instead, most people keep track of their schema version and run table upgrades on plugin update. But that's for later.
Second, never assume the WordPress table prefix, that is asking for trouble some day. Instead, always use $wpdb->prefix.
The code below is the smallest version of a plugin that does what you are looking for. Instead of a function in a file, I'm just using a local anonymous function. The bulk of the code is the same as yours, just with some formatting that my IDE does for me automatically. This code is a full plugin which I'd recommend testing first. Once you've confirmed it is working, you should be able to pull the activation logic out. It is not wrong to use another file, I just try to remove as much distraction when I debug things.
<?php
/**
* Plugin Name: Page Authors
*/
register_activation_hook(
__FILE__,
static function () {
global $wpdb;
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
// Never assume the prefix
$table_name = $wpdb->prefix . 'postsauthors';
$sql = "CREATE TABLE `${table_name}`
(
`ID` INT(200) NOT NULL AUTO_INCREMENT ,
`post_ID` INT(200) NOT NULL ,
`author_name` VARCHAR(200) NOT NULL ,
`title` VARCHAR(200) NOT NULL ,
`description` VARCHAR(200) NOT NULL ,
PRIMARY KEY (`ID`)) ENGINE = InnoDB;";
dbDelta($sql);
}
);
As CodeIgniter comes out of the box, it supportes one controller for each unique url.
So, let's say i have the following urls in my routes.php file:
$route['default_controller'] = "homepage";
$route['404_override'] = "homepage/not_found";
$route['^products$'] = "product/list";
$route['^product/(:any)$'] = "product/details";
My urls will look like this:
product list => http://www.mywebsite.com/products
product details => http://www.mywebsite.com/product/my-custom-product
In the controller where I build the products list, I create the url for each product like this:
$this->db->from('products');
$products_result = $this->db->get();
$data['products'] = array();
foreach ($products_result->result() as $row)
{
$data['products'][] = array(
'title' => $row->title,
'image' => $row->image,
'url' => site_url('product/' . $row->url)
);
}
$this->load->view('products/list_view', $data);
But there is too much redundancy for each url. I have to write the url every time I want to echo it somewhere. If I want to change the url, I have to open each php file and replace them all.
Question: Isn't there a "method" I can use to call the controller name and its method and that "method" returns the url for that one? Something like this:
build_site_url('product/details', array('my-product-url'));
where the first argument is the controller and its method (since only one controller exists for a url pattern), and the second argument is the array of url parts.
What you're looking for is a feature called reverse routing. There is no such feature built into CodeIgniter at this time, and any library I could find was done in like 2010, so probably not the most up-to-date.
However, there are articles and pull requests out there relating to reverse routing, so if you are experienced enough, you should be able to put something together for your application.
Otherwise, your best bet may be to create helpers for your most common URLs (like your products). So you could do something like echo product_url('my-product-name');, and you would only need to adjust the URL in the helper function.
I am not sure what exactly that you desired, but you can override controller behaviour using _remap() function;
look: http://ellislab.com/codeigniter/user-guide/general/controllers.html#remapping
e.g.
public function _remap($method){
if ($method == 'product/details') {
///do what you want to do
}
You could either use a default lookup function in the product controller (described in the CI Routing docs; look at the examples).
$route['product/(:any)'] = "catalog/product_lookup";
A URL with "product" as the first segment, and anything in the second
will be remapped to the "catalog" class and the "product_lookup"
method.
Or you could use database driven routes.
Add the table product_slugs to your MySQL database:
CREATE TABLE IF NOT EXISTS `product_slugs` (
`id` bigint(20) NOT NULL auto_increment,
`slug` varchar(192) collate utf8_unicode_ci NOT NULL
PRIMARY KEY (`id`),
KEY `slug` (`slug`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1;
Replace the code in application/config/routes.php with the one below:
$route[ 'default_controller' ] = 'main';
$route[ '404_override' ] = 'error404';
require_once( BASEPATH .'database/DB'. EXT );
$db =& DB();
$query = $db->get( 'product_slugs' );
$result = $query->result();
foreach( $result as $row )
{
$route[ $row->slug ] = 'product/detail/$1;
}
All you would have to do then is to create a record when you create a product entry and you're done:
INSERT INTO `product_slugs` (`slug`) VALUES ('name-of-the-product');
I edited the 'comment' table in my Drupal MySQL database to add two rows. This is because I have a page that takes in a URL parameter, so while there is one page, I need to distinguish between the values of that parameter for comments. I'm having trouble editing my comment.module to edit the MySQL query. I can't find any kind of 'INSERT into...' query anywhere, not just in that file. I've looked through everything in the comment module folder.
What appears to be what affects the database insertion is the comment_publish_action() function in comment.module but I'm still running into some problems regarding the added columns, as they don't have default values.
Here's that function, 'typenode' and 'idofnode' are the added columns with test values:
function comment_publish_action($comment, $context = array()) {
if (isset($comment->subject)) {
$subject = $comment->subject;
$comment->status = COMMENT_PUBLISHED;
}
else {
$cid = $context['cid'];
$subject = db_query('SELECT subject FROM {comment} WHERE cid = :cid', array(':cid' => $cid))->fetchField();
db_update('comment')
->fields(array(
'status' => COMMENT_PUBLISHED,
'typenode' => 'player',
'idofnode' => 1239
))
->condition('cid', $cid)
->execute();
}
watchdog('action', 'Published comment %subject.', array('%subject' => $subject));
}
Edit comment.module is not good idea. During next core updates all changes will be lost. Better to create a custom module and implement some hooks there.
There is function comment_save($comment) which perform steps to insert / update new comment. In this function you can find a line drupal_write_record('comment', $comment); which do insert or update of db table 'comment' (dependence on logic). But before this line there is hook module_invoke_all('comment_presave', $comment); which allows you to modify $comment object before it will be store in database. This is good way to go - implement this hook in custom module and do modifications there.
function custom_module_comment_presave($comment) {
//add rows info here
}
I'm new to plugin and WP development, so I need some help.
What I'm trying to do is plugin that would use/reuse certain images from media folder and display them in side widget, per certain page, in a way that I like, or using shortcodes within certain page. (so should work on both posts\pages and sidebar widgets).
It should be used multiple times, on many many pages.
What I've decided to do is create my own table in WP database, even though I've read here on post that it is maybe not needed: WordPress plugin development using OOP
I struggle on several fields. First I had problems to find decent explanation how to create widget that can be used multiple times. OK, I have resolved this using:
class FeatDispWidget extends WP_Widget {...}
examples, and it realy works, I can have multiple instances and data is saved do wp_options.
Now, I'm trying to use $wpdb. And from all possible examples i see I have to use global $wpdb or include some php files, or extend wpdb with my own DB class, but what is the best / correct way in OOP approach ?
this is part of my code, constructor and try to call db function that gives me errors all the time.
class FeatDispWidget extends WP_Widget {
private $featdisplayer_table;
$featdisplayer_table = $wpdb->prefix . 'featdisplayer';
/**
* Widget setup.
*/
function FeatDispWidget() {
/* Widget settings. */
$widget_ops = array( 'classname' => 'featdisp', 'description' => __('Sexy Feature Displayer.', 'featdisp') );
/* Widget control settings. */
$control_ops = array( 'width' => 300, 'height' => 350, 'id_base' => 'featdisp-widget' );
/* Create the widget. */
$this->WP_Widget( 'featdisp-widget', __('Feature Displayer Widget', 'featdisp'), $widget_ops, $control_ops );
}
function featDispDBsetup (){
global $wpdb;
global $featdisplayer_table;
if ( $wpdb->get_var( "show tables like '$featdisplayer_table'" ) != $featdisplayer_table ) {
$sql = "CREATE TABLE $featdisplayer_table (".
"sandf_id INT NOT NULL AUTO_INCREMENT, ".
"type VARCHAR( 30 ) NOT NULL, ".
"attachid INT NOT NULL, ".
"setid INT NOT NULL, ".
"imgpath LONGTEXT NOT NULL, ".
"title LONGTEXT NOT NULL, ".
"desc LONGTEXT, ".
"linkto LONGTEXT, ".
"altertext LONGTEXT, ".
"txtnxttoimg LONGTEXT, ".
"sortorder INT, ".
")";
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
dbDelta( $sql );
}
}
So my questions:
1) can I extend WP_widget, as I do, and display it on both pages and sidebar ?
2) do I need to extend WP_widget in order to have widget instantiated several times (once on each page)
3) If I extend WP_widget, where do I put $wpdb in order to create table in wp database
So, this is it for now, I think I took something to complex for my first widget, but I'm not giving up! :)
$wpdb is just the name of the global instance of Wordpress' database wrapper. Your best bet might be to set your table name in your constructor and include a reference to the global database object as a class parameter, e.g.:
class FeatDispWidget extends WP_Widget {
private
$featdisplayer_table,
$wpdb;
public function __construct() {
global $wpdb;
$this->wpdb = &$wpdb;
$this->featdisplayer_table = $this->wpdb->prefix . 'featdisplayer';
}
// .. the rest of your widget goes here
}
You can then go on referring to $this->wpdb in your other class methods.
As for your other questions, you can add additional "widget-ready" regions to your site's theme by using the register_sidebar and dynamic_sidebar functions. Widgets sub-classed from WP_Widget can be re-used on multiple sidebars without additional modifications. If you want to use it on specific pages (i.e., attached to post content), however, a widget really isn't the right solution.
How would one go about deleting all option names in a WordPress database beginning with a specific prefix?
I would assume we need to specify a prefix, get all options that begin with that prefix, and then delete each option found.
Here is a sample of the prefix and WP functions for getting and deleting options in the database.
<?php
$prefix = 'cpt_';
$getOpt = get_option($prefix);
foreach($getOpt as $toDelete){
$deleteOpt = delete_option($prefix);
if(!$deleteOpt){
echo 'Failure.';
}
if($deleteOpt){
echo 'Success.';
}
}
?>
Resources:
http://codex.wordpress.org/Function_Reference/delete_option
http://codex.wordpress.org/Function_Reference/get_option
You could run this query:
global $wpdb;
$wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE 'cpt_%'" );
or put it in a function like so:
function delete_options_prefixed( $prefix ) {
global $wpdb;
$wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '{$prefix}%'" );
}
delete_options_prefixed( 'cpt_' );
You need to make a "whitelist" of all the variables your plugin sets (I assume you are looking at a plugin uninstall script), then just loop through it at the other end so you can delete them all.
Something as simple as:
// Somewhere in your plugin, maybe as a class property
$pluginDefinedOptions = array('my_name', 'my_created', 'my_modified'); // etc
// Clear up our settings
foreach($pluginDefinedOptions as $optionName) {
delete_option($optionName);
}
This is the only way to keep your plugin code tidy.