Create a Widget system like WordPress without any framework - php

I have searched for this topic here and Google but I only found the solutions with PHP frameworks (for example, YII and Laravel)
I am developing a simple CMS and I would like to add widget system just like WordPress ( Recent Comments, Categories widgets )
List available widgets.
Users can active the widgets and use them in sidebar.
My steps:
1. First at all, I already made an admin tool as the screenshot blow ( jQuery UI sortable works fine)
Here is my php code:
$available_widgets = array(
0 => array(
'id' => 'recent-post',
'title' => 'Latest Pots',
'option' => array( 'display_count' => 5, 'multi_widget' => 0)
),
1 => array(
'id' => 'recent-comment',
'title' => 'Recent Commets',
'option' => array( 'display_count' => 5, 'multi_widget' => 0)
),
2 => array(
'id' => 'text-box',
'title' => 'Text Box',
'option' => array('multi_widget' => 1)
)
);
View
foreach ( $available_widgets AS $available_widget ) {
if ( $available_widget['option']['multi_widget'] == 0 ) {
echo '<li class="widget-box widget-single" data-widget-id="' . $available_widget['id'] . '" ><div class="widget-handle">' . $available_widget['title'] . '</div></li>';
}
else {
echo '<li class="widget-box widget-multiple" data-widget-id="' . $available_widget['id'] . '" ><div class="widget-handle">' . $available_widget['title'] . '</div></li>';
}
}
But I still no idea about the next step, any idea will be grateful.
Thanks.
Update:
For my step 2 I made a simple EventDispatcher, I put the link here if someone else needs it.
https://github.com/terrylinooo/PHP-EventDispatcher

You may be underestimating the complexity of this question. If you are doing this from scratch, there will be several things to consider.
Are you creating all your widgets, and then just want the user to be able to pick and choose which ones they want visible?
If so, roughly I would probably:
Obviously make html sidebar that will house the widgets, styled by your css. Have the width of column set to 0 if no widgets are published.
And of course make all your widgets in separate files probably in their own folder.
Have database table with at very least path to widget file, "published" boolean column, and "widget_order" column.
Choose where in the admin area the user will choose which ones to show, and have it change the "published" column in the table, and maybe also a small text box or dropdown where they can specify the order number.
Then on the front end, just do a database lookup in the sidebar, if the number of rows from the module table that are "published" is greater than 0, then 'echo' out a css value that will give your column the correct width (of your choice) instead of 0 width keeping it hidden otherwise if none are enabled.
The database look up should have the ORDER BY clause to follow the 'widget_order' values. This obviously is how the widgets get displayed in order by the users preference.
Now each widgets functionality is all in each file, so put any relevant php, Javascript etc, in each one which will make them easy to develop and modify. Obviously you can refactor after where feasible.
Hope this gives you an idea of what you're getting in to lol..

Take a look at Observer Pattern
or Event Dispatcher Pattern for plugin system
When installing plugins, don't forget to save it to the database
And, to list available widgets, you just need to query the database which plugins are available or activated.

Related

Changing CSS by checking a checkbox - Redux Framework

I'm building a theme options system to my theme using the Redux framework.
I want to append a css property (background-image) when the user press specific button in a "Button Set" field.
The code:
array(
'id' => 'opt_change_menu_button',
'type' => 'button_set',
'title' => __('Change Menu Button', 'faster'),
'options' => array(
'yes' => __('Yes', 'faster'),
'no' => __('No', 'faster'),
),
'defualt' => 'no',
),
When the user press YES, I want, in addition to what already happen (some other options appear in the bottom), to append a CSS property in the front end ( background-image: none), that overwrites the other properties which relate to the chosen selector.
In some other fields it is possible using the "output" value, but in that case I didn't fiend it possible, after hours of struggling.
Thanks in advance!
Lead dev of Redux here. You'll have to append your own JavaScript for in-panel changes via JS. Luckily, it's quite easy. https://docs.reduxframework.com/core/advanced/custom-panel-css/

TYPO3 TCA, hide tab in translated item

