Cant create table on plugin activation - php

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);
}
);

Related

database driven codeigniter navbar

I am new with CodeIgniter and have been told that it is the way to go.
I have read the user manual a few times now but don't seem to understand one thing which is I wanted to do a navbar driven from the database. I found a few posts on here saying about a method that I have implemented but no matter what I do, it just doesn't seem to work for me. what I have done so far:
Created a table with :
CREATE TABLE IF NOT EXISTS `app_routes` (
`id` bigint(20) NOT NULL auto_increment,
`slug` varchar(192) collate utf8_unicode_ci NOT NULL,
`controller` varchar(64) collate utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `slug` (`slug`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1;
Added to route.php file
$route[ 'default_controller' ] = 'home';
$route[ '404_override' ] = 'error404';
require_once( BASEPATH .'database/DB'. EXT );
$db =& DB();
$query = $db->get( 'app_routes' );
$result = $query->result();
foreach( $result as $row )
{
$route[ $row->slug ] = $row->controller;
$route[ $row->slug.'/:any' ] = $row->controller;
$route[ $row->controller ] = 'error404';
$route[ $row->controller.'/:any' ] = 'error404';
}
Set up a controller with:
<?php
class Home extends CI_Controller {
public function index()
{
$this->load->view('smooth/header.php');
$this->load->view('smooth/navbar.php');
$this->load->view('smooth/index.php');
$this->load->view('smooth/footer.php');
}
}
?>
In the database I have under controller home and as page contact
When I visit my site via my domain name only I see the frontpage but if I add the index.php/home to it I get nothing or index.php/home/contact nothing either
The path to my index.php files as situated in my domain/application/views/themes/smooth/index.php
Can anyone help with what I am missing please or what the problem is?
You didn't pass the routes to the view.
Without seeing the view in question I can't tell if there's an issue there, but you need to pass the data through like this:
$this->load->model('yourmodel');
$routes = $this->yourmodel->getRoutes();
$data = array(
'routes' => $routes
);
$this->load->view('smooth/header.php');
The database query goes in a model, so you will need to define that, and a method to return the data - here I've represented that model as yourmodel and the method to call as getRoutes. You should not, under any circumstances, be placing your database query in routes.php.

Load url from routes for a controller

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');

Where to put $wpdb with OOP plugin / widget using and WP_widget extension

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.

WP Custom plugin: Create table and insert data once.

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);

Why won't my global variables properly resolve?

here is my plugin activation code
$classified_category_name = 'classified';
$credit_table_name = 'credits';
$credit_table_version = 0.1;
register_activation_hook(__FILE__, 'LBH_Classifieds_Activate');
function LBH_Classifieds_Activate()
{
global $wpdb;
global $classified_category_name;
global $credit_table_name;
global $credit_table_version;
$table_name = $wpdb->prefix . $credit_table_name;
if($wpdb->get_var("SHOW TABLES LIKE '$table_name'") != $table_name) {
$sql = "CREATE TABLE " . $table_name . " (
time bigint(11) DEFAULT 0 NOT NULL,
amount tinyint(3) DEFAULT 0 NOT NULL,
username varchar(50) NOT NULL,
UNIQUE KEY username (username)
);";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
add_option('lbh_db_version', $credit_table_version);
}
but the global variables are empty.
Also, is there any way to print any information from within a plugin? I've tried returning a WP_Error, throwing a WP_Error, and all I can ever get is a big yellow box, mostly empty, with "Plugin could not be activated because it triggered a fatal error."
When activation occurs, your plugin is included from another function and then your myplugin_activate() is called from within that function (specifically, within the activate_plugin() function) at the point where your plugin is activated. The main body variables are therefore in the scope of the activate_plugin() function and are not global, unless you explicitly declare their global scope
See the rest of this note on variable scope: http://codex.wordpress.org/Function_Reference/register_activation_hook#A_Note_on_Variable_Scope

Categories