I'm new to use jqGrid and there is a problem when I try to use the inline edit feature. Here is my code:
My First Grid
<link rel="stylesheet" type="text/css" media="screen" href="css/ui-lightness/jquery-ui-1.8.16.custom.css" />
<link rel="stylesheet" type="text/css" media="screen" href="css/ui.jqgrid.css" />
<style type="text/css">
html, body {
margin: 0;
padding: 0;
font-size: 75%;
}
</style>
<script src="js/jquery-1.5.2.min.js" type="text/javascript"></script>
<script src="js/i18n/grid.locale-en.js" type="text/javascript"></script>
<script src="js/jquery.jqGrid.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
var lastsel2
$("#list").jqGrid({
url:'example.php',
datatype: 'xml',
mtype: 'GET',
colNames:['id','name', 'status'],
colModel :[
{name:'id', index:'id', width:55},
{name:'name', index:'name', width:90, editable: true},
{name:'status', index:'status', width:80, align:'right', editable: true},
],
onSelectRow: function(id){
if(appid && appid!==lastsel2){
jQuery('#list').restoreRow(lastsel2);
jQuery('#list').editRow(id,true);
lastsel2=id;
}
},
editurl: "example.php",
pager: '#pager',
rowNum:10,
rowList:[10,20,30],
sortname: 'appid',
sortorder: 'desc',
viewrecords: true,
gridview: true,
caption: 'My first grid'
});
});
</script>
</head>
<body>
<table id="list"><tr><td/></tr></table>
<div id="pager"></div>
</body>
The problem is it could edit the row when I click it, and also can save temporarily after I press the enter. But when I reload the grid, it still shows the previous data before I eidt, which means it doesn't update the database. I wonder why and how to solve it?
Here is the example.php code:
<?php
include("dbconfig.php");
$page = $_GET['page'];
$limit = $_GET['rows'];
$sidx = $_GET['sidx'];
$sord = $_GET['sord'];
if (!$sidx)
$sidx = 1;
$db = mysql_connect("$dbhost", "$dbuser", "$dbpassword") or die("Connection Error: " . mysql_error());
mysql_select_db("$database") or die("Error connecting to db.");
$result = mysql_query("SELECT COUNT(*) AS count FROM app");
$row = mysql_fetch_array($result, MYSQL_ASSOC);
$count = $row['count'];
if ($count > 0 && $limit > 0) {
$total_pages = ceil($count / $limit);
} else {
$total_pages = 0;
}
if ($page > $total_pages)
$page = $total_pages;
$start = $limit * $page - $limit;
if ($start < 0)
$start = 0;
$SQL = "SELECT id, name, status FROM app";
$result = mysql_query($SQL) or die("Couldn't execute query." . mysql_error());
header("Content-type: text/xml;charset=utf-8");
$s = "<?xml version='1.0' encoding='utf-8'?>";
$s .= "<rows>";
$s .= "<page>" . $page . "</page>";
$s .= "<total>" . $total_pages . "</total>";
$s .= "<records>" . $count . "</records>";
// be sure to put text data in CDATA
while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
$s .= "<row id='" . $row['id'] . "'>";
$s .= "<cell>" . $row['id'] . "</cell>";
$s .= "<cell>" . $row['name'] . "</cell>";
$s .= "<cell>" . $row['status'] . "</cell>";
$s .= "</row>";
}
$s .= "</rows>";
echo $s;
?>
First of all you should change the code
onSelectRow: function(id){
if(appid && appid!==lastsel2){
jQuery('#list').restoreRow(lastsel2);
jQuery('#list').editRow(id,true);
lastsel2=id;
}
}
to something like
onSelectRow: function (id) {
if (id && id !== lastsel2){
jQuery('#list').restoreRow(lastsel2);
jQuery('#list').editRow(id,true);
lastsel2 = id;
}
}
because currently you use undefined appid instead of id.
Moreover you should remove trailing comma at the end of colModel definition: change },] to }] and place semicolon after var lastsel2.
Related
Imagine that I have 1 2 3 4pages in my table, then if I click the page 1 the number 1 will be background: black Then the problem is the whole pages will be black, when I executing. Please help me out of this problem. I want to change the background color of the page if what page I click. Tyia
Here's the code:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<div class="table-responsive" id="pagination_data"></div>
<script>
$(document).ready(function(){
load_data();
function load_data(page)
{
$.ajax({
url:"pagination.php",
method:"POST",
data:{page:page},
success:function(data){
$('#pagination_data').html(data);
$(".pagination_link").css({"background":, "black"});
}
})
}
$(document).on('click', '.pagination_link', function(){
var page = $(this).attr("id");
load_data(page);
$(".pagination_link").css({"background":, "black"});
});
});
</script>
PHP code:
<?php
//pagination.php
$connect = mysqli_connect("localhost", "root", "", "psbr");
$record_per_page = 6;
$page = '';
$output = '';
if(isset($_POST["page"]))
{
$page = $_POST["page"];
}
else
{
$page = 1;
}
$start_from = ($page - 1)*$record_per_page;
$query = "SELECT * FROM accounts ORDER BY id DESC LIMIT $start_from, $record_per_page";
$result = mysqli_query($connect, $query);
$output .= "
<div class='grid-container'>
";
while($row = mysqli_fetch_array($result))
{
$output .= '
<div class="grid-content">
<img src="../accounts/table/upload/'.$row['image'].'" class="grid-image">
</div>
';
}
$output .= '</div> <br /><div align="right">';
$page_query = "SELECT * FROM accounts ORDER BY id DESC";
$page_result = mysqli_query($connect, $page_query);
$total_records = mysqli_num_rows($page_result);
$total_pages = ceil($total_records/$record_per_page);
for($i=1; $i<=$total_pages; $i++)
{
$output .= "<span class='pagination_link' id='".$i."'>".$i."</span>";
}
$output .= '</div><br /><br />';
echo $output;
?>
I am gathering live data from a mysql database using php and ajax. I want the data to be live updated every 2 seconds.
My code displays the chart and data as I want it, but does not live update the data from the database. The piece of code meant to be doing that is:
setInterval(function(){
jsonData.ajax.reload();
}, 2000);
And I think the error lies somewhere there as when I inspect the element with google chrome it tells me "Uncaught TypeError: Cannot read property 'reload' of undefined".
Here is the full JS code:
<script type="text/javascript">
// load chart lib
google.load('visualization', '1', {
packages: ['corechart']
});
// call drawChart once google charts is loaded
google.setOnLoadCallback(drawChart);
function drawChart() {
var jsonData = $.ajax({
url: "php/connection3_temp.php",
dataType:"json",
async: true
}).done(function (results) {
var data = new google.visualization.DataTable();
data.addColumn('datetime', 'Time');
data.addColumn('number', 'Ambient Temp.');
data.addColumn('number', 'Object Temp.');
data.addColumn('number', 'Humidity');
$.each(results, function (i, row) {
data.addRow([
(new Date(row.timestamp)),
parseFloat(row.amb_temp),
parseFloat(row.obj_temp),
parseFloat(row.hum)
]);
});
var options = {
title: 'Temperature and Humidity against Time',
legend: { position: 'bottom' },
series: {
0: {targetAxisIndex: 0},
1: {targetAxisIndex: 0},
2: {targetAxisIndex: 1}
},
vAxes: {0: {title: 'Temp. (°C)',
minValue: 0,
maxValue: 30
},
1: {title: 'Humidity (%)',
minValue: 20,
maxValue: 80
}
},
hAxis: {
title: 'Time (s)'
},
};
var chart = new google.visualization.LineChart($('#temp_chart').get(0));
chart.draw(data, options);
});
setInterval(function(){
jsonData.ajax.reload();
}, 2000);
}
</script>
and also the PHP:
<?php
$servername = "localhost";
$username = "root";
$password = "raspberryblue";
$dbname = "test";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$sql = "SELECT * FROM sensortag3 ORDER BY id DESC LIMIT 3000";
$result = $conn->query($sql);
// All good?
if ( !$result ) {
// Nope
$message = 'Invalid query: ' . mysqli_error() . "<br>";
$message .= 'Whole query: ' . $sql;
die( $message );
}
// Print out rows
$prefix = '';
echo "[\n";
while ( $row = mysqli_fetch_assoc( $result ) ) {
echo $prefix . " {\n";
echo ' "timestamp": "' . $row['timestamp'] . '",' . "\n";
echo ' "amb_temp": "' . $row['amb_temp'] . '",' . "\n";
echo ' "obj_temp": "' . $row['obj_temp'] . '",' . "\n";
echo ' "hum": "' . $row['hum'] . '"' . "\n";
echo " }";
$prefix = ",\n";
}
echo "\n]";
$conn->close();
?>
There's no property named reload() in your script. That's why the console is showing undefined property reload(). So add the reload method inside ajax() for refreshing the data.
I can generate now highcharts calling data with mysql. Now I plot splines, but I need to combine 2 splines (for TMax and TMin) and 1 column (for Rain). Anybody knows what I should change in the next two files, I guess in index.php ? I can do plot this combination using csv files but now with mysql. Any idea?
Code of mysql-highcharts.php
<?php
session_start();
$con = mysqli_connect("xxxx","xxx","xxx","xxx");
if (!$con) {
die('Could not connect: ' . mysqli_error());
}
mysqli_set_charset($con, 'utf8');
function split($date){
$day=substr($date,0,2);
$month=substr($date,3,2);
$year=substr($date,6,4);
return $year . "/" . $month . "/" . $day;
}
$sth = mysqli_query($con,"SELECT City,TMax FROM Meteo2 where City= '" . $_SESSION["City"] ."' AND Data BETWEEN '" . split($_SESSION["date8"]) ."' AND '" . split($_SESSION["date9"]) ."'order by Data");
$rows = array();
$rows['name'] = 'TMAX';
while($r = mysqli_fetch_array($sth)) {
$rows['data'][] = $r['TMax'];
}
$sth = mysqli_query($con,"SELECT City,TMin FROM Meteo2 where City= '" . $_SESSION["City"] ."' AND Data BETWEEN '" . split($_SESSION["date8"]) ."' AND '" . split($_SESSION["date9"]) ."'order by Data");
$rows1 = array();
$rows1['name'] = 'TMIN';
while($rr = mysqli_fetch_assoc($sth)) {
$rows1['data'][] = $rr['TMin'];
}
$sth = mysqli_query($con,"SELECT City,Rain FROM Meteo2 where City= '" . $_SESSION["City"] ."' AND Data BETWEEN '" . split($_SESSION["date8"]) ."' AND '" . split($_SESSION["date9"]) ."'order by Data");
$rows2 = array();
$rows2['name'] = 'RAINS';
while($rr = mysqli_fetch_assoc($sth)) {
$rows2['data'][] = $rr['Rain'];
}
$result = array();
array_push($result,$rows);
array_push($result,$rows1);
array_push($result,$rows2);
print json_encode($result, JSON_NUMERIC_CHECK);
mysqli_close($con);
?>
Code of index.php (highcharts code)
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Highcharts Example</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
<?php
$city = $_POST["City"];
session_start();
$_SESSION['City'] = $_POST['City'];
$_SESSION['date8'] = $_POST['date8'];
$_SESSION['date9'] = $_POST['date9'];
?>
$(function () {
var chart;
$(document).ready(function() {
$.getJSON("mysql-highcharts.php", function(json) {
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'spline',
marginRight: 130,
marginBottom: 25
},
title: {
text: 'TMax-TMin-Rain <?php echo $city ?>',
x: -20 //center
},
subtitle: {
text: '',
x: -20
},
xAxis: {
categories: []
},
yAxis: {
title: {
text: 'Temperature (ºC)'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
formatter: function() {
return '<b>'+ this.series.name +'</b><br/>'+
this.x +': '+ this.y;
}
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'top',
x: -10,
y: 100,
borderWidth: 0
},
series: json
});
});
});
});
</script>
</head>
<body>
<script src="http://code.highcharts.com/highcharts.js"></script>
<script src="http://code.highcharts.com/modules/exporting.js"></script>
<div id="container" style="min-width: 400px; height: 400px; margin: 0 auto"></div>
</body>
</html>
Simply set for that specific series type, like this:
$rows1 = array();
$rows1['name'] = 'TMIN';
$rows1['type'] = 'column';
while($rr = mysqli_fetch_assoc($sth)) {
$rows1['data'][] = $rr['TMin'];
}
I have two sets of code Loadmore Button And Jqueury Drag N Drop but they do not work as one.
How can I merge them together to function as one code?
Here is the Problem:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"
type="text/javascript">
This Line is needed by the Loadmore Button and kills the UI function of the Drag and Drop elements.
Drag N Drop:
<title>jQuery Dynamic Drag'n Drop</title>
<script type="text/javascript" src="jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="jquery-ui-1.7.1.custom.min.js">
</script><script type="text/javascript">
$(document).ready(function(){
$(function() {
$("#contentLeft ul").sortable({ opacity: 0.6, cursor: 'move', update: function() {
var order = $(this).sortable("serialize") + '&action=updateRecordsListings';
$.post("updateDB.php", order, function(theResponse){
$("#contentRight").html(theResponse);
});
}
});
});
});
</script>
DND updateDB.php
<?php
require("db.php");
$action = mysql_real_escape_string($_POST['action']);
$updateRecordsArray = $_POST['recordsArray'];
if ($action == "updateRecordsListings"){
$listingCounter = 1;
foreach ($updateRecordsArray as $recordIDValue) {
$query = "UPDATE records SET recordListingID = " . $listingCounter . " WHERE recordID = " . $recordIDValue;
mysql_query($query) or die('Error, insert query failed');
$listingCounter = $listingCounter + 1;
}
echo '<pre>';
print_r($updateRecordsArray);
echo '</pre>';
echo 'If you refresh the page, you will see that records will stay just as you modified.';
}?>
DND main PHP:
<ul>
<?php
$query = "SELECT * FROM records ORDER BY recordListingID ASC";
$result = mysql_query($query);
while($row = mysql_fetch_array($result, MYSQL_ASSOC))
{
?>
<li id="recordsArray_<?php echo $row['recordID']; ?>"><?php echo $row['recordID'] . ". " . $row['recordText']; ?></li>
<?php } ?>
</ul>
Loadmore:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"
type="text/javascript"></script>
<script>
$(function() {
var page = 1;
$("#LoadMore").click(function(){
$.ajax({
type:"GET",
url:"page4.php",
data:{page:page},
success: function(response) {
$("#data_grid").append(response);
page++;
}
});
});
});</script>
Loadmore page4.php
<?php
//set argument as your mysql server
$connect = mysql_connect("mysql_server","mysql_user","mysql_password");
mysql_select_db("database_name",$connect);
$page = isset($_GET["page"]) ? $_GET["page"] : 1;
$limit = 25;
$offset = ($page - 1) * $limit;
$sql = "SELECT * FROM table2 limit $offset, $limit";
$result = mysql_query($sql);
$numRows = mysql_num_rows($result);
if($numRows>0) {
while($row = mysql_fetch_array($result)) {
//get field data and set to the following row
echo "<tr><td>field 1</td><td>field 2</td><td>field 3</td></tr>";
//edit row as you table data
}
} else {
echo "<tr><td colspan='3'> No more data </td></tr>";
}
exit;
?>
What am I missing? Can I fix this? Am I going to have to scrap the Jquery Drag N Drop? Is there an alternative that I should be using?
Background: A user will rate listed items in the order they deem fit. The total possible Items exceed 300,000 but the user will probably only utilize the first few hundred and the rest is used as a searchable database to add an odd item into the list. I can get the 2 codes in question to work separately but when I attempt the combination they create conflict.
Thank you for your time in assisting this project.
Look here
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"
type="text/javascript">
and
<script type="text/javascript" src="jquery-1.3.2.min.js"></script>
are same (jQuery file)
So use only one
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"
type="text/javascript">
Is there an equivalent to the following:
header("Content-type: text/xml");
I'm using Google Maps with Wordpress and I get the "headers already sent" error. I've gone through all the files and taken out all the whitespace but the error still appears so just wondering if there was another way of doing the code above.
This is the error:
Warning: Cannot modify header information - headers already sent by (output started at /home/medicom/public_html/mapping/wp-content/themes/default/header.php:11) in /home/medicom/public_html/mapping/wp-content/themes/default/new-version1.php on line 45
And this is my page - http://www.mediwales.com/mapping/test/
<?php
/**
* #package WordPress
* #subpackage Default_Theme
* Template Name: Latest Version
*/
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head profile="http://gmpg.org/xfn/11">
<meta http-equiv="Content-Type" content="<?php bloginfo('html_type');?>; charset=<?php bloginfo('charset');?>" />
<title><?php wp_title('«', true, 'right');?></title>
<link rel="stylesheet" href="<?php bloginfo('stylesheet_url');?>" type="text/css" media="screen" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
<script src="<?php bloginfo('template_directory'); ?>/markerclusterer.js" type="text/javascript"></script>
<link rel="pingback" href="<?php bloginfo('pingback_url'); ?>" />
<script src="http://maps.google.com/maps?file=api&v=2&key=ABQIAAAAdnbfsmnsdaFBmEZfsJEmiWC7p0LLmMBSsffI9l26I_viUYjW7vRG7TlO-sRQKR0B_YAsP2VnDdVgsr4Aegvksdw" type="text/javascript"></script>
<?php if ( is_singular() ) wp_enqueue_script( 'comment-reply' ); ?>
<?php wp_head(); ?>
</head>
<body <?php body_class(); ?> onload="load()" onunload="GUnload()">
<?php if (have_posts()) : ?>
<?php while (have_posts()) : the_post(); ?>
<div id="body">
<?php
require("database.php");
function parseToXML($htmlStr)
{
$xmlStr=str_replace('<','<',$htmlStr);
$xmlStr=str_replace('>','>',$xmlStr);
$xmlStr=str_replace('"','"',$xmlStr);
$xmlStr=str_replace("'",''',$xmlStr);
$xmlStr=str_replace("&",'&',$xmlStr);
return $xmlStr;
}
// Opens a connection to a MySQL server
$connection=mysql_connect (localhost, $username, $password);
if (!$connection) {
die('Not connected : ' . mysql_error());
}
// Set the active MySQL database
$db_selected = mysql_select_db($database, $connection);
if (!$db_selected) {
die ('Can\'t use db : ' . mysql_error());
}
// Select all the rows in the markers table
$query = "SELECT * FROM markers WHERE 1";
$result = mysql_query($query);
if (!$result) {
die('Invalid query: ' . mysql_error());
}
header("Content-type: text/xml");
// Start XML file, echo parent node
echo '<markers>';
// Iterate through the rows, printing XML nodes for each
while ($row = #mysql_fetch_assoc($result)){
// ADD TO XML DOCUMENT NODE
echo '<marker ';
echo 'name="' . parseToXML($row['name']) . '" ';
echo 'address="' . parseToXML($row['address']) . '" ';
echo 'lat="' . $row['lat'] . '" ';
echo 'lng="' . $row['lng'] . '" ';
echo 'type="' . $row['type'] . '" ';
echo '/>';
}
// End XML file
echo '</markers>';
?>
<script type="text/javascript">
//<![CDATA[
var iconBlue = new GIcon();
iconBlue.image = 'http://labs.google.com/ridefinder/images/mm_20_blue.png';
iconBlue.shadow = 'http://labs.google.com/ridefinder/images/mm_20_shadow.png';
iconBlue.iconSize = new GSize(12, 20);
iconBlue.shadowSize = new GSize(22, 20);
iconBlue.iconAnchor = new GPoint(6, 20);
iconBlue.infoWindowAnchor = new GPoint(5, 1);
var iconRed = new GIcon();
iconRed.image = 'http://labs.google.com/ridefinder/images/mm_20_red.png';
iconRed.shadow = 'http://labs.google.com/ridefinder/images/mm_20_shadow.png';
iconRed.iconSize = new GSize(12, 20);
iconRed.shadowSize = new GSize(22, 20);
iconRed.iconAnchor = new GPoint(6, 20);
iconRed.infoWindowAnchor = new GPoint(5, 1);
var customIcons = [];
customIcons["restaurant"] = iconBlue;
customIcons["bar"] = iconRed;
function load() {
if (GBrowserIsCompatible()) {
var map = new GMap2(document.getElementById("map"));
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(47.614495, -122.341861), 13);
GDownloadUrl("phpsqlajax_genxml.php", function(data) {
var xml = GXml.parse(data);
var markers = xml.documentElement.getElementsByTagName("marker");
for (var i = 0; i < markers.length; i++) {
var name = markers[i].getAttribute("name");
var address = markers[i].getAttribute("address");
var type = markers[i].getAttribute("type");
var point = new GLatLng(parseFloat(markers[i].getAttribute("lat")),
parseFloat(markers[i].getAttribute("lng")));
var marker = createMarker(point, name, address, type);
map.addOverlay(marker);
}
});
}
}
function createMarker(point, name, address, type) {
var marker = new GMarker(point, customIcons[type]);
var html = "<b>" + name + "</b> <br/>" + address;
GEvent.addListener(marker, 'click', function() {
marker.openInfoWindowHtml(html);
});
return marker;
}
//]]>
</script>
<div id="map" style="width: 500px; height: 300px"></div>
</div>
<?php endwhile; ?>
<?php endif; ?>
</div>
<?php wp_footer(); ?>
</body></html>
Now I see what you are doing. You cannot send output to the screen then change the headers. If you are trying to create an XML file of map marker and download them to display, they should be in separate files.
Take this
<?php
require("database.php");
function parseToXML($htmlStr)
{
$xmlStr=str_replace('<','<',$htmlStr);
$xmlStr=str_replace('>','>',$xmlStr);
$xmlStr=str_replace('"','"',$xmlStr);
$xmlStr=str_replace("'",''',$xmlStr);
$xmlStr=str_replace("&",'&',$xmlStr);
return $xmlStr;
}
// Opens a connection to a MySQL server
$connection=mysql_connect (localhost, $username, $password);
if (!$connection) {
die('Not connected : ' . mysql_error());
}
// Set the active MySQL database
$db_selected = mysql_select_db($database, $connection);
if (!$db_selected) {
die ('Can\'t use db : ' . mysql_error());
}
// Select all the rows in the markers table
$query = "SELECT * FROM markers WHERE 1";
$result = mysql_query($query);
if (!$result) {
die('Invalid query: ' . mysql_error());
}
header("Content-type: text/xml");
// Start XML file, echo parent node
echo '<markers>';
// Iterate through the rows, printing XML nodes for each
while ($row = #mysql_fetch_assoc($result)){
// ADD TO XML DOCUMENT NODE
echo '<marker ';
echo 'name="' . parseToXML($row['name']) . '" ';
echo 'address="' . parseToXML($row['address']) . '" ';
echo 'lat="' . $row['lat'] . '" ';
echo 'lng="' . $row['lng'] . '" ';
echo 'type="' . $row['type'] . '" ';
echo '/>';
}
// End XML file
echo '</markers>';
?>
and place it in phpsqlajax_genxml.php so your javascript can download the XML file. You are trying to do too many things in the same file.
No. You can't send headers after they were sent. Try to use hooks in wordpress