In my Extension I create several tabs for the backend with --div--, the code looks something like this:
'types' => array(
'0' => array('showitem' => 'sys_language_uid;;;;1-1-1, l10n_parent, l10n_diffsource, hidden;;1,--div--;My Tab, title, category,
),
While there is an easy way to hide a single field in the translated item with: 'displayCond' => 'FIELD:sys_language_uid:=:0',, I have no idea how to hide a whole tab.
Does anybody know how I have to write the 'types' array to hide "My Tab" in the translation records? Thank you in advance.
Edit (Solution):
Using config as stated in the answer is possible, but there is another way I discovered by accident: If you hide all fields that are associated with a tab with 'displayCond' => 'FIELD:sys_language_uid:=:0', the tabs will also be hidden.
I think you may need to use tsconfig.
Please check the section: "New content element wizard (mod.wizards.newContentElement)" in this link: http://typo3.org/documentation/document-library/core-documentation/doc_core_tsconfig/4.3.2/view/1/5/

Drupal node 2-page content split

My employer requires certain pages on the website have a two page feature.
What this means is that some default content show up on the node_view page as normal but the second part should show up when a link is clicked.
This will be easy if I could do this across multiple nodes but the requirement is for all the data to be stored in one node but displayed across two pages.
I hacked together the following code:
function mymodule_node_view($node, $view_mode, $langcode){
$path = current_path();
$path_alias = drupal_lookup_path('alias',$path);
$links = array( 'test' => array('title'=>'my_link', 'query'=>'', 'href'=>"{$path_alias}/nextpage") );
$node->content['my_module'] = array(
'#theme' => 'links__node__mymodule',
'#links' => $links,
'#attributes' => array('class' => array('links', 'inline')),
);
}
That creates a hyperlink called my_link across the top of my content area - which is great.
The problem starts when I click the hyperlink. Supposing I am on http://example.org/homepage and I click the hyperlink, I expect to be redirected to http://example.org/homepage/nextpage. Also, I still want to maintain the view and edit tabs of the actual node I was on. However, Drupal correctly gives me a "page not found" error.
What's interesting is if I used http://example.org/node/1 and visited http://example.org/node/1/nextpage, I don't get the issues I described above but the url is less descriptive.
To solve this problem, I am sure I have to extend hook_menu but I don't know how to account for any number of taxonomy terms leading up to the actual node title. So, I can't predict how many % I will need before the node title and then my /nextpage. However, I want /nextpage to still have the view and edit tabs of it's parent page.
This is all unexplored territory for me.
Update
I found the following function which does a great job of returning the entire node path complete with taxonomies:
$path = current_path();
$path_alias = drupal_lookup_path('alias',$path);
What I don't know is how to take advantage of this in hook_menu to dynamically create /nextpage for my nodes.
Please remember, I don't really want /nextpage to be entirely independent of the original and actual Drupal node. When on /nextpage I want to be able to have access to the view, edit etc tabs of the node.
So, /nextpage effectively is just an extension of a Drupal node page.
There is a quick way to do that. Using views module.
In the fields section choose the field you wanna view. And in the arguments add the nid.
Then add the link to the node view you already created.
The final result http://mysite/views-page/[nid]
Hope this helps... Muhammad.
I would check the node_menu() function to get some reference on how it's implemented.
Not sure on your taxonomy requirements so this might be insufficient but I'll go with what I understand.
But off the top of my head I'd go for something like:
function mymodule_menu() {
$items['node/%node/nextpage'] = array(
'title' => 'Next page',
'type' => MENU_LOCAL_TASK, // Makes it a tab on node/%node-pages
'page callback' => 'mymodule_node_page_view', // Your page display function
'page arguments' => array(1), // First will be a node object, second will be whatever value is passed in the url
// You should rip access callback and access arguments from node_menu()
);
return $items;
}
That should do something like what you are asking for.
It is also possible, easier and definitely recommended to do this with Panels/Pages (see also Chaos Tools) or arguably Views as they are quite capable of all this and generally a better way to work with Drupal's strengths than custom code.
Updated
To clarify I've simplified the menu hook and you should be able to use the below page view function. I still believe you would make a better solution using Panels and overriding node_view and such.
The MENU_LOCAL_TASK part in the menu hook should turn this into another tab along with View and Edit.
function mymodule_node_page_view($node) {
die("It works: ".$node->title);
}
Hope that's more helpful.

The pagination `before` and `complete` options not working properly

I want to display a loading image when I click on a sorting link of a listing record. Before, I used the complete property of Paginator. This works well if the table has more than one record.
My code is as follows:
<?php
$this->Paginator->options(array(
'update' => '#ourCompany-part',
'evalScripts' => true,
'before' => $this->Js->get('#loading')->
effect('fadeIn', array('buffer' => false)),
'complete' => $this->Js->get('#loading')->
effect('fadeOut', array('buffer' => false)),
));
?>
When the table has one record and we click on the sorting link of the paginator, it doesn't display the loading image. If the table has no records, then the index page is not loaded. How could I solve this?
Personally i don't like JsHelper i wrote jquery pugins or small function in my view. So check that the javascript looks like where you see 1 record or no record, it seems that helper not render javascitpt.

Programmatically creating a CMS/Page in Magento

I saw the following answer to the post Where are Magento static CMS blocks stored? regarding programatically using PHP generating cms/blocks in Magento.
I changed the code to the following
$newBlock = Mage::getModel('cms/page')
->setTitle('Test CMS Page Title')
->setContent('Hello I\'m a new cms page.')
->setIdentifier('this-is-the-page-url')
->setIsActive(true)
->save();
... and it works. I see a new page show up in the CMS Pages area in the backend.
What I need to add to this is the ability to set the content of the other fields in the CMS/Page. Namely:
Layout (trying to set to 1 column)
meta keyword
meta description
fields. These fields are blank currently. I so far haven't been able to figure this part out.
Thanks,
here you go:
$cmsPageData = array(
'title' => 'Test CMS Page Title',
'root_template' => 'one_column',
'meta_keywords' => 'meta,keywords',
'meta_description' => 'meta description',
'identifier' => 'this-is-the-page-url',
'content_heading' => 'content heading',
'stores' => array(0),//available for all store views
'content' => "Hello I'm a new cms page."
);
Mage::getModel('cms/page')->setData($cmsPageData)->save();
The keys of the array are the name of the fields of the cms_page table (check the db). And to know the value, I manually create the cms page I want and then see the value for this entry in the db.

Categories