I would like to get a list of ALL Wordpress plugins.
There is a function called get_plugins() but it will return all plugins that I have installed. What I need is a list of all plugins, no matter if I installed them before or not.
Is there a function that I could use? If not, is there a JSON, database, API or anything that I could use?
Edit:
var_dump(plugins_api('query_plugins', array(
'per_page' => 100,
'tag' => 'contact form 7',
'number' => 5,
'page' => 1,
'fields' =>
array(
'short_description' => false,
'description' => false,
'sections' => false,
'tested' => false,
'requires' => false,
'rating' => false,
'ratings' => false,
'downloaded' => false,
'downloadlink' => false,
'last_updated' => false,
'added' => false,
'tags' => false,
'compatibility' => false,
'homepage' => false,
'versions' => false,
'donate_link' => false,
'reviews' => false,
'banners' => false,
'icons' => false,
'active_installs' => false,
'group' => false,
'contributors' => false
))));
This returns a full of data that I don't need:
The only data that I need are the yellow marked keys below: name and slug
I know that I could get them out from the array but it would be very bad for the performance.
Even when I try it with a loop, I'll get 45 plugins but not more. Where is the rest???
foreach ($plugins as $plugin) { // $plugins is the variable of my code above but without 'tag' => 'contact form 7',
foreach ($plugin as $p) {
if ($p != null) {
echo $p->name . "<br>";
}
}
}
Not the best answer but I tried to solve my own problem the best way I could.
Getting a list of plugins
This will not return ALL plugins but it will return the top rated ones:
$plugins = plugins_api('query_plugins', array(
'per_page' => 100,
'browse' => 'top-rated',
'fields' =>
array(
'short_description' => false,
'description' => false,
'sections' => false,
'tested' => false,
'requires' => false,
'rating' => false,
'ratings' => false,
'downloaded' => false,
'downloadlink' => false,
'last_updated' => false,
'added' => false,
'tags' => false,
'compatibility' => false,
'homepage' => false,
'versions' => false,
'donate_link' => false,
'reviews' => false,
'banners' => false,
'icons' => false,
'active_installs' => false,
'group' => false,
'contributors' => false
)));
Save the data as JSON
Since the data that we get is huge and it will be bad for performance, we try to get the name and the slug out of the array and then we write it in a JSON file:
$plugins_json = '{' . PHP_EOL;
// Get only the name and the slug
foreach ($plugins as $plugin) {
foreach ($plugin as $key => $p) {
if ($p->name != null) {
// Let's beautify the JSON
$plugins_json .= ' "'. $p->name . '": {' . PHP_EOL;
$plugins_json .= ' "slug": "' . $p->slug . '"' . PHP_EOL;
end($plugin);
$plugins_json .= ($key !== key($plugin)) ? ' },' . PHP_EOL : ' }' . PHP_EOL;
}
}
}
$plugins_json .= '}';
file_put_contents('plugins.json', $plugins_json);
Now we have a slim JSON file with only the data that we need.
To keep updating the JSON file, we run that script to create a JSON file every 24 hours by setting up a Cron Job.
Because getting all plugins at once will be too heavy for the server, it is a better idea to do it in steps.
You could do as many plugins at once as the server can handle. For the example I use a safe 100 plugins at once.
Everytime the script runs, it increments the "page" number with 1. So the next time the script runs the next 100 plugins are retrieved. The contents of the existing plugins.json will be parsed. The new plugins will be added (or overwritten if the plugin already is present) to the existing data, before encoding and saving it again.
If the page number is past the last, no results will be returned. This way the script knows there are no more plugins next. It then resets the page to 1, so it starts over.
I use the wp_options table to keep track of the pages, simply because it's the quickest way. It would be better to use some kind of filesystem caching. That will be easier to reset manually if needed.
You can set a cronjob to execute the script every x minutes. Now the plugins.json file will build up and grow step by step, every time it runs.
// get the current "page", or if the option not exists, set page to 1.
$page = get_option( 'plugins_page' ) ? (int)get_option( 'plugins_page' ) : 1;
// get the plugin objects
$plugins = plugins_api( 'query_plugins', [
'per_page' => 100,
'page' => $page,
'fields' => [
//.........
]
] );
// increment the page, or when no results, reset to 1.
update_option( 'plugins_page', count( $plugins ) > 0 ? ++ $page : 1 );
// build up the data array
$newData = [];
foreach ( $plugins as $plugin ) {
foreach ( $plugin as $key => $p ) {
if ( $p->name != null ) {
$newData[ $p->name ] = [ 'slug' => $p->slug ];
}
}
}
// get plugin data already in file.
// The last argument (true) is important. It makes json objects into
// associative arrays so they can be merged with array_merge.
$existingData = json_decode( file_get_contents( 'plugins.json' ), true );
// merge existing data with new data
$pluginData = array_merge( $existingData, $newData );
file_put_contents( 'plugins.json', json_encode( $pluginData ) );
Related
Hosted on Heroku
Yii 1.14
PHP 5.6
A stranger error when Yii::app()->user->id returns the id sometimes but at other times returns empty. The same page load results in this strange behaviour.
I check for this in a parent class called AdminController.php
class AdminController extends CController
{
public $partnerCount;
public $vendorCount;
public $plantationMarkers;
public function init()
{
echo Yii::app()->user->id;
if(empty(Yii::app()->user->id)) {
echo 'User id empty: '. Yii::app()->user->id;
//$this->redirect(Yii::app()->createAbsoluteUrl('admin/auth/login'));
exit;
return false;
}
elseif(!Yii::app()->user->checkAccess(User::PARTNER)) {
$this->layout = 'column1';
$this->render('/auth/not-authorized');
return false;
}
$this->partnerCount = $this->getPartnerCount();
$this->vendorCount = $this->getVendorCount();
$this->plantationMarkers = $this->getPlantationMarkers();
return true;
}
So in this code 'User id empty: ' is echoed in some cases while in other cases I get the id.
The point is with no change in code how can this work at some time while not at other times.
Solved by changing the session to be stored in DB table. I am not sure but there was some issue with Yii storing session on the server under Heroku.
The change is required in the config array under 'components'.
From :
'session' => array(
'class' => 'CHttpSession',
'timeout' => 2400,
'cookieParams' => array(
'httpOnly' => true,
'secure' => false,
),
),
To :
'session' => array(
'timeout' => 2400,
'cookieParams' => array(
'httpOnly' => true,
'secure' => false,
),
'class' => 'CDbHttpSession',
'connectionID' => 'db',
'sessionTableName' => 'lig_session',
),
Following this question I gather that upsert: false and multi: true fields need to be set for this to work.
However, when I try to code this in PHP, I have a problem:
$conn = new Mongo("mongodb://foo:bar#localhost:27017");
$db = $conn->selectDB("someDB");
$data = array('$rename' => array(
'nmae' => 'name'
));
$db->command(array(
'findAndModify' => 'foo',
'update' => $data,
'upsert' => 'false',
'multi' => 'true'
));
After running this script, only the first document with the nmae typo is changed to name; the rest still say nmae. The same as if I had run it without the upsert and multi options.
I also tried this:
$data = array('$rename' => array(
'nmae' => 'name'
),
'upsert' => 'false',
'multi' => 'true'
);
$db->command(array(
'findAndModify' => 'foo',
'update' => $data
));
But that does the same thing.
Any way to get this working?
The findAndModify query doesn't have a "multi" option:
http://www.php.net/manual/en/mongocollection.findandmodify.php
What you probably want to use is update instead:
http://www.php.net/manual/en/mongocollection.update.php
I have to modify a Zend form where some of the fields can contain decimals. Currently you can only enter your decimals using a point: 34.75)
What I'd like the users to be able is to write their decimals both with a comma or a point. The fields can contain either numbers like 34.75 and 34,75 (In this case, both have the same value). I don't want to modify any configuration on the server, so I need to do this in the code.
Right now the value of some fields is calculated in function of other fields; so when you enter a comma, it messes up the calculations. It's done in javascript, and I'll need to fix those calculations - but for now, I want to fix this issue in the php code when I retrieve the form.
I tried to find a solution on the Zend website, but I didn't find anything I've already read elsewhere with more examples. As you'll see in the code, I need to add either a filter or a validator to a zend_form_element_text. I cannot use a str_replace, as the element is a zend_form_element_text.
I have found this other question for reference.
Here is my resulting code:
$tabBilanFrais = array( 'txtFraisSecretariat' => array( 'nom' => 'Frais secrétariat', 'disabled' => true, "class"=>"calcul"),
'txtFraisRegion' => array( 'nom' => 'Frais région', 'disabled' => false),
'txtFraisSalle' => array( 'nom' => 'Salle', 'disabled' => false, "class"=>"calcul"),
'txtFraisPause' => array( 'nom' => 'Pauses', 'disabled' => false, "class"=>"calcul"),
'txtDivers' => array( 'nom' => 'Divers', 'disabled' => false, "class"=>"calcul"),
'txtTotalRegion' => array( 'nom' => 'Total région', 'disabled' => true, "class"=>"total"),
'txtIndemnisationAdherent' => array( 'nom' => 'Comm. ADH', 'disabled' => true, "class"=>"calcul"),
'txtIndemnisationPAP' => array( 'nom' => 'Comm. PAP', 'disabled' => true, "class"=>"calcul"),
'txtIndemnisationForNext' => array( 'nom' => 'Comm. ForNext', 'disabled' => true, "class"=>"calcul"),
'txtIndemnisationPROStages' => array( 'nom' => 'Comm. PROStages', 'disabled' => true, "class"=>"calcul"),
'txtRecettes' => array( 'nom' => 'Recettes', 'disabled' => true, "class"=>"totalMontant"),
'txtDepenses' => array( 'nom' => 'Dépenses', 'disabled' => true, "class"=>"totalMontant"),
'txtRecettesH' => array( 'nom' => 'Recettes', 'disabled' => false, "class"=>"hiddenTxt"),
'txtDepensesH' => array( 'nom' => 'Dépenses', 'disabled' => false, "class"=>"hiddenTxt")
);
$tabFormulaire = array() ;
foreach($tabBilanFrais as $id => $tabElement)
{
if($tabElement['nom'] == 'Frais region' )
$element = new Zend_Form_Element_Hidden($id, array("label" => $tabElement['nom'], "required" => false, 'decorators' => array("ViewHelper", "Errors", "Label"))) ;
else{
$element = new Zend_Form_Element_Text($id, array("label" => $tabElement['nom'], "required" => false, 'decorators' => array("ViewHelper", "Errors", "Label"))) ;
//$element->addFilter('pregReplace', array('match' => '/,/', 'replace' => '.'));
$element->addFilter('LocalizedToNormalized');
$element->addValidator('float', true, array('locale' => 'fr_FR'));
if(isset($tabElement['class']) && $tabElement['class']){
$element->setAttrib('class', $tabElement['class']);
}
}
if( $tabElement['disabled'])
$element->setAttrib('disabled', 'disabled');
$tabFormulaire[] = $element ;
}
The pregReplace isn't working. The validator is (comma becomes a .). I get an error message about the number not being a float.
You can always write your own validator. In case of float I faced the same problem like you:
class Yourlib_Validate_Float extends Zend_Validate_Abstract
{
const INVALID = 'floatInvalid';
const NOT_FLOAT = 'notFloat';
/**
* #var array
*/
protected $_messageTemplates = array(
self::INVALID => "Invalid type given. String, integer or float expected",
self::NOT_FLOAT => "'%value%' does not appear to be a float",
);
public function isValid($value)
{
$this->_setValue($value);
$value = str_replace(',', '.', $value);
if (!is_string($value) && !is_int($value) && !is_numeric($value)) {
$this->_error(self::INVALID);
return false;
}
if (is_numeric($value)) {
return true;
}
$this->_error(self::NOT_FLOAT);
return false;
}
}
And to add the validator:
$element->addValidator(new Yourlib_Validate_Float());
Please rename Yourlib to whatever suits you. And you need to register your "namespace" in the application.ini like this:
autoloadernamespaces.Yourlib = "Yourlib_"
Strictly speaking this validator is a numeric validator. It accepts all numeric values like ints and floats thru the check with is_numeric. Feel free to modify that.
Alright, here is the modified part of the code:
foreach($tabBilanFrais as $id => $tabElement)
{
if($tabElement['nom'] == 'Frais region' )
$element = new Zend_Form_Element_Hidden($id, array("label" => $tabElement['nom'], "required" => false, 'decorators' => array("ViewHelper", "Errors", "Label"))) ;
else{
$element = new Zend_Form_Element_Text($id, array("label" => $tabElement['nom'], "required" => false, 'decorators' => array("ViewHelper", "Errors", "Label"))) ;
$element->addFilter('pregReplace', array('match' => '/,/', 'replace' => '.'));
$element->addFilter('LocalizedToNormalized');
$element->addValidator(new Anper_Validate_Float(), true, array('locale' => 'fr_FR'));
if(isset($tabElement['class']) && $tabElement['class']){
$element->setAttrib('class', $tabElement['class']);
}
}
if( $tabElement['disabled'])
$element->setAttrib('disabled', 'disabled');
$tabFormulaire[] = $element ;
}
But now I need the values of the fields in $element to have the comma replaced by a point before the element is added to $tabFormulaire. Currently numbers with a comma are truncated (124,5 becomes 124) when I validate the form and display the updated values.
The pregreplace doesn't seem to work.
Edit: it seems I don't need the pregReplace. I used two echo in my isValid function for the custom validator: one before the str_replace and one after. When I write in one of the field a value with a comma, both the echo displays the number with a point. I assume it's the result of the filter LocalizedToNormalized.
What I don't understand is why once the values are saved and displayed those with a comma are truncated despite the findings I just made.
Edit2: If I write for example 124 8, and use a pregReplace to do like there was no blank, the 8 isn't kept on save; despite the pregReplace working (tried with my previous echo).
Although #bitWorking's answer is 100% OK, from the view point of semantics, it's better to use a filter (since it's more of filtering rather than validating)
either NumberFormat filter or writing your own.
How can I use PHP closure function like function() use() on PHP 5.2 version as it has no support for anonymous functions?
Currently my code is something like below
$this->init(function() use($taxonomy_name, $plural, $post_type_name, $options)
{
// Override defaults with user provided options
$options = array_merge(
array(
"hierarchical" => false,
"label" => $taxonomy_name,
"singular_label" => $plural,
"show_ui" => true,
"query_var" => true,
"rewrite" => array("slug" => strtolower($taxonomy_name))
), $options
);
// name of taxonomy, associated post type, options
register_taxonomy(strtolower($taxonomy_name), $post_type_name, $options);
});
Php supports anonymous functions since 5.3.0, read about it in manual.
You could use create_function but you should avoid this (for example because of this comment) and it's practically the same as eval... One bad enclosure and you'll make your sources vulnerable. It's also evaluted on runtime, not on compilation time what can decrease performance and may cause fatal error in the middle of included file.
Rather declare that function somewhere, it'll be more effective.
I assume you are asking for the 'use' directive due to the early value bindings, right?
You could use 'create function' and insert there some static variables with the values you have at the creation time, for example
$code = '
static $taxonomy_name = "'.$taxonomy_name.'";
static $plural = "'.$plural.'";
static $post_type_name = "'.$post_type_name.'";
static $options = json_decode("'.json_encode($options).'");
$options = array_merge(
array(
"hierarchical" => false,
"label" => $taxonomy_name,
"singular_label" => $plural,
"show_ui" => true,
"query_var" => true,
"rewrite" => array("slug" => strtolower($taxonomy_name))
),
$options
);
// name of taxonomy, associated post type, options
register_taxonomy(strtolower($taxonomy_name), $post_type_name, $options);
';
$func = create_function('', $code);
Something like that should do:
$this->init(create_function('','
$taxonomy_name = '.var_export($taxonomy_name,TRUE).';
$plural = '.var_export($plural,TRUE).';
$post_type_name = '.var_export($post_type_name,TRUE).';
$options = '.var_export($options,TRUE).';
$options = array_merge(
array(
"hierarchical" => false,
"label" => $taxonomy_name,
"singular_label" => $plural,
"show_ui" => true,
"query_var" => true,
"rewrite" => array("slug" => strtolower($taxonomy_name))
), $options
);
// name of taxonomy, associated post type, options
register_taxonomy(strtolower($taxonomy_name), $post_type_name, $options);
'));
I need to create field that as option gets regex string.
So, i made PatternType field:
public function getDefaultOptions(array $options)
{
$defaultOptions = array(
'data' => null,
'data_class' => null,
'trim' => true,
'required' => true,
'read_only' => false,
'max_length' => null,
'pattern' => null,
'property_path' => null,
'by_reference' => true,
'error_bubbling' => false,
'regexp' => false,
'error_mapping' => array(),
'label' => null,
'attr' => array(),
'invalid_message' => 'This value is not valid',
'invalid_message_parameters' => array()
);
$class = isset($options['data_class']) ? $options['data_class'] : null;
// If no data class is set explicitly and an object is passed as data,
// use the class of that object as data class
if (!$class && isset($options['data']) && is_object($options['data'])) {
$defaultOptions['data_class'] = $class = get_class($options['data']);
}
if ($class) {
$defaultOptions['empty_data'] = function () use ($class) {
return new $class();
};
} else {
$defaultOptions['empty_data'] = '';
}
$patt = $options['regexp'];
unset($options['regexp']);
$defaultOptions['validation_constraint'] = new Regex(
array(
'pattern' => $patt,
'match' => true,
'message' => 'Niewłaściwy format'
)
);
var_dump($defaultOptions);
return $defaultOptions;
}
var_dump returns well formatted settings array, with regex object within - but when form is generated validation doesn't work - pass any value. Any idea why?
Why are you doing this? There is a regex validator already. Just use a normal text field with that validator.
In case you need a form without a model class to bind to, read the corresponding section.
Ok, I found what was wrong - you can only add validator constant to root form object (others symfony simply ignore). So it seems that what I need is simply get root form, add there validator_constant with validator_group option set. Then just assign field proper validator_group